From 264b8b4e973f8741adf530a388be72af4bfee953 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 8 Jan 2014 16:40:39 +0200 Subject: [PATCH 001/139] Bluetooth: Fix outgoing authentication requirement check The check for HIGH security level dates back to pre-mgmt times when a raw L2CAP socket with HIGH security level was used to trigger dedicated bonding. For legacy pairing checking for the security level was the only way to catch the need to authenticate in all scenarios. With mgmt however, the pair_device command does not use HIGH security but MEDIUM security. Therefore, the existing code would never trigger authentication for a non-SSP connection without an MITM requirement (e.g. if user space provided a NoInputNoOutput IO capability). In such a scenario the mgmt_pair_device command would return success without actually triggering any kind of pairing. This patch updates the authentication requirement check to also consider MEDIUM security level, and thereby ensures that mgmt_pair_device will always trigger authentication. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5f812455a450..cfcce448957b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1185,9 +1185,12 @@ 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 or if MITM protection is requested */ + * devices with sec_level MEDIUM or HIGH or if MITM protection + * is requested. + */ if (!hci_conn_ssp_enabled(conn) && !(conn->auth_type & 0x01) && - conn->pending_sec_level != BT_SECURITY_HIGH) + conn->pending_sec_level != BT_SECURITY_HIGH && + conn->pending_sec_level != BT_SECURITY_MEDIUM) return 0; return 1; From d5991585d0bc49dca4ff36d18447bb27ad1ccd73 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:16 -0800 Subject: [PATCH 002/139] Bluetooth: Add LMP feature definitions for Secure Connections support The support for Secure Connections introduces two new controller features and one new host feature. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 4 ++++ include/net/bluetooth/hci_core.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 66c1cd87bfe7..cd40219d32aa 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -282,10 +282,14 @@ enum { #define LMP_SYNC_TRAIN 0x04 #define LMP_SYNC_SCAN 0x08 +#define LMP_SC 0x01 +#define LMP_PING 0x02 + /* Host features */ #define LMP_HOST_SSP 0x01 #define LMP_HOST_LE 0x02 #define LMP_HOST_LE_BREDR 0x04 +#define LMP_HOST_SC 0x08 /* Connection modes */ #define HCI_CM_ACTIVE 0x0000 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f2f0cf5865c4..bb984d0626b7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -803,9 +803,12 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_csb_slave_capable(dev) ((dev)->features[2][0] & LMP_CSB_SLAVE) #define lmp_sync_train_capable(dev) ((dev)->features[2][0] & LMP_SYNC_TRAIN) #define lmp_sync_scan_capable(dev) ((dev)->features[2][0] & LMP_SYNC_SCAN) +#define lmp_sc_capable(dev) ((dev)->features[2][1] & LMP_SC) +#define lmp_ping_capable(dev) ((dev)->features[2][1] & LMP_PING) /* ----- Host capabilities ----- */ #define lmp_host_ssp_capable(dev) ((dev)->features[1][0] & LMP_HOST_SSP) +#define lmp_host_sc_capable(dev) ((dev)->features[1][0] & LMP_HOST_SC) #define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE)) #define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR)) From eb4b95c627258f0b5cee6c26c8e478dda6941e2b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:17 -0800 Subject: [PATCH 003/139] Bluetooth: Add HCI command definition for Secure Connections enabling The Secure Connections feature is optional and host stacks have to manually enable it. This add the HCI command definiton for reading and writing this setting. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index cd40219d32aa..2a35d273de2c 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -937,6 +937,17 @@ struct hci_rp_write_sync_train_params { __le16 sync_train_int; } __packed; +#define HCI_OP_READ_SC_SUPPORT 0x0c79 +struct hci_rp_read_sc_support { + __u8 status; + __u8 support; +} __packed; + +#define HCI_OP_WRITE_SC_SUPPORT 0x0c7a +struct hci_cp_write_sc_support { + __u8 support; +} __packed; + #define HCI_OP_READ_LOCAL_VERSION 0x1001 struct hci_rp_read_local_version { __u8 status; From e2f9913157133c3ffab4b835940927879d541b57 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:18 -0800 Subject: [PATCH 004/139] Bluetooth: Add HCI command definition for extended OOB data The Secure Connections feature introduces the support for P-256 strength pairings (compared to P-192 with Secure Simple Pairing). This however means that for out-of-band pairing the hash and randomizer needs to be differentiated. Two new commands are introduced to handle the possible combinations of P-192 and P-256. This add the HCI command definition for both. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 2a35d273de2c..e4e94bfc5232 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -664,6 +664,15 @@ struct hci_rp_set_csb { #define HCI_OP_START_SYNC_TRAIN 0x0443 +#define HCI_OP_REMOTE_OOB_EXT_DATA_REPLY 0x0445 +struct hci_cp_remote_oob_ext_data_reply { + bdaddr_t bdaddr; + __u8 hash192[16]; + __u8 randomizer192[16]; + __u8 hash256[16]; + __u8 randomizer256[16]; +} __packed; + #define HCI_OP_SNIFF_MODE 0x0803 struct hci_cp_sniff_mode { __le16 handle; @@ -948,6 +957,15 @@ struct hci_cp_write_sc_support { __u8 support; } __packed; +#define HCI_OP_READ_LOCAL_OOB_EXT_DATA 0x0c7d +struct hci_rp_read_local_oob_ext_data { + __u8 status; + __u8 hash192[16]; + __u8 randomizer192[16]; + __u8 hash256[16]; + __u8 randomizer256[16]; +} __packed; + #define HCI_OP_READ_LOCAL_VERSION 0x1001 struct hci_rp_read_local_version { __u8 status; From 11015c7903c74350402f8753339c48bee0186e90 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:19 -0800 Subject: [PATCH 005/139] Bluetooth: Add definitions for new link key types With the introduction of Secure Connections, the list of link key types got extended by P-256 versions of authenticated and unauthenticated link keys. To avoid any confusion the previous authenticated and unauthenticated link key types got ammended with a P912 postfix. And the two new keys have a P256 postfix now. Existing code using the previous definitions has been adjusted. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 6 ++++-- net/bluetooth/hci_conn.c | 4 ++-- net/bluetooth/hci_event.c | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index e4e94bfc5232..8d888bc432c6 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -331,9 +331,11 @@ enum { #define HCI_LK_LOCAL_UNIT 0x01 #define HCI_LK_REMOTE_UNIT 0x02 #define HCI_LK_DEBUG_COMBINATION 0x03 -#define HCI_LK_UNAUTH_COMBINATION 0x04 -#define HCI_LK_AUTH_COMBINATION 0x05 +#define HCI_LK_UNAUTH_COMBINATION_P192 0x04 +#define HCI_LK_AUTH_COMBINATION_P192 0x05 #define HCI_LK_CHANGED_COMBINATION 0x06 +#define HCI_LK_UNAUTH_COMBINATION_P256 0x07 +#define HCI_LK_AUTH_COMBINATION_P256 0x08 /* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */ #define HCI_SMP_STK 0x80 #define HCI_SMP_STK_SLAVE 0x81 diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index ba5366c320da..251f22e32fbf 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -802,12 +802,12 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* An authenticated combination key has sufficient security for any security level. */ - if (conn->key_type == HCI_LK_AUTH_COMBINATION) + if (conn->key_type == HCI_LK_AUTH_COMBINATION_P192) goto encrypt; /* An unauthenticated combination key has sufficient security for security level 1 and 2. */ - if (conn->key_type == HCI_LK_UNAUTH_COMBINATION && + if (conn->key_type == HCI_LK_UNAUTH_COMBINATION_P192 && (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW)) goto encrypt; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index cfcce448957b..defa1252b534 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2633,7 +2633,7 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (conn) { - if (key->type == HCI_LK_UNAUTH_COMBINATION && + if (key->type == HCI_LK_UNAUTH_COMBINATION_P192 && conn->auth_type != 0xff && (conn->auth_type & 0x01)) { BT_DBG("%s ignoring unauthenticated key", hdev->name); goto not_found; From 66138ce8e556a8ddd13baf035fb3a8d0d6dd4bb5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:20 -0800 Subject: [PATCH 006/139] Bluetooth: Add support for handling P-256 derived link keys Before being able to enable Secure Connections support, the core needs to know on how to handle P-256 derived link keys. The difference between authenticated and unauthenticated P-256 derived link keys is the same as its P-192 counter parts. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 6 ++++-- net/bluetooth/hci_event.c | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 251f22e32fbf..cf96b3438a91 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -802,12 +802,14 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* An authenticated combination key has sufficient security for any security level. */ - if (conn->key_type == HCI_LK_AUTH_COMBINATION_P192) + if (conn->key_type == HCI_LK_AUTH_COMBINATION_P192 || + conn->key_type == HCI_LK_AUTH_COMBINATION_P256) goto encrypt; /* An unauthenticated combination key has sufficient security for security level 1 and 2. */ - if (conn->key_type == HCI_LK_UNAUTH_COMBINATION_P192 && + if ((conn->key_type == HCI_LK_UNAUTH_COMBINATION_P192 || + conn->key_type == HCI_LK_UNAUTH_COMBINATION_P256) && (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW)) goto encrypt; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index defa1252b534..b3c5396e0c1b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2633,7 +2633,8 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (conn) { - if (key->type == HCI_LK_UNAUTH_COMBINATION_P192 && + if ((key->type == HCI_LK_UNAUTH_COMBINATION_P192 || + key->type == HCI_LK_UNAUTH_COMBINATION_P256) && conn->auth_type != 0xff && (conn->auth_type & 0x01)) { BT_DBG("%s ignoring unauthenticated key", hdev->name); goto not_found; From 40c59fcbcdc25d5b1aafef23b94167c2376b0dce Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:21 -0800 Subject: [PATCH 007/139] Bluetooth: Enable Authenticated Payload Timeout Expired event With Secure Connections capable controllers, the authenticated payload timeout can trigger. Enable the event so the controller informs the host when this happens. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 5e8663c194c1..52e398f37129 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1288,6 +1288,10 @@ static void hci_set_event_mask_page_2(struct hci_request *req) events[2] |= 0x08; /* Truncated Page Complete */ } + /* Enable Authenticated Payload Timeout Expired event if supported */ + if (lmp_ping_capable(hdev)) + events[2] |= 0x80; + hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, sizeof(events), events); } From e98d2ce293a941d41b5c8435975ff25a1b858bf9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:22 -0800 Subject: [PATCH 008/139] Bluetooth: Add flags and setting for Secure Connections support The MGMT_SETTING_SECURE_CONN setting is used to track the support and status for Secure Connections from the management interface. For HCI based tracking HCI_SC_ENABLED flag is used. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/mgmt.h | 1 + net/bluetooth/mgmt.c | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 8d888bc432c6..0253276e88e4 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -122,6 +122,7 @@ enum { HCI_LE_SCAN, HCI_SSP_ENABLED, + HCI_SC_ENABLED, HCI_HS_ENABLED, HCI_LE_ENABLED, HCI_ADVERTISING, diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 518c5c84e39a..4ec17dec62e0 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -94,6 +94,7 @@ struct mgmt_rp_read_index_list { #define MGMT_SETTING_HS 0x00000100 #define MGMT_SETTING_LE 0x00000200 #define MGMT_SETTING_ADVERTISING 0x00000400 +#define MGMT_SETTING_SECURE_CONN 0x00000800 #define MGMT_OP_READ_INFO 0x0004 #define MGMT_READ_INFO_SIZE 0 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a03ca3ca91bf..b00fa0253cba 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -79,6 +79,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_SET_BREDR, MGMT_OP_SET_STATIC_ADDRESS, MGMT_OP_SET_SCAN_PARAMS, + MGMT_OP_SET_SECURE_CONN, }; static const u16 mgmt_events[] = { @@ -376,6 +377,9 @@ static u32 get_supported_settings(struct hci_dev *hdev) settings |= MGMT_SETTING_SSP; settings |= MGMT_SETTING_HS; } + + if (lmp_sc_capable(hdev)) + settings |= MGMT_SETTING_SECURE_CONN; } if (lmp_le_capable(hdev)) { @@ -423,6 +427,9 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) settings |= MGMT_SETTING_ADVERTISING; + if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) + settings |= MGMT_SETTING_SECURE_CONN; + return settings; } From eac83dc632a7afba72f7084266bc310219486253 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:23 -0800 Subject: [PATCH 009/139] Bluetooth: Add management command for enabling Secure Connections The support for Secure Connections need to be explicitly enabled by userspace. This is required since only userspace that can handle the new link key types should enable support for Secure Connections. This command handling is similar to how Secure Simple Pairing enabling is done. It also tracks the case when Secure Connections support is enabled via raw HCI commands. This makes sure that the host features page is updated as well. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/mgmt.h | 2 + net/bluetooth/hci_event.c | 32 ++++++++++ net/bluetooth/mgmt.c | 106 +++++++++++++++++++++++++++++++ 4 files changed, 141 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bb984d0626b7..1eb55ec40ac0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1125,6 +1125,7 @@ void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status); void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); +void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, u8 status); void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 4ec17dec62e0..8a2c78175997 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -370,6 +370,8 @@ struct mgmt_cp_set_scan_params { } __packed; #define MGMT_SET_SCAN_PARAMS_SIZE 4 +#define MGMT_OP_SET_SECURE_CONN 0x002D + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b3c5396e0c1b..b6f0c241e236 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -461,6 +461,34 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) } } +static void hci_cc_write_sc_support(struct hci_dev *hdev, struct sk_buff *skb) +{ + u8 status = *((u8 *) skb->data); + struct hci_cp_write_sc_support *sent; + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SC_SUPPORT); + if (!sent) + return; + + if (!status) { + if (sent->support) + hdev->features[1][0] |= LMP_HOST_SC; + else + hdev->features[1][0] &= ~LMP_HOST_SC; + } + + if (test_bit(HCI_MGMT, &hdev->dev_flags)) + mgmt_sc_enable_complete(hdev, sent->support, status); + else if (!status) { + if (sent->support) + set_bit(HCI_SC_ENABLED, &hdev->dev_flags); + else + clear_bit(HCI_SC_ENABLED, &hdev->dev_flags); + } +} + static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_read_local_version *rp = (void *) skb->data; @@ -2147,6 +2175,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_write_ssp_mode(hdev, skb); break; + case HCI_OP_WRITE_SC_SUPPORT: + hci_cc_write_sc_support(hdev, skb); + break; + case HCI_OP_READ_LOCAL_VERSION: hci_cc_read_local_version(hdev, skb); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b00fa0253cba..68a3c998d19c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4006,6 +4006,79 @@ unlock: return err; } +static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_mode *cp = data; + struct pending_cmd *cmd; + u8 status; + int err; + + BT_DBG("request for %s", hdev->name); + + status = mgmt_bredr_support(hdev); + if (status) + return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, + status); + + if (!lmp_sc_capable(hdev)) + return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, + MGMT_STATUS_NOT_SUPPORTED); + + if (cp->val != 0x00 && cp->val != 0x01) + return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + if (!hdev_is_powered(hdev)) { + bool changed; + + if (cp->val) + changed = !test_and_set_bit(HCI_SC_ENABLED, + &hdev->dev_flags); + else + changed = test_and_clear_bit(HCI_SC_ENABLED, + &hdev->dev_flags); + + err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev); + if (err < 0) + goto failed; + + if (changed) + err = new_settings(hdev, sk); + + goto failed; + } + + if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) { + err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, + MGMT_STATUS_BUSY); + goto failed; + } + + if (!!cp->val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { + err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev); + goto failed; + } + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &cp->val); + if (err < 0) { + mgmt_pending_remove(cmd); + goto failed; + } + +failed: + hci_dev_unlock(hdev); + return err; +} + static bool ltk_is_valid(struct mgmt_ltk_info *key) { if (key->authenticated != 0x00 && key->authenticated != 0x01) @@ -4134,6 +4207,7 @@ static const struct mgmt_handler { { set_bredr, false, MGMT_SETTING_SIZE }, { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE }, { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE }, + { set_secure_conn, false, MGMT_SETTING_SIZE }, }; @@ -4917,6 +4991,38 @@ void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) hci_req_run(&req, NULL); } +void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) +{ + struct cmd_lookup match = { NULL, hdev }; + bool changed = false; + + if (status) { + u8 mgmt_err = mgmt_status(status); + + if (enable && test_and_clear_bit(HCI_SC_ENABLED, + &hdev->dev_flags)) + new_settings(hdev, NULL); + + mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev, + cmd_status_rsp, &mgmt_err); + return; + } + + if (enable) + changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags); + else + changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags); + + mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev, + settings_rsp, &match); + + if (changed) + new_settings(hdev, match.sk); + + if (match.sk) + sock_put(match.sk); +} + static void sk_lookup(struct pending_cmd *cmd, void *data) { struct cmd_lookup *match = data; From a6d0d690e1bd56ce031f38a3144cb9f6ea23456f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:24 -0800 Subject: [PATCH 010/139] Bluetooth: Enable Secure Connection during power on if configured If support for Secure Connection has been configured, then make sure to send the appropiate HCI command to enable it when powering on the controller. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 52e398f37129..b3b619a448b5 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1363,6 +1363,14 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) /* Check for Synchronization Train support */ if (lmp_sync_train_capable(hdev)) hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); + + /* Enable Secure Connections if supported and configured */ + if (lmp_sc_capable(hdev) && + test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { + u8 support = 0x01; + hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT, + sizeof(support), &support); + } } static int __hci_init(struct hci_dev *hdev) From 8e99113277fb9f7b8b28fbcc866a359d2fa1ba41 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:25 -0800 Subject: [PATCH 011/139] Bluetooth: Limit acceptable link key types to only supported ones The link keys that are loaded by userspace during controller setup should be limited to actual valid and supported types. With the support for Secure Connections, it is limited to types 0x00 - 0x08 at the moment. Reject any other link key types. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 68a3c998d19c..9b162038acb7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2241,7 +2241,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, for (i = 0; i < key_count; i++) { struct mgmt_link_key_info *key = &cp->keys[i]; - if (key->addr.type != BDADDR_BREDR) + if (key->addr.type != BDADDR_BREDR || key->type > 0x08) return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, MGMT_STATUS_INVALID_PARAMS); } From 4d2d27962642e23f88745b0430d47c3ff75afdd3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:26 -0800 Subject: [PATCH 012/139] Bluetooth: Add support for local OOB data with Secure Connections For Secure Connections support and the usage of out-of-band pairing, it is needed to read the P-256 hash and randomizer or P-192 hash and randomizer. This change will read P-192 data when Secure Connections is disabled and P-192 and P-256 data when it is enabled. The difference is between using HCI Read Local OOB Data and using the new HCI Read Local OOB Extended Data command. The first one has been introduced with Bluetooth 2.1 and returns only the P-192 data. < HCI Command: Read Local OOB Data (0x03|0x0057) plen 0 > HCI Event: Command Complete (0x0e) plen 36 Read Local OOB Data (0x03|0x0057) ncmd 1 Status: Success (0x00) Hash C from P-192: 975a59baa1c4eee391477cb410b23e6d Randomizer R with P-192: 9ee63b7dec411d3b467c5ae446df7f7d The second command has been introduced with Bluetooth 4.1 and will return P-192 and P-256 data. < HCI Command: Read Local OOB Extended Data (0x03|0x007d) plen 0 > HCI Event: Command Complete (0x0e) plen 68 Read Local OOB Extended Data (0x03|0x007d) ncmd 1 Status: Success (0x00) Hash C from P-192: 6489731804b156fa6355efb8124a1389 Randomizer R with P-192: 4781d5352fb215b2958222b3937b6026 Hash C from P-256: 69ef8a928b9d07fc149e630e74ecb991 Randomizer R with P-256: 4781d5352fb215b2958222b3937b6026 The change for the management interface is transparent and no change is required for existing userspace. The Secure Connections feature needs to be manually enabled. When it is disabled, then userspace only gets the P-192 returned and with Secure Connections enabled, userspace gets P-192 and P-256 in an extended structure. It is also acceptable to just ignore the P-256 data since it is not required to support them. The pairing with out-of-band credentials will still succeed. However then of course no Secure Connection will b established. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 5 ++-- include/net/bluetooth/mgmt.h | 6 +++++ net/bluetooth/hci_event.c | 28 ++++++++++++++++++---- net/bluetooth/mgmt.c | 41 +++++++++++++++++++++++++------- 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 1eb55ec40ac0..bd15eaa4c06e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1129,8 +1129,9 @@ void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, u8 status); void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); -void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, - u8 *randomizer, u8 status); +void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192, + u8 *randomizer192, u8 *hash256, + u8 *randomizer256, u8 status); void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8 ssp, u8 *eir, u16 eir_len); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 8a2c78175997..036ddc7dc7ed 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -295,6 +295,12 @@ struct mgmt_rp_read_local_oob_data { __u8 hash[16]; __u8 randomizer[16]; } __packed; +struct mgmt_rp_read_local_oob_ext_data { + __u8 hash192[16]; + __u8 randomizer192[16]; + __u8 hash256[16]; + __u8 randomizer256[16]; +} __packed; #define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0021 struct mgmt_cp_add_remote_oob_data { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b6f0c241e236..d5374d36e9fe 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -932,16 +932,30 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev, hci_dev_unlock(hdev); } -static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, - struct sk_buff *skb) +static void hci_cc_read_local_oob_data(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_rp_read_local_oob_data *rp = (void *) skb->data; BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); hci_dev_lock(hdev); - mgmt_read_local_oob_data_reply_complete(hdev, rp->hash, - rp->randomizer, rp->status); + mgmt_read_local_oob_data_complete(hdev, rp->hash, rp->randomizer, + NULL, NULL, rp->status); + hci_dev_unlock(hdev); +} + +static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data; + + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); + + hci_dev_lock(hdev); + mgmt_read_local_oob_data_complete(hdev, rp->hash192, rp->randomizer192, + rp->hash256, rp->randomizer256, + rp->status); hci_dev_unlock(hdev); } @@ -2248,7 +2262,11 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) break; case HCI_OP_READ_LOCAL_OOB_DATA: - hci_cc_read_local_oob_data_reply(hdev, skb); + hci_cc_read_local_oob_data(hdev, skb); + break; + + case HCI_OP_READ_LOCAL_OOB_EXT_DATA: + hci_cc_read_local_oob_ext_data(hdev, skb); break; case HCI_OP_LE_READ_BUFFER_SIZE: diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9b162038acb7..a7d4ae679ab7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3078,7 +3078,12 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, goto unlock; } - err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); + if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) + err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA, + 0, NULL); + else + err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); + if (err < 0) mgmt_pending_remove(cmd); @@ -5077,8 +5082,9 @@ void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) cmd ? cmd->sk : NULL); } -void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, - u8 *randomizer, u8 status) +void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192, + u8 *randomizer192, u8 *hash256, + u8 *randomizer256, u8 status) { struct pending_cmd *cmd; @@ -5092,13 +5098,32 @@ void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, mgmt_status(status)); } else { - struct mgmt_rp_read_local_oob_data rp; + if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) && + hash256 && randomizer256) { + struct mgmt_rp_read_local_oob_ext_data rp; - memcpy(rp.hash, hash, sizeof(rp.hash)); - memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer)); + memcpy(rp.hash192, hash192, sizeof(rp.hash192)); + memcpy(rp.randomizer192, randomizer192, + sizeof(rp.randomizer192)); - cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, - 0, &rp, sizeof(rp)); + memcpy(rp.hash256, hash256, sizeof(rp.hash256)); + memcpy(rp.randomizer256, randomizer256, + sizeof(rp.randomizer256)); + + cmd_complete(cmd->sk, hdev->id, + MGMT_OP_READ_LOCAL_OOB_DATA, 0, + &rp, sizeof(rp)); + } else { + struct mgmt_rp_read_local_oob_data rp; + + memcpy(rp.hash, hash192, sizeof(rp.hash)); + memcpy(rp.randomizer, randomizer192, + sizeof(rp.randomizer)); + + cmd_complete(cmd->sk, hdev->id, + MGMT_OP_READ_LOCAL_OOB_DATA, 0, + &rp, sizeof(rp)); + } } mgmt_pending_remove(cmd); From 5afeac149ebc94485b750eb841d0f971ea9772cd Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:27 -0800 Subject: [PATCH 013/139] Bluetooth: Add debugfs quirk for forcing Secure Connections support The Bluetooth 4.1 specification with Secure Connections support has just been released and controllers with this feature are still in an early stage. A handful of controllers have already support for it, but they do not always identify this feature correctly. This debugfs entry allows to tell the kernel that the controller can be treated as it would fully support Secure Connections. Using debugfs to force Secure Connections support of course does not make this feature magically appear in all controllers. This is a debug functionality for early adopters. Once the majority of controllers matures this quirk will be removed. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 51 ++++++++++++++++++++++++++++++++++++- net/bluetooth/mgmt.c | 6 +++-- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 0253276e88e4..2bc19881e250 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -117,6 +117,7 @@ enum { HCI_SERVICE_CACHE, HCI_DEBUG_KEYS, HCI_DUT_MODE, + HCI_FORCE_SC, HCI_UNREGISTER, HCI_USER_CHANNEL, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b3b619a448b5..946631ffe802 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -415,6 +415,52 @@ static int ssp_debug_mode_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(ssp_debug_mode_fops, ssp_debug_mode_get, ssp_debug_mode_set, "%llu\n"); +static ssize_t force_sc_support_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + char buf[3]; + + buf[0] = test_bit(HCI_FORCE_SC, &hdev->dev_flags) ? 'Y': 'N'; + buf[1] = '\n'; + buf[2] = '\0'; + return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static ssize_t force_sc_support_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + char buf[32]; + size_t buf_size = min(count, (sizeof(buf)-1)); + bool enable; + + if (test_bit(HCI_UP, &hdev->flags)) + return -EBUSY; + + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + buf[buf_size] = '\0'; + if (strtobool(buf, &enable)) + return -EINVAL; + + if (enable == test_bit(HCI_FORCE_SC, &hdev->dev_flags)) + return -EALREADY; + + change_bit(HCI_FORCE_SC, &hdev->dev_flags); + + return count; +} + +static const struct file_operations force_sc_support_fops = { + .open = simple_open, + .read = force_sc_support_read, + .write = force_sc_support_write, + .llseek = default_llseek, +}; + static int idle_timeout_set(void *data, u64 val) { struct hci_dev *hdev = data; @@ -1365,7 +1411,8 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL); /* Enable Secure Connections if supported and configured */ - if (lmp_sc_capable(hdev) && + if ((lmp_sc_capable(hdev) || + test_bit(HCI_FORCE_SC, &hdev->dev_flags)) && test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { u8 support = 0x01; hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT, @@ -1442,6 +1489,8 @@ static int __hci_init(struct hci_dev *hdev) hdev, &auto_accept_delay_fops); debugfs_create_file("ssp_debug_mode", 0644, hdev->debugfs, hdev, &ssp_debug_mode_fops); + debugfs_create_file("force_sc_support", 0644, hdev->debugfs, + hdev, &force_sc_support_fops); } if (lmp_sniff_capable(hdev)) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a7d4ae679ab7..bbe30c983492 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -378,7 +378,8 @@ static u32 get_supported_settings(struct hci_dev *hdev) settings |= MGMT_SETTING_HS; } - if (lmp_sc_capable(hdev)) + if (lmp_sc_capable(hdev) || + test_bit(HCI_FORCE_SC, &hdev->dev_flags)) settings |= MGMT_SETTING_SECURE_CONN; } @@ -4026,7 +4027,8 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, status); - if (!lmp_sc_capable(hdev)) + if (!lmp_sc_capable(hdev) && + !test_bit(HCI_FORCE_SC, &hdev->dev_flags)) return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, MGMT_STATUS_NOT_SUPPORTED); From 519ca9d017ab7eb4a15787bd8f2d867bebe375bc Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:28 -0800 Subject: [PATCH 014/139] Bluetooth: Provide remote OOB data for Secure Connections When Secure Connections has been enabled it is possible to provide P-192 and/or P-256 data during the pairing process. The internal out-of-band credentials storage has been extended to also hold P-256 data. Initially the P-256 data will be empty and with Secure Connections enabled no P-256 data will be provided. This is according to the specification since it might be possible that the remote side did not provide either of the out-of-band credentials. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 6 ++++-- net/bluetooth/hci_core.c | 6 +++--- net/bluetooth/hci_event.c | 32 ++++++++++++++++++++++++-------- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bd15eaa4c06e..5948930f92e6 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -114,8 +114,10 @@ struct link_key { struct oob_data { struct list_head list; bdaddr_t bdaddr; - u8 hash[16]; - u8 randomizer[16]; + u8 hash192[16]; + u8 randomizer192[16]; + u8 hash256[16]; + u8 randomizer256[16]; }; #define HCI_MAX_SHORT_NAME_LENGTH 10 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 946631ffe802..f13c0550f368 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2802,7 +2802,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, data = hci_find_remote_oob_data(hdev, bdaddr); if (!data) { - data = kmalloc(sizeof(*data), GFP_ATOMIC); + data = kzalloc(sizeof(*data), GFP_ATOMIC); if (!data) return -ENOMEM; @@ -2810,8 +2810,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, list_add(&data->list, &hdev->remote_oob_data); } - memcpy(data->hash, hash, sizeof(data->hash)); - memcpy(data->randomizer, randomizer, sizeof(data->randomizer)); + memcpy(data->hash192, hash, sizeof(data->hash192)); + memcpy(data->randomizer192, randomizer, sizeof(data->randomizer192)); BT_DBG("%s for %pMR", hdev->name, bdaddr); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d5374d36e9fe..da1eca1c43db 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3391,20 +3391,36 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev, data = hci_find_remote_oob_data(hdev, &ev->bdaddr); if (data) { - struct hci_cp_remote_oob_data_reply cp; + if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { + struct hci_cp_remote_oob_ext_data_reply cp; - bacpy(&cp.bdaddr, &ev->bdaddr); - memcpy(cp.hash, data->hash, sizeof(cp.hash)); - memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer)); + bacpy(&cp.bdaddr, &ev->bdaddr); + memcpy(cp.hash192, data->hash192, sizeof(cp.hash192)); + memcpy(cp.randomizer192, data->randomizer192, + sizeof(cp.randomizer192)); + memcpy(cp.hash256, data->hash256, sizeof(cp.hash256)); + memcpy(cp.randomizer256, data->randomizer256, + sizeof(cp.randomizer256)); - hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp), - &cp); + hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_EXT_DATA_REPLY, + sizeof(cp), &cp); + } else { + struct hci_cp_remote_oob_data_reply cp; + + bacpy(&cp.bdaddr, &ev->bdaddr); + memcpy(cp.hash, data->hash192, sizeof(cp.hash)); + memcpy(cp.randomizer, data->randomizer192, + sizeof(cp.randomizer)); + + hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, + sizeof(cp), &cp); + } } else { struct hci_cp_remote_oob_data_neg_reply cp; bacpy(&cp.bdaddr, &ev->bdaddr); - hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp), - &cp); + hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, + sizeof(cp), &cp); } unlock: From 0798872ef1ad6433362faca1d16a31ad7ad72638 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:29 -0800 Subject: [PATCH 015/139] Bluetooth: Add internal function for storing P-192 and P-256 data Add function to allow adding P-192 and P-256 data to the internal storage. This also fixes a few coding style issues from the previous helper functions for the out-of-band credentials storage. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 9 +++++--- net/bluetooth/hci_core.c | 37 ++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5948930f92e6..66e96ebffe97 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -761,9 +761,12 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_remote_oob_data_clear(struct hci_dev *hdev); struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, - bdaddr_t *bdaddr); -int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, - u8 *randomizer); + bdaddr_t *bdaddr); +int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 *hash, u8 *randomizer); +int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 *hash192, u8 *randomizer192, + u8 *hash256, u8 *randomizer256); int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f13c0550f368..499ec1b1095d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2794,15 +2794,14 @@ int hci_remote_oob_data_clear(struct hci_dev *hdev) return 0; } -int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, - u8 *randomizer) +int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 *hash, u8 *randomizer) { struct oob_data *data; data = hci_find_remote_oob_data(hdev, bdaddr); - if (!data) { - data = kzalloc(sizeof(*data), GFP_ATOMIC); + data = kmalloc(sizeof(*data), GFP_ATOMIC); if (!data) return -ENOMEM; @@ -2813,6 +2812,36 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, memcpy(data->hash192, hash, sizeof(data->hash192)); memcpy(data->randomizer192, randomizer, sizeof(data->randomizer192)); + memset(data->hash256, 0, sizeof(data->hash256)); + memset(data->randomizer256, 0, sizeof(data->randomizer256)); + + BT_DBG("%s for %pMR", hdev->name, bdaddr); + + return 0; +} + +int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 *hash192, u8 *randomizer192, + u8 *hash256, u8 *randomizer256) +{ + struct oob_data *data; + + data = hci_find_remote_oob_data(hdev, bdaddr); + if (!data) { + data = kmalloc(sizeof(*data), GFP_ATOMIC); + if (!data) + return -ENOMEM; + + bacpy(&data->bdaddr, bdaddr); + list_add(&data->list, &hdev->remote_oob_data); + } + + memcpy(data->hash192, hash192, sizeof(data->hash192)); + memcpy(data->randomizer192, randomizer192, sizeof(data->randomizer192)); + + memcpy(data->hash256, hash256, sizeof(data->hash256)); + memcpy(data->randomizer256, randomizer256, sizeof(data->randomizer256)); + BT_DBG("%s for %pMR", hdev->name, bdaddr); return 0; From ec1091131f9b53ea280247b5a01a617ce87d399e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 10 Jan 2014 02:07:30 -0800 Subject: [PATCH 016/139] Bluetooth: Add support for remote OOB input of P-256 data The current management interface only allows to provide the remote OOB input of P-192 data. This extends the command to also accept P-256 data as well. To make this backwards compatible, the userspace can decide to only provide P-192 data or the combined P-192 and P-256 data. It is also allowed to leave the P-192 data empty if userspace only has the remote P-256 data. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 8 +++++++ net/bluetooth/mgmt.c | 45 +++++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 036ddc7dc7ed..e19049fb6c46 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -309,6 +309,14 @@ struct mgmt_cp_add_remote_oob_data { __u8 randomizer[16]; } __packed; #define MGMT_ADD_REMOTE_OOB_DATA_SIZE (MGMT_ADDR_INFO_SIZE + 32) +struct mgmt_cp_add_remote_oob_ext_data { + struct mgmt_addr_info addr; + __u8 hash192[16]; + __u8 randomizer192[16]; + __u8 hash256[16]; + __u8 randomizer256[16]; +} __packed; +#define MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE (MGMT_ADDR_INFO_SIZE + 64) #define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0022 struct mgmt_cp_remove_remote_oob_data { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bbe30c983492..4b6034fcc902 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3096,23 +3096,46 @@ unlock: static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { - struct mgmt_cp_add_remote_oob_data *cp = data; - u8 status; int err; BT_DBG("%s ", hdev->name); hci_dev_lock(hdev); - err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash, - cp->randomizer); - if (err < 0) - status = MGMT_STATUS_FAILED; - else - status = MGMT_STATUS_SUCCESS; + if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) { + struct mgmt_cp_add_remote_oob_data *cp = data; + u8 status; - err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status, - &cp->addr, sizeof(cp->addr)); + err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, + cp->hash, cp->randomizer); + if (err < 0) + status = MGMT_STATUS_FAILED; + else + status = MGMT_STATUS_SUCCESS; + + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, + status, &cp->addr, sizeof(cp->addr)); + } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) { + struct mgmt_cp_add_remote_oob_ext_data *cp = data; + u8 status; + + err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr, + cp->hash192, + cp->randomizer192, + cp->hash256, + cp->randomizer256); + if (err < 0) + status = MGMT_STATUS_FAILED; + else + status = MGMT_STATUS_SUCCESS; + + err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, + status, &cp->addr, sizeof(cp->addr)); + } else { + BT_ERR("add_remote_oob_data: invalid length of %u bytes", len); + err = cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, + MGMT_STATUS_INVALID_PARAMS); + } hci_dev_unlock(hdev); return err; @@ -4202,7 +4225,7 @@ static const struct mgmt_handler { { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE }, { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE }, { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE }, - { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE }, + { add_remote_oob_data, true, MGMT_ADD_REMOTE_OOB_DATA_SIZE }, { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE }, { start_discovery, false, MGMT_START_DISCOVERY_SIZE }, { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE }, From b848079a5e55480e16439af62c94f02ca1e33b08 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 7 Jan 2014 22:23:08 +0800 Subject: [PATCH 017/139] Bluetooth: Convert to use ATTRIBUTE_GROUPS macro Use ATTRIBUTE_GROUPS macro to reduce the number of lines of code. Signed-off-by: Wei Yongjun Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sysfs.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 0b61250cfdf9..555982a78a58 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -49,14 +49,7 @@ static struct attribute *bt_link_attrs[] = { NULL }; -static struct attribute_group bt_link_group = { - .attrs = bt_link_attrs, -}; - -static const struct attribute_group *bt_link_groups[] = { - &bt_link_group, - NULL -}; +ATTRIBUTE_GROUPS(bt_link); static void bt_link_release(struct device *dev) { @@ -182,14 +175,7 @@ static struct attribute *bt_host_attrs[] = { NULL }; -static struct attribute_group bt_host_group = { - .attrs = bt_host_attrs, -}; - -static const struct attribute_group *bt_host_groups[] = { - &bt_host_group, - NULL -}; +ATTRIBUTE_GROUPS(bt_host); static void bt_host_release(struct device *dev) { From eadd663a6ab78df479d116a59368a70dc60d8288 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 13 Jan 2014 17:15:53 +0200 Subject: [PATCH 018/139] Bluetooth: Fix mgmt error code for negative PIN response The NOT_PAIRED status is only really suitable for operations where being paired is a pre-requisite. Using it e.g. for the mgmt_pair_device command seems unintuitive. In the case that either the local or the remote user responds with a negative PIN Code response the "PIN or Key Missing" HCI status will be generated. This patch changes the mapping of this status from the NOT_PAIRED mgmt status to the more intuitive AUTH_FAILED mgmt status. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4b6034fcc902..4ee07b432379 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -128,7 +128,7 @@ static u8 mgmt_status_table[] = { MGMT_STATUS_FAILED, /* Hardware Failure */ MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */ MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */ - MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */ + MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */ MGMT_STATUS_NO_RESOURCES, /* Memory Full */ MGMT_STATUS_TIMEOUT, /* Connection Timeout */ MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */ From eb9a8f3fb6762a4e6ae0aa9e96532c9c544f400e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 15 Jan 2014 22:37:38 -0800 Subject: [PATCH 019/139] Bluetooth: Track Secure Connections support of remote devices It is important to know if Secure Connections support has been enabled for a given remote device. The information is provided in the remote host features page. So track this information and provide a simple helper function to extract the status. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 8 ++++++++ net/bluetooth/hci_event.c | 3 +++ 2 files changed, 11 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 66e96ebffe97..8d225e4ea2ce 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -448,6 +448,7 @@ enum { HCI_CONN_LE_SMP_PEND, HCI_CONN_MGMT_CONNECTED, HCI_CONN_SSP_ENABLED, + HCI_CONN_SC_ENABLED, HCI_CONN_POWER_SAVE, HCI_CONN_REMOTE_OOB, HCI_CONN_6LOWPAN, @@ -460,6 +461,13 @@ static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) test_bit(HCI_CONN_SSP_ENABLED, &conn->flags); } +static inline bool hci_conn_sc_enabled(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + return test_bit(HCI_SC_ENABLED, &hdev->dev_flags) && + test_bit(HCI_CONN_SC_ENABLED, &conn->flags); +} + static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) { struct hci_conn_hash *h = &hdev->conn_hash; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index da1eca1c43db..8c44bbe19add 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2898,6 +2898,9 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, * features do not indicate SSP support */ clear_bit(HCI_CONN_SSP_ENABLED, &conn->flags); } + + if (ev->features[0] & LMP_HOST_SC) + set_bit(HCI_CONN_SC_ENABLED, &conn->flags); } if (conn->state != BT_CONFIG) From 7b5a9241b780ea2f77e71647bc0d3c9708c18ef1 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 15 Jan 2014 22:37:39 -0800 Subject: [PATCH 020/139] Bluetooth: Introduce requirements for security level 4 The security level 4 is a new strong security requirement that is based around 128-bit equivalent strength for link and encryption keys required using FIPS approved algorithms. Which means that E0, SAFER+ and P-192 are not allowed. Only connections created with P-256 resulting from using Secure Connections support are allowed. This security level needs to be enforced when Secure Connection Only mode is enabled for a controller or a service requires FIPS compliant strong security. Currently it is not possible to enable either of these two cases. This patch just puts in the foundation for being able to handle security level 4 in the future. It should be noted that devices or services with security level 4 requirement can only communicate using Bluetooth 4.1 controllers with support for Secure Connections. There is no backward compatibilty if used with older hardware. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 1 + include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_conn.c | 18 +++++++++++++----- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index f4f9ee466791..904777c1cd24 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -65,6 +65,7 @@ struct bt_security { #define BT_SECURITY_LOW 1 #define BT_SECURITY_MEDIUM 2 #define BT_SECURITY_HIGH 3 +#define BT_SECURITY_FIPS 4 #define BT_DEFER_SETUP 7 diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 2bc19881e250..0064a9aa5df1 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -313,6 +313,7 @@ enum { #define HCI_LM_TRUSTED 0x0008 #define HCI_LM_RELIABLE 0x0010 #define HCI_LM_SECURE 0x0020 +#define HCI_LM_FIPS 0x0040 /* Authentication types */ #define HCI_AT_NO_BONDING 0x00 diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index cf96b3438a91..0266bd8e4913 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -800,10 +800,17 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) if (!(conn->link_mode & HCI_LM_AUTH)) goto auth; - /* An authenticated combination key has sufficient security for any - security level. */ - if (conn->key_type == HCI_LK_AUTH_COMBINATION_P192 || - conn->key_type == HCI_LK_AUTH_COMBINATION_P256) + /* An authenticated FIPS approved combination key has sufficient + * security for security level 4. */ + if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256 && + sec_level == BT_SECURITY_FIPS) + goto encrypt; + + /* An authenticated combination key has sufficient security for + security level 3. */ + if ((conn->key_type == HCI_LK_AUTH_COMBINATION_P192 || + conn->key_type == HCI_LK_AUTH_COMBINATION_P256) && + sec_level == BT_SECURITY_HIGH) goto encrypt; /* An unauthenticated combination key has sufficient security for @@ -818,7 +825,8 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) is generated using maximum PIN code length (16). For pre 2.1 units. */ if (conn->key_type == HCI_LK_COMBINATION && - (sec_level != BT_SECURITY_HIGH || conn->pin_length == 16)) + (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW || + conn->pin_length == 16)) goto encrypt; auth: From 7d513e9243afd01df315db45ffe96a6e3688e612 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 15 Jan 2014 22:37:40 -0800 Subject: [PATCH 021/139] Bluetooth: Handle security level 4 for L2CAP connections With the introduction of security level 4, the L2CAP sockets need to be made aware of this new level. This change ensures that the pairing requirements are set correctly for these connections. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 11 ++++++++--- net/bluetooth/l2cap_sock.c | 10 ++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index dbc4a89984ca..c695083eee2b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -91,6 +91,7 @@ struct l2cap_conninfo { #define L2CAP_LM_TRUSTED 0x0008 #define L2CAP_LM_RELIABLE 0x0010 #define L2CAP_LM_SECURE 0x0020 +#define L2CAP_LM_FIPS 0x0040 /* L2CAP command codes */ #define L2CAP_COMMAND_REJ 0x01 diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b0ad2c752d73..3f0dd552cb2b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -737,6 +737,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) case L2CAP_CHAN_RAW: switch (chan->sec_level) { case BT_SECURITY_HIGH: + case BT_SECURITY_FIPS: return HCI_AT_DEDICATED_BONDING_MITM; case BT_SECURITY_MEDIUM: return HCI_AT_DEDICATED_BONDING; @@ -749,7 +750,8 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) if (chan->sec_level == BT_SECURITY_LOW) chan->sec_level = BT_SECURITY_SDP; } - if (chan->sec_level == BT_SECURITY_HIGH) + if (chan->sec_level == BT_SECURITY_HIGH || + chan->sec_level == BT_SECURITY_FIPS) return HCI_AT_NO_BONDING_MITM; else return HCI_AT_NO_BONDING; @@ -759,7 +761,8 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) if (chan->sec_level == BT_SECURITY_LOW) chan->sec_level = BT_SECURITY_SDP; - if (chan->sec_level == BT_SECURITY_HIGH) + if (chan->sec_level == BT_SECURITY_HIGH || + chan->sec_level == BT_SECURITY_FIPS) return HCI_AT_NO_BONDING_MITM; else return HCI_AT_NO_BONDING; @@ -768,6 +771,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) default: switch (chan->sec_level) { case BT_SECURITY_HIGH: + case BT_SECURITY_FIPS: return HCI_AT_GENERAL_BONDING_MITM; case BT_SECURITY_MEDIUM: return HCI_AT_GENERAL_BONDING; @@ -7206,7 +7210,8 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) if (encrypt == 0x00) { if (chan->sec_level == BT_SECURITY_MEDIUM) { __set_chan_timer(chan, L2CAP_ENC_TIMEOUT); - } else if (chan->sec_level == BT_SECURITY_HIGH) + } else if (chan->sec_level == BT_SECURITY_HIGH || + chan->sec_level == BT_SECURITY_FIPS) l2cap_chan_close(chan, ECONNREFUSED); } else { if (chan->sec_level == BT_SECURITY_MEDIUM) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index d58f76bcebd1..fe086b4efc0c 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -432,6 +432,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE; break; + case BT_SECURITY_FIPS: + opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | + L2CAP_LM_SECURE | L2CAP_LM_FIPS; + break; default: opt = 0; break; @@ -445,6 +449,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, if (put_user(opt, (u32 __user *) optval)) err = -EFAULT; + break; case L2CAP_CONNINFO: @@ -699,6 +704,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, break; } + if (opt & L2CAP_LM_FIPS) { + err = -EINVAL; + break; + } + if (opt & L2CAP_LM_AUTH) chan->sec_level = BT_SECURITY_LOW; if (opt & L2CAP_LM_ENCRYPT) From 2c068e0b924c6fabd9a2ac59bc451b4b656cbae3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 15 Jan 2014 22:37:41 -0800 Subject: [PATCH 022/139] Bluetooth: Handle security level 4 for RFCOMM connections With the introduction of security level 4, the RFCOMM sockets need to be made aware of this new level. This change ensures that the pairing requirements are set correctly for these connections. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/rfcomm.h | 1 + net/bluetooth/rfcomm/core.c | 4 +++- net/bluetooth/rfcomm/sock.c | 12 +++++++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index 486213a1aed8..c312cfc4e922 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -295,6 +295,7 @@ struct rfcomm_conninfo { #define RFCOMM_LM_TRUSTED 0x0008 #define RFCOMM_LM_RELIABLE 0x0010 #define RFCOMM_LM_SECURE 0x0020 +#define RFCOMM_LM_FIPS 0x0040 #define rfcomm_pi(sk) ((struct rfcomm_pinfo *) sk) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index facd8a79c038..ba115d472f7b 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -216,6 +216,7 @@ static int rfcomm_check_security(struct rfcomm_dlc *d) switch (d->sec_level) { case BT_SECURITY_HIGH: + case BT_SECURITY_FIPS: auth_type = HCI_AT_GENERAL_BONDING_MITM; break; case BT_SECURITY_MEDIUM: @@ -2085,7 +2086,8 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt) set_bit(RFCOMM_SEC_PENDING, &d->flags); rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); continue; - } else if (d->sec_level == BT_SECURITY_HIGH) { + } else if (d->sec_level == BT_SECURITY_HIGH || + d->sec_level == BT_SECURITY_FIPS) { set_bit(RFCOMM_ENC_DROP, &d->flags); continue; } diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 3c2d3e4aa2f5..fb8158af1f39 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -648,6 +648,11 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u break; } + if (opt & RFCOMM_LM_FIPS) { + err = -EINVAL; + break; + } + if (opt & RFCOMM_LM_AUTH) rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW; if (opt & RFCOMM_LM_ENCRYPT) @@ -762,7 +767,11 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u break; case BT_SECURITY_HIGH: opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT | - RFCOMM_LM_SECURE; + RFCOMM_LM_SECURE; + break; + case BT_SECURITY_FIPS: + opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT | + RFCOMM_LM_SECURE | RFCOMM_LM_FIPS; break; default: opt = 0; @@ -774,6 +783,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u if (put_user(opt, (u32 __user *) optval)) err = -EFAULT; + break; case RFCOMM_CONNINFO: From 134c2a89af22f500b1d7525d663fddda345ff01e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 15 Jan 2014 22:37:42 -0800 Subject: [PATCH 023/139] Bluetooth: Add debugfs entry to show Secure Connections Only mode For debugging purposes of Secure Connection Only support a simple debugfs entry is used to indicate if this mode is active or not. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 0064a9aa5df1..232c07804ca8 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -124,6 +124,7 @@ enum { HCI_LE_SCAN, HCI_SSP_ENABLED, HCI_SC_ENABLED, + HCI_SC_ONLY, HCI_HS_ENABLED, HCI_LE_ENABLED, HCI_ADVERTISING, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 499ec1b1095d..369d30750417 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -461,6 +461,24 @@ static const struct file_operations force_sc_support_fops = { .llseek = default_llseek, }; +static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + char buf[3]; + + buf[0] = test_bit(HCI_SC_ONLY, &hdev->dev_flags) ? 'Y': 'N'; + buf[1] = '\n'; + buf[2] = '\0'; + return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static const struct file_operations sc_only_mode_fops = { + .open = simple_open, + .read = sc_only_mode_read, + .llseek = default_llseek, +}; + static int idle_timeout_set(void *data, u64 val) { struct hci_dev *hdev = data; @@ -1491,6 +1509,8 @@ static int __hci_init(struct hci_dev *hdev) hdev, &ssp_debug_mode_fops); debugfs_create_file("force_sc_support", 0644, hdev->debugfs, hdev, &force_sc_support_fops); + debugfs_create_file("sc_only_mode", 0444, hdev->debugfs, + hdev, &sc_only_mode_fops); } if (lmp_sniff_capable(hdev)) { From b131237ca3995edad9efc162d0bc959c3b1dddc2 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 16 Jan 2014 15:37:11 +0100 Subject: [PATCH 024/139] Bluetooth: Enable Atheros 0cf3:311e for firmware upload The device will bind to btusb without firmware, but with the original buggy firmware device discovery does not work. No devices are detected. Device descriptor without firmware: T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311e Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms with firmware: T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311e Rev= 0.02 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Oliver Neukum Signed-off-by: Marcel Holtmann --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 106d1d8e16ad..99ea2ee5326f 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -77,6 +77,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0CF3, 0x3004) }, { USB_DEVICE(0x0CF3, 0x3008) }, { USB_DEVICE(0x0CF3, 0x311D) }, + { USB_DEVICE(0x0CF3, 0x311E) }, { USB_DEVICE(0x0CF3, 0x817a) }, { USB_DEVICE(0x13d3, 0x3375) }, { USB_DEVICE(0x04CA, 0x3004) }, @@ -122,6 +123,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index baeaaed299e4..cc7ddd7e662f 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -144,6 +144,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, From 1e56f1eb2bbeab0ddc3a1e536d2a0065cfe4c131 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 16 Jan 2014 16:02:58 +0100 Subject: [PATCH 025/139] Bluetooth: Add firmware update for Atheros 0cf3:311f The device is not functional without firmware. The device without firmware: T: Bus=02 Lev=02 Prnt=02 Port=05 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311f Rev=00.01 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb The device with firmware: T: Bus=02 Lev=02 Prnt=02 Port=05 Cnt=01 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=3007 Rev=00.01 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Signed-off-by: Oliver Neukum Signed-off-by: Marcel Holtmann --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 99ea2ee5326f..41ec6f9a8252 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -78,6 +78,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0CF3, 0x3008) }, { USB_DEVICE(0x0CF3, 0x311D) }, { USB_DEVICE(0x0CF3, 0x311E) }, + { USB_DEVICE(0x0CF3, 0x311F) }, { USB_DEVICE(0x0CF3, 0x817a) }, { USB_DEVICE(0x13d3, 0x3375) }, { USB_DEVICE(0x04CA, 0x3004) }, @@ -124,6 +125,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311F), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index cc7ddd7e662f..5926a9db44b4 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -145,6 +145,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311f), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, From 162b49e75cf2c6858852e7a0ae2c2e30e51f0e09 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Jan 2014 20:45:10 +0200 Subject: [PATCH 026/139] Bluetooth: Reorder L2CAP functions to avoid forward declarations This patch moves the l2cap_conn_add, is_valid_psm and l2cap_chan_connect functions further down in l2cap_core.c. The patch doesn't contain anything else except the relocation of these functions. By moving the functions further down the patch enables a subsequent patch that adds a pending RX queue to be implemented without a forward declaration of a function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 415 ++++++++++++++++++------------------- 1 file changed, 207 insertions(+), 208 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3f0dd552cb2b..317a5737daf6 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1722,66 +1722,6 @@ static void security_timeout(struct work_struct *work) } } -static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) -{ - struct l2cap_conn *conn = hcon->l2cap_data; - struct hci_chan *hchan; - - if (conn) - return conn; - - hchan = hci_chan_create(hcon); - if (!hchan) - return NULL; - - conn = kzalloc(sizeof(struct l2cap_conn), GFP_KERNEL); - if (!conn) { - hci_chan_del(hchan); - return NULL; - } - - kref_init(&conn->ref); - hcon->l2cap_data = conn; - conn->hcon = hcon; - hci_conn_get(conn->hcon); - conn->hchan = hchan; - - BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan); - - switch (hcon->type) { - case LE_LINK: - if (hcon->hdev->le_mtu) { - conn->mtu = hcon->hdev->le_mtu; - break; - } - /* fall through */ - default: - conn->mtu = hcon->hdev->acl_mtu; - break; - } - - conn->feat_mask = 0; - - if (hcon->type == ACL_LINK) - conn->hs_enabled = test_bit(HCI_HS_ENABLED, - &hcon->hdev->dev_flags); - - spin_lock_init(&conn->lock); - mutex_init(&conn->chan_lock); - - INIT_LIST_HEAD(&conn->chan_l); - INIT_LIST_HEAD(&conn->users); - - if (hcon->type == LE_LINK) - INIT_DELAYED_WORK(&conn->security_timer, security_timeout); - else - INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); - - conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; - - return conn; -} - static void l2cap_conn_free(struct kref *ref) { struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref); @@ -1852,154 +1792,6 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, return c1; } -static bool is_valid_psm(u16 psm, u8 dst_type) -{ - if (!psm) - return false; - - if (bdaddr_type_is_le(dst_type)) - return (psm <= 0x00ff); - - /* PSM must be odd and lsb of upper byte must be 0 */ - return ((psm & 0x0101) == 0x0001); -} - -int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, - bdaddr_t *dst, u8 dst_type) -{ - struct l2cap_conn *conn; - struct hci_conn *hcon; - struct hci_dev *hdev; - __u8 auth_type; - int err; - - BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst, - dst_type, __le16_to_cpu(psm)); - - hdev = hci_get_route(dst, &chan->src); - if (!hdev) - return -EHOSTUNREACH; - - hci_dev_lock(hdev); - - l2cap_chan_lock(chan); - - if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid && - chan->chan_type != L2CAP_CHAN_RAW) { - err = -EINVAL; - goto done; - } - - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) { - err = -EINVAL; - goto done; - } - - switch (chan->mode) { - case L2CAP_MODE_BASIC: - break; - case L2CAP_MODE_LE_FLOWCTL: - l2cap_le_flowctl_init(chan); - break; - case L2CAP_MODE_ERTM: - case L2CAP_MODE_STREAMING: - if (!disable_ertm) - break; - /* fall through */ - default: - err = -ENOTSUPP; - goto done; - } - - switch (chan->state) { - case BT_CONNECT: - case BT_CONNECT2: - case BT_CONFIG: - /* Already connecting */ - err = 0; - goto done; - - case BT_CONNECTED: - /* Already connected */ - err = -EISCONN; - goto done; - - case BT_OPEN: - case BT_BOUND: - /* Can connect */ - break; - - default: - err = -EBADFD; - goto done; - } - - /* Set destination address and psm */ - bacpy(&chan->dst, dst); - chan->dst_type = dst_type; - - chan->psm = psm; - chan->dcid = cid; - - auth_type = l2cap_get_auth_type(chan); - - if (bdaddr_type_is_le(dst_type)) - hcon = hci_connect(hdev, LE_LINK, dst, dst_type, - chan->sec_level, auth_type); - else - hcon = hci_connect(hdev, ACL_LINK, dst, dst_type, - chan->sec_level, auth_type); - - if (IS_ERR(hcon)) { - err = PTR_ERR(hcon); - goto done; - } - - conn = l2cap_conn_add(hcon); - if (!conn) { - hci_conn_drop(hcon); - err = -ENOMEM; - goto done; - } - - if (cid && __l2cap_get_chan_by_dcid(conn, cid)) { - hci_conn_drop(hcon); - err = -EBUSY; - goto done; - } - - /* Update source addr of the socket */ - bacpy(&chan->src, &hcon->src); - chan->src_type = bdaddr_type(hcon, hcon->src_type); - - l2cap_chan_unlock(chan); - l2cap_chan_add(conn, chan); - l2cap_chan_lock(chan); - - /* l2cap_chan_add takes its own ref so we can drop this one */ - hci_conn_drop(hcon); - - l2cap_state_change(chan, BT_CONNECT); - __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); - - if (hcon->state == BT_CONNECTED) { - if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { - __clear_chan_timer(chan); - if (l2cap_chan_check_security(chan)) - l2cap_state_change(chan, BT_CONNECTED); - } else - l2cap_do_start(chan); - } - - err = 0; - -done: - l2cap_chan_unlock(chan); - hci_dev_unlock(hdev); - hci_dev_put(hdev); - return err; -} - static void l2cap_monitor_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, @@ -7136,6 +6928,213 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) } } +static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) +{ + struct l2cap_conn *conn = hcon->l2cap_data; + struct hci_chan *hchan; + + if (conn) + return conn; + + hchan = hci_chan_create(hcon); + if (!hchan) + return NULL; + + conn = kzalloc(sizeof(struct l2cap_conn), GFP_KERNEL); + if (!conn) { + hci_chan_del(hchan); + return NULL; + } + + kref_init(&conn->ref); + hcon->l2cap_data = conn; + conn->hcon = hcon; + hci_conn_get(conn->hcon); + conn->hchan = hchan; + + BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan); + + switch (hcon->type) { + case LE_LINK: + if (hcon->hdev->le_mtu) { + conn->mtu = hcon->hdev->le_mtu; + break; + } + /* fall through */ + default: + conn->mtu = hcon->hdev->acl_mtu; + break; + } + + conn->feat_mask = 0; + + if (hcon->type == ACL_LINK) + conn->hs_enabled = test_bit(HCI_HS_ENABLED, + &hcon->hdev->dev_flags); + + spin_lock_init(&conn->lock); + mutex_init(&conn->chan_lock); + + INIT_LIST_HEAD(&conn->chan_l); + INIT_LIST_HEAD(&conn->users); + + if (hcon->type == LE_LINK) + INIT_DELAYED_WORK(&conn->security_timer, security_timeout); + else + INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); + + conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; + + return conn; +} + +static bool is_valid_psm(u16 psm, u8 dst_type) { + if (!psm) + return false; + + if (bdaddr_type_is_le(dst_type)) + return (psm <= 0x00ff); + + /* PSM must be odd and lsb of upper byte must be 0 */ + return ((psm & 0x0101) == 0x0001); +} + +int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, + bdaddr_t *dst, u8 dst_type) +{ + struct l2cap_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; + __u8 auth_type; + int err; + + BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst, + dst_type, __le16_to_cpu(psm)); + + hdev = hci_get_route(dst, &chan->src); + if (!hdev) + return -EHOSTUNREACH; + + hci_dev_lock(hdev); + + l2cap_chan_lock(chan); + + if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid && + chan->chan_type != L2CAP_CHAN_RAW) { + err = -EINVAL; + goto done; + } + + if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) { + err = -EINVAL; + goto done; + } + + switch (chan->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_LE_FLOWCTL: + l2cap_le_flowctl_init(chan); + break; + case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: + if (!disable_ertm) + break; + /* fall through */ + default: + err = -ENOTSUPP; + goto done; + } + + switch (chan->state) { + case BT_CONNECT: + case BT_CONNECT2: + case BT_CONFIG: + /* Already connecting */ + err = 0; + goto done; + + case BT_CONNECTED: + /* Already connected */ + err = -EISCONN; + goto done; + + case BT_OPEN: + case BT_BOUND: + /* Can connect */ + break; + + default: + err = -EBADFD; + goto done; + } + + /* Set destination address and psm */ + bacpy(&chan->dst, dst); + chan->dst_type = dst_type; + + chan->psm = psm; + chan->dcid = cid; + + auth_type = l2cap_get_auth_type(chan); + + if (bdaddr_type_is_le(dst_type)) + hcon = hci_connect(hdev, LE_LINK, dst, dst_type, + chan->sec_level, auth_type); + else + hcon = hci_connect(hdev, ACL_LINK, dst, dst_type, + chan->sec_level, auth_type); + + if (IS_ERR(hcon)) { + err = PTR_ERR(hcon); + goto done; + } + + conn = l2cap_conn_add(hcon); + if (!conn) { + hci_conn_drop(hcon); + err = -ENOMEM; + goto done; + } + + if (cid && __l2cap_get_chan_by_dcid(conn, cid)) { + hci_conn_drop(hcon); + err = -EBUSY; + goto done; + } + + /* Update source addr of the socket */ + bacpy(&chan->src, &hcon->src); + chan->src_type = bdaddr_type(hcon, hcon->src_type); + + l2cap_chan_unlock(chan); + l2cap_chan_add(conn, chan); + l2cap_chan_lock(chan); + + /* l2cap_chan_add takes its own ref so we can drop this one */ + hci_conn_drop(hcon); + + l2cap_state_change(chan, BT_CONNECT); + __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); + + if (hcon->state == BT_CONNECTED) { + if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { + __clear_chan_timer(chan); + if (l2cap_chan_check_security(chan)) + l2cap_state_change(chan, BT_CONNECTED); + } else + l2cap_do_start(chan); + } + + err = 0; + +done: + l2cap_chan_unlock(chan); + hci_dev_unlock(hdev); + hci_dev_put(hdev); + return err; +} + /* ---- L2CAP interface with lower layer (HCI) ---- */ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) From 61a939c68ee033d43be3aa436d95eb8afdd16142 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 17 Jan 2014 20:45:11 +0200 Subject: [PATCH 027/139] Bluetooth: Queue incoming ACL data until BT_CONNECTED state is reached This patch adds a queue for incoming L2CAP data that's received before l2cap_connect_cfm is called and processes the data once l2cap_connect_cfm is called. This way we ensure that we have e.g. all remote features before processing L2CAP signaling data (which is very important for making the correct security decisions). The processing of the pending rx data needs to be done through queue_work since unlike l2cap_recv_acldata, l2cap_connect_cfm is called with the hci_dev lock held which could cause potential deadlocks. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 3 +++ net/bluetooth/l2cap_core.c | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c695083eee2b..85cf40acc47e 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -624,6 +624,9 @@ struct l2cap_conn { __u32 rx_len; __u8 tx_ident; + struct sk_buff_head pending_rx; + struct work_struct pending_rx_work; + __u8 disc_reason; struct delayed_work security_timer; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 317a5737daf6..cd534599fbfa 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1550,6 +1550,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) } mutex_unlock(&conn->chan_lock); + + queue_work(hcon->hdev->workqueue, &conn->pending_rx_work); } /* Notify sockets that we cannot guaranty reliability anymore */ @@ -1675,6 +1677,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree_skb(conn->rx_skb); + skb_queue_purge(&conn->pending_rx); + flush_work(&conn->pending_rx_work); + l2cap_unregister_all_users(conn); mutex_lock(&conn->chan_lock); @@ -6880,9 +6885,16 @@ drop: static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) { struct l2cap_hdr *lh = (void *) skb->data; + struct hci_conn *hcon = conn->hcon; u16 cid, len; __le16 psm; + if (hcon->state != BT_CONNECTED) { + BT_DBG("queueing pending rx skb"); + skb_queue_tail(&conn->pending_rx, skb); + return; + } + skb_pull(skb, L2CAP_HDR_SIZE); cid = __le16_to_cpu(lh->cid); len = __le16_to_cpu(lh->len); @@ -6928,6 +6940,18 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) } } +static void process_pending_rx(struct work_struct *work) +{ + struct l2cap_conn *conn = container_of(work, struct l2cap_conn, + pending_rx_work); + struct sk_buff *skb; + + BT_DBG(""); + + while ((skb = skb_dequeue(&conn->pending_rx))) + l2cap_recv_frame(conn, skb); +} + static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) { struct l2cap_conn *conn = hcon->l2cap_data; @@ -6983,6 +7007,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) else INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); + skb_queue_head_init(&conn->pending_rx); + INIT_WORK(&conn->pending_rx_work, process_pending_rx); + conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; return conn; From 03a0c5d61c878e3196b80fa9dc9fbae0fb2eb8f8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 18 Jan 2014 21:32:59 +0200 Subject: [PATCH 028/139] Bluetooth: Remove useless l2cap_seq_list_remove function The only user of l2cap_seq_list_remove() was l2cap_seq_list_pop() which only removes the head, meaning only the "else if (seq_list->head == seq)" branch was ever being used. This patch moves the code from this branch straight into l2cap_seq_list_pop() and removes the (now useless) l2cap_seq_list_remove(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 48 ++++++++++---------------------------- 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cd534599fbfa..138394ad3e51 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -330,44 +330,20 @@ static inline bool l2cap_seq_list_contains(struct l2cap_seq_list *seq_list, return seq_list->list[seq & seq_list->mask] != L2CAP_SEQ_LIST_CLEAR; } -static u16 l2cap_seq_list_remove(struct l2cap_seq_list *seq_list, u16 seq) -{ - u16 mask = seq_list->mask; - - if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) { - /* In case someone tries to pop the head of an empty list */ - return L2CAP_SEQ_LIST_CLEAR; - } else if (seq_list->head == seq) { - /* Head can be removed in constant time */ - seq_list->head = seq_list->list[seq & mask]; - seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; - - if (seq_list->head == L2CAP_SEQ_LIST_TAIL) { - seq_list->head = L2CAP_SEQ_LIST_CLEAR; - seq_list->tail = L2CAP_SEQ_LIST_CLEAR; - } - } else { - /* Walk the list to find the sequence number */ - u16 prev = seq_list->head; - while (seq_list->list[prev & mask] != seq) { - prev = seq_list->list[prev & mask]; - if (prev == L2CAP_SEQ_LIST_TAIL) - return L2CAP_SEQ_LIST_CLEAR; - } - - /* Unlink the number from the list and clear it */ - seq_list->list[prev & mask] = seq_list->list[seq & mask]; - seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; - if (seq_list->tail == seq) - seq_list->tail = prev; - } - return seq; -} - static inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list) { - /* Remove the head in constant time */ - return l2cap_seq_list_remove(seq_list, seq_list->head); + u16 seq = seq_list->head; + u16 mask = seq_list->mask; + + seq_list->head = seq_list->list[seq & mask]; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; + + if (seq_list->head == L2CAP_SEQ_LIST_TAIL) { + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; + } + + return seq; } static void l2cap_seq_list_clear(struct l2cap_seq_list *seq_list) From 2338a7e0440d646c194d421748ea36665e648384 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 24 Jan 2014 10:35:40 +0200 Subject: [PATCH 029/139] Bluetooth: Rename L2CAP_CHAN_CONN_FIX_A2MP to L2CAP_CHAN_FIXED There's no reason why A2MP should need or deserve its on channel type. Instead we should be able to group all fixed CID users under a single channel type and reuse as much code as possible for them. Where CID specific exceptions are needed the chan-scid value can be used. This patch renames the current A2MP channel type to a generic one and thereby paves the way to allow converting ATT and SMP (and any future fixed channel protocols) to use the new channel type. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/a2mp.c | 8 ++++++-- net/bluetooth/l2cap_core.c | 15 ++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 85cf40acc47e..ae482f41594a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -651,7 +651,7 @@ struct l2cap_user { #define L2CAP_CHAN_RAW 1 #define L2CAP_CHAN_CONN_LESS 2 #define L2CAP_CHAN_CONN_ORIENTED 3 -#define L2CAP_CHAN_CONN_FIX_A2MP 4 +#define L2CAP_CHAN_FIXED 4 /* ----- L2CAP socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index efcd108822c4..f986b9968bdb 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -235,7 +235,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb, BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); - if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) + if (chan->scid == L2CAP_CID_A2MP) continue; l2cap_chan_lock(chan); @@ -726,7 +726,11 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked) BT_DBG("chan %p", chan); - chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP; + chan->chan_type = L2CAP_CHAN_FIXED; + chan->scid = L2CAP_CID_A2MP; + chan->dcid = L2CAP_CID_A2MP; + chan->omtu = L2CAP_A2MP_DEFAULT_MTU; + chan->imtu = L2CAP_A2MP_DEFAULT_MTU; chan->flush_to = L2CAP_DEFAULT_FLUSH_TO; chan->ops = &a2mp_chan_ops; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 138394ad3e51..cd28057d2903 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -519,11 +519,8 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) chan->omtu = L2CAP_DEFAULT_MTU; break; - case L2CAP_CHAN_CONN_FIX_A2MP: - chan->scid = L2CAP_CID_A2MP; - chan->dcid = L2CAP_CID_A2MP; - chan->omtu = L2CAP_A2MP_DEFAULT_MTU; - chan->imtu = L2CAP_A2MP_DEFAULT_MTU; + case L2CAP_CHAN_FIXED: + /* Caller will set CID and CID specific MTU values */ break; default: @@ -571,7 +568,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) chan->conn = NULL; - if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP) + if (chan->scid != L2CAP_CID_A2MP) hci_conn_drop(conn->hcon); if (mgr && mgr->bredr_chan == chan) @@ -1310,7 +1307,7 @@ static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err) __clear_ack_timer(chan); } - if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) { + if (chan->scid == L2CAP_CID_A2MP) { l2cap_state_change(chan, BT_DISCONN); return; } @@ -1508,7 +1505,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) l2cap_chan_lock(chan); - if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) { + if (chan->scid == L2CAP_CID_A2MP) { l2cap_chan_unlock(chan); continue; } @@ -7245,7 +7242,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid, state_to_string(chan->state)); - if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) { + if (chan->scid == L2CAP_CID_A2MP) { l2cap_chan_unlock(chan); continue; } From 21626e6214f92aaae580052c760dc85f83b5faef Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 24 Jan 2014 10:35:41 +0200 Subject: [PATCH 030/139] Bluetooth: Switch ATT channels to use L2CAP_CHAN_FIXED ATT channels are not connection oriented so having them use L2CAP_CHAN_CONN_ORIENTED is quite confusing. Instead, use the new L2CAP_CHAN_FIXED type and ensure that the MTU and CID values get properly set. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 21 +++++++++------------ net/bluetooth/l2cap_sock.c | 9 +++++++++ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cd28057d2903..e5c5c7427c41 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -498,18 +498,10 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) switch (chan->chan_type) { case L2CAP_CHAN_CONN_ORIENTED: - if (conn->hcon->type == LE_LINK) { - if (chan->dcid == L2CAP_CID_ATT) { - chan->omtu = L2CAP_DEFAULT_MTU; - chan->scid = L2CAP_CID_ATT; - } else { - chan->scid = l2cap_alloc_cid(conn); - } - } else { - /* Alloc CID for connection-oriented socket */ - chan->scid = l2cap_alloc_cid(conn); + /* Alloc CID for connection-oriented socket */ + chan->scid = l2cap_alloc_cid(conn); + if (conn->hcon->type == ACL_LINK) chan->omtu = L2CAP_DEFAULT_MTU; - } break; case L2CAP_CHAN_CONN_LESS: @@ -7025,7 +7017,12 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, goto done; } - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) { + if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !psm) { + err = -EINVAL; + goto done; + } + + if (chan->chan_type == L2CAP_CHAN_FIXED && !cid) { err = -EINVAL; goto done; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index fe086b4efc0c..04abd26a3466 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -101,6 +101,15 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) if (!bdaddr_type_is_valid(la.l2_bdaddr_type)) return -EINVAL; + if (la.l2_cid) { + /* When the socket gets created it defaults to + * CHAN_CONN_ORIENTED, so we need to overwrite the + * default here. + */ + chan->chan_type = L2CAP_CHAN_FIXED; + chan->omtu = L2CAP_DEFAULT_MTU; + } + if (bdaddr_type_is_le(la.l2_bdaddr_type)) { if (!enable_lecoc && la.l2_psm) return -EINVAL; From e0c888ad739513b9baae5c25e85dd6490595e5be Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 25 Jan 2014 17:10:07 -0500 Subject: [PATCH 031/139] Bluetooth: Fix BT_SECURITY socket option for fixed channels (ATT) The BT_SECURITY option should also be allowed for fixed channels, so punch the appropriate hole for it when checking for the channel type. The main user of fixed CID user space sockets is right now ATT (which is broken without this patch). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_sock.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 04abd26a3466..7ad346ea06ed 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -513,6 +513,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, switch (optname) { case BT_SECURITY: if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED && + chan->chan_type != L2CAP_CHAN_FIXED && chan->chan_type != L2CAP_CHAN_RAW) { err = -EINVAL; break; @@ -769,6 +770,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, switch (optname) { case BT_SECURITY: if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED && + chan->chan_type != L2CAP_CHAN_FIXED && chan->chan_type != L2CAP_CHAN_RAW) { err = -EINVAL; break; From 7a8e5a31ecd50ace4fce57304c8fdd206f013fde Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 25 Jan 2014 17:10:09 -0500 Subject: [PATCH 032/139] Bluetooth: Fix CID initialization for fixed channels Fixed channels have the same source and destination CID. Ensure that the values get properly initialized when receiving incoming connections and deriving values from the parent socket. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 2 -- net/bluetooth/l2cap_sock.c | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e5c5c7427c41..cc340700573e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1462,8 +1462,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) if (!chan) goto clean; - chan->dcid = L2CAP_CID_ATT; - bacpy(&chan->src, &hcon->src); bacpy(&chan->dst, &hcon->dst); chan->src_type = bdaddr_type(hcon, hcon->src_type); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 7ad346ea06ed..ae4f6b593fc0 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1470,6 +1470,11 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->tx_credits = pchan->tx_credits; chan->rx_credits = pchan->rx_credits; + if (chan->chan_type == L2CAP_CHAN_FIXED) { + chan->scid = pchan->scid; + chan->dcid = pchan->scid; + } + security_sk_clone(parent, sk); } else { switch (sk->sk_type) { From d1d79413ec066b9d13390590be3ff684e2dd3631 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 27 Jan 2014 15:11:33 -0800 Subject: [PATCH 033/139] Bluetooth: Fix respecting le_default_mps value There's a le_default_mps variable that can be modified through debugfs but it was never actually used for determining our MPS value. This patch fixes the MPS initialization to use the variable instead of a fixed value. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cc340700573e..5a30fc72f4ba 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -482,7 +482,7 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan) chan->sdu_len = 0; chan->tx_credits = 0; chan->rx_credits = le_max_credits; - chan->mps = min_t(u16, chan->imtu, L2CAP_LE_DEFAULT_MPS); + chan->mps = min_t(u16, chan->imtu, le_default_mps); skb_queue_head_init(&chan->tx_q); } From dfd9774c5ad4abe9d51e52056e441eaf983b9080 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 27 Jan 2014 15:11:34 -0800 Subject: [PATCH 034/139] Bluetooth: Fix disconnecting L2CAP channel for credits violation The L2CAP specification requires us to disconnect a channel if the remote device sends us data when it doesn't have any credits to do so. This patch makes sure that we send the appropriate L2CAP Disconnect request in this situation. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 5a30fc72f4ba..fbc9709abccf 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6635,6 +6635,7 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) if (!chan->rx_credits) { BT_ERR("No credits to receive LE L2CAP data"); + l2cap_send_disconn_req(chan, ECONNRESET); return -ENOBUFS; } From 0f1bfe4e5eb8db9841b57ade1384b9a8ffcd38c3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 27 Jan 2014 15:11:35 -0800 Subject: [PATCH 035/139] Bluetooth: Fix disconnecting L2CAP when a credits overflow occurs The L2CAP specification requires us to disconnect an L2CAP channel if the remote side gives us credits beyond 65535. This patch makes sure we disconnect the channel in such a situation. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index fbc9709abccf..d2ef49b54aa2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -42,6 +42,8 @@ #include "amp.h" #include "6lowpan.h" +#define LE_FLOWCTL_MAX_CREDITS 65535 + bool disable_ertm; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD; @@ -5473,7 +5475,7 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn, { struct l2cap_le_credits *pkt; struct l2cap_chan *chan; - u16 cid, credits; + u16 cid, credits, max_credits; if (cmd_len != sizeof(*pkt)) return -EPROTO; @@ -5488,6 +5490,17 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn, if (!chan) return -EBADSLT; + max_credits = LE_FLOWCTL_MAX_CREDITS - chan->tx_credits; + if (credits > max_credits) { + BT_ERR("LE credits overflow"); + l2cap_send_disconn_req(chan, ECONNRESET); + + /* Return 0 so that we don't trigger an unnecessary + * command reject packet. + */ + return 0; + } + chan->tx_credits += credits; while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) { From 61202e4de92d9bf7169dd5f2ef2d6c6e5683ec53 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Jan 2014 15:16:48 -0800 Subject: [PATCH 036/139] Bluetooth: Free up l2cap_chan->sport when initiating a connection The sport variable is used to track the allocation of the local PSM database to ensure no two sockets take the same local PSM. It is acquired upon bind() but needs to be freed up if the socket ends up becoming a client one. This patch adds the clearing of the value when l2cap_chan_connect is called. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d2ef49b54aa2..f583988a4653 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7126,6 +7126,13 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, l2cap_state_change(chan, BT_CONNECT); __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); + /* Release chan->sport so that it can be reused by other + * sockets (as it's only used for listening sockets). + */ + write_lock(&chan_list_lock); + chan->sport = 0; + write_unlock(&chan_list_lock); + if (hcon->state == BT_CONNECTED) { if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { __clear_chan_timer(chan); From b783fbc3a55691f978b9f78d552a0d7e7d2705ad Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Jan 2014 15:16:49 -0800 Subject: [PATCH 037/139] Bluetooth: Refuse peer L2CAP address reading when not connected When we're not connected the peer address information is undefined. This patch fixes the remote address getting to return a proper error in case the state is anything else than BT_CONNECTED. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_sock.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index ae4f6b593fc0..b0aaa651a5ba 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -366,6 +366,9 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, BT_DBG("sock %p, sk %p", sock, sk); + if (peer && sk->sk_state != BT_CONNECTED) + return -ENOTCONN; + memset(la, 0, sizeof(struct sockaddr_l2)); addr->sa_family = AF_BLUETOOTH; *len = sizeof(struct sockaddr_l2); From 35364c99d20edc7329843e2a6dad6851d77eafd7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Jan 2014 15:16:50 -0800 Subject: [PATCH 038/139] Bluetooth: Refuse peer RFCOMM address reading when not connected When we're not connected the peer address information is undefined. This patch fixes the remote address getting to return a proper error in case the sate is anything else than BT_CONNECTED. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/sock.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index fb8158af1f39..00573fb79030 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -528,6 +528,9 @@ static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int * BT_DBG("sock %p, sk %p", sock, sk); + if (peer && sk->sk_state != BT_CONNECTED) + return -ENOTCONN; + memset(sa, 0, sizeof(*sa)); sa->rc_family = AF_BLUETOOTH; sa->rc_channel = rfcomm_pi(sk)->channel; From d7e5e76b6f4c5848ad3093493bdb226c27d8350e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Jan 2014 15:16:51 -0800 Subject: [PATCH 039/139] Bluetooth: Always use l2cap_chan->psm for returning PSM to user space The l2cap_chan->psm value is always set to a valid value for a connection oriented channel. The l2cap_chan->sport is used for tracking local PSM allocations but will not always have a proper value, such as with connected sockets derived from a listening socket. This patch fixes the sock_getname callback to always use chan->psm when returning address information. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_sock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index b0aaa651a5ba..27d3d6d48b6e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -373,13 +373,13 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, addr->sa_family = AF_BLUETOOTH; *len = sizeof(struct sockaddr_l2); + la->l2_psm = chan->psm; + if (peer) { - la->l2_psm = chan->psm; bacpy(&la->l2_bdaddr, &chan->dst); la->l2_cid = cpu_to_le16(chan->dcid); la->l2_bdaddr_type = chan->dst_type; } else { - la->l2_psm = chan->sport; bacpy(&la->l2_bdaddr, &chan->src); la->l2_cid = cpu_to_le16(chan->scid); la->l2_bdaddr_type = chan->src_type; From 7b25c9b3c90150164f36b16cc0107d774eaec68f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 28 Jan 2014 15:28:04 -0800 Subject: [PATCH 040/139] Bluetooth: Remove unnecessary check for chan->psm Now that ATT sockets have been converted to use the new L2CAP_CHAN_FIXED type there is no need to have an extra check for chan->psm in the l2cap_chan_close function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index f583988a4653..66fbac91eaed 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -666,10 +666,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) case BT_CONNECTED: case BT_CONFIG: - /* ATT uses L2CAP_CHAN_CONN_ORIENTED so we must also - * check for chan->psm. - */ - if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && chan->psm) { + if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) { __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); l2cap_send_disconn_req(chan, reason); } else From 40456644295998321b8743b72c9cc0e4db937959 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 28 Jan 2014 15:39:01 -0800 Subject: [PATCH 041/139] Bluetooth: Increment management interface revision This patch increments the management interface revision due to the various fixes, improvements and other changes that have been made. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4ee07b432379..bde8e675c5ea 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -34,7 +34,7 @@ #include "smp.h" #define MGMT_VERSION 1 -#define MGMT_REVISION 4 +#define MGMT_REVISION 5 static const u16 mgmt_commands[] = { MGMT_OP_READ_INDEX_LIST, From 0cf73b9fa51be32042dad09953f7a82f19933e97 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 29 Jan 2014 13:55:59 -0800 Subject: [PATCH 042/139] Bluetooth: Enable LTK distribution to slave devices So far we've only been requesting the LTK to be distributed to the master (initiator) of pairing, which is usually enough since it's the master that will establish future connections and initiate encryption. However, in the case that both devices support switching to the opposing role (which seems to be increasingly common) pairing will have to performed again since the "new" master will not have all information. As there is no real harm in it, this patch updates the code to always try distributing the LTK also to the slave device, thereby enabling role switches for future connections. Signed-off-by: Johan Hedberg Acked-by: Vinicius Gomes Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 45007362683b..9b1167007653 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -216,7 +216,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, req->io_capability = conn->hcon->io_capability; req->oob_flag = SMP_OOB_NOT_PRESENT; req->max_key_size = SMP_MAX_ENC_KEY_SIZE; - req->init_key_dist = 0; + req->init_key_dist = dist_keys; req->resp_key_dist = dist_keys; req->auth_req = (authreq & AUTH_REQ_MASK); return; @@ -225,7 +225,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, rsp->io_capability = conn->hcon->io_capability; rsp->oob_flag = SMP_OOB_NOT_PRESENT; rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE; - rsp->init_key_dist = 0; + rsp->init_key_dist = req->init_key_dist & dist_keys; rsp->resp_key_dist = req->resp_key_dist & dist_keys; rsp->auth_req = (authreq & AUTH_REQ_MASK); } From e834004b8a940ab28dace6043985ae2adf305661 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 30 Jan 2014 11:16:50 -0800 Subject: [PATCH 043/139] Bluetooth: Remove Simultaneous LE & BR/EDR flags from AD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Starting with the 4.1 Core Specification these flags are no longer used and should always be cleared. From volume 3, part C, section 13.1.1: "The 'Simultaneous LE and BR/EDR to Same Device Capable (Controller)' and ‘Simultaneous LE and BR/EDR to Same Device Capable (Host)’ bits in the Flags AD type shall be set to ‘0’." Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bde8e675c5ea..111b1296a2b8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -637,14 +637,8 @@ static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr) flags |= get_adv_discov_flags(hdev); - if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) { - if (lmp_le_br_capable(hdev)) - flags |= LE_AD_SIM_LE_BREDR_CTRL; - if (lmp_host_le_br_capable(hdev)) - flags |= LE_AD_SIM_LE_BREDR_HOST; - } else { + if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) flags |= LE_AD_NO_BREDR; - } if (flags) { BT_DBG("adv flags 0x%02x", flags); From f813f1be1f82a09720e94533f46ac79276eb037d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 30 Jan 2014 19:39:57 -0800 Subject: [PATCH 044/139] Bluetooth: Fix long_term_keys debugfs output The code was previously iterating the wrong list (and what's worse casting entries to a type which they were not) and also missing a proper line terminator when printing each entry. The code now also prints the LTK type in hex for easier comparison with the kernel-defined values. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 369d30750417..8094a41c9a26 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -620,9 +620,9 @@ static int long_term_keys_show(struct seq_file *f, void *ptr) struct list_head *p, *n; hci_dev_lock(hdev); - list_for_each_safe(p, n, &hdev->link_keys) { + list_for_each_safe(p, n, &hdev->long_term_keys) { struct smp_ltk *ltk = list_entry(p, struct smp_ltk, list); - seq_printf(f, "%pMR (type %u) %u %u %u %.4x %*phN %*phN\\n", + seq_printf(f, "%pMR (type %u) %u 0x%02x %u %.4x %*phN %*phN\n", <k->bdaddr, ltk->bdaddr_type, ltk->authenticated, ltk->type, ltk->enc_size, __le16_to_cpu(ltk->ediv), 8, ltk->rand, 16, ltk->val); From 21b93b75ad1090dd9aed69b56292648bac6666a9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 30 Jan 2014 19:39:58 -0800 Subject: [PATCH 045/139] Bluetooth: Make LTK key type check more readable Instead of magic bitwise operations simply compare with the two possible type values that we are interested in. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8094a41c9a26..754a59079de9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2717,7 +2717,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, if (!new_key) return 0; - if (type & HCI_SMP_LTK) + if (type == HCI_SMP_LTK || type == HCI_SMP_LTK_SLAVE) mgmt_new_ltk(hdev, key, 1); return 0; From a513e260ce25eaa5e8c6b834a70085be1d6f40c0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 30 Jan 2014 19:39:59 -0800 Subject: [PATCH 046/139] Bluetooth: Remove unnecessary LTK type check from hci_add_ltk All callers of hci_add_ltk pass a valid value to it. There are no places where e.g. user space, the controller or the remote peer would be able to cause invalid values to be passed. Therefore, just remove the potentially confusing check from the beginning of the function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 754a59079de9..180473d965f6 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2692,9 +2692,6 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, { struct smp_ltk *key, *old_key; - if (!(type & HCI_SMP_STK) && !(type & HCI_SMP_LTK)) - return 0; - old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type); if (old_key) key = old_key; From 98a0b845c63cb74e90a72d1e864ea4be968bdd83 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 30 Jan 2014 19:40:00 -0800 Subject: [PATCH 047/139] Bluetooth: Fix differentiating stored master vs slave LTK types If LTK distribution happens in both directions we will have two LTKs for the same remote device: one which is used when we're connecting as master and another when we're connecting as slave. When looking up LTKs from the locally stored list we shouldn't blindly return the first match but also consider which type of key is in question. If we do not do this we may end up selecting an incorrect encryption key for a connection. This patch fixes the issue by always specifying to the LTK lookup functions whether we're looking for a master or a slave key. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 5 +++-- net/bluetooth/hci_core.c | 22 ++++++++++++++++++---- net/bluetooth/hci_event.c | 2 +- net/bluetooth/smp.c | 3 ++- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8d225e4ea2ce..378e2f32cfa0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -757,12 +757,13 @@ int hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); -struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); +struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8], + bool master); int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, int new_key, u8 authenticated, u8 tk[16], u8 enc_size, __le16 ediv, u8 rand[8]); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type); + u8 addr_type, bool master); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 180473d965f6..d370b432aea6 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2605,7 +2605,16 @@ static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, return false; } -struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) +static bool ltk_type_master(u8 type) +{ + if (type == HCI_SMP_STK || type == HCI_SMP_LTK) + return true; + + return false; +} + +struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8], + bool master) { struct smp_ltk *k; @@ -2614,6 +2623,9 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) memcmp(rand, k->rand, sizeof(k->rand))) continue; + if (ltk_type_master(k->type) != master) + continue; + return k; } @@ -2621,13 +2633,14 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) } struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type) + u8 addr_type, bool master) { struct smp_ltk *k; list_for_each_entry(k, &hdev->long_term_keys, list) if (addr_type == k->bdaddr_type && - bacmp(bdaddr, &k->bdaddr) == 0) + bacmp(bdaddr, &k->bdaddr) == 0 && + ltk_type_master(k->type) == master) return k; return NULL; @@ -2691,8 +2704,9 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, ediv, u8 rand[8]) { struct smp_ltk *key, *old_key; + bool master = ltk_type_master(type); - old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type); + old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, master); if (old_key) key = old_key; else { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8c44bbe19add..7bb8094a3ff2 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3650,7 +3650,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) if (conn == NULL) goto not_found; - ltk = hci_find_ltk(hdev, ev->ediv, ev->random); + ltk = hci_find_ltk(hdev, ev->ediv, ev->random, conn->out); if (ltk == NULL) goto not_found; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9b1167007653..efe51ccdc615 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -699,7 +699,8 @@ static u8 smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) struct smp_ltk *key; struct hci_conn *hcon = conn->hcon; - key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type); + key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type, + hcon->out); if (!key) return 0; From 1e406eefbe41467c00973939c2b61b37bf0e1323 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 30 Jan 2014 18:22:04 -0300 Subject: [PATCH 048/139] Bluetooth: Save connection interval parameters in hci_conn This patch creates two new fields in struct hci_conn to save the minimum and maximum connection interval values used to establish the connection this object represents. This change is required in order to know what parameters the connection is currently using. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_conn.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 378e2f32cfa0..b9676cc1a59d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -334,6 +334,8 @@ struct hci_conn { __u8 passkey_entered; __u16 disc_timeout; __u16 setting; + __u16 le_conn_min_interval; + __u16 le_conn_max_interval; unsigned long flags; __u8 remote_cap; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 0266bd8e4913..7f148c975736 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -558,8 +558,8 @@ static int hci_create_le_conn(struct hci_conn *conn) bacpy(&cp.peer_addr, &conn->dst); cp.peer_addr_type = conn->dst_type; cp.own_address_type = conn->src_type; - cp.conn_interval_min = cpu_to_le16(hdev->le_conn_min_interval); - cp.conn_interval_max = cpu_to_le16(hdev->le_conn_max_interval); + cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval); + cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval); cp.supervision_timeout = __constant_cpu_to_le16(0x002a); cp.min_ce_len = __constant_cpu_to_le16(0x0000); cp.max_ce_len = __constant_cpu_to_le16(0x0000); @@ -624,6 +624,8 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, conn->sec_level = BT_SECURITY_LOW; conn->pending_sec_level = sec_level; conn->auth_type = auth_type; + conn->le_conn_min_interval = hdev->le_conn_min_interval; + conn->le_conn_max_interval = hdev->le_conn_max_interval; err = hci_create_le_conn(conn); if (err) From 5c136e90a45e3d8e050b212f8f40f2d81f096879 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 30 Jan 2014 18:22:05 -0300 Subject: [PATCH 049/139] Bluetooth: Group list_head fields from strcut hci_dev together This patch groups the list_head fields from struct hci_dev together and removes empty lines between them. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b9676cc1a59d..2e1d184bd8d3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -259,18 +259,15 @@ struct hci_dev { __u32 req_status; __u32 req_result; - struct list_head mgmt_pending; struct discovery_state discovery; struct hci_conn_hash conn_hash; + + struct list_head mgmt_pending; struct list_head blacklist; - struct list_head uuids; - struct list_head link_keys; - struct list_head long_term_keys; - struct list_head remote_oob_data; struct hci_dev_stats stat; From 9bb3c01fdb2201d405dfff8950145640b2355ec4 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 30 Jan 2014 18:22:08 -0300 Subject: [PATCH 050/139] Bluetooth: Introduce le_conn_failed() helper This patch moves connection attempt failure code to its own function so it can be reused in the next patch. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7f148c975736..7ef5bffb61aa 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -514,6 +514,21 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) } EXPORT_SYMBOL(hci_get_route); +/* This function requires the caller holds hdev->lock */ +static void le_conn_failed(struct hci_conn *conn, u8 status) +{ + struct hci_dev *hdev = conn->hdev; + + conn->state = BT_CLOSED; + + mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type, + status); + + hci_proto_connect_cfm(conn, status); + + hci_conn_del(conn); +} + static void create_le_conn_complete(struct hci_dev *hdev, u8 status) { struct hci_conn *conn; @@ -530,14 +545,7 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status) if (!conn) goto done; - conn->state = BT_CLOSED; - - mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type, - status); - - hci_proto_connect_cfm(conn, status); - - hci_conn_del(conn); + le_conn_failed(conn, status); done: hci_dev_unlock(hdev); From b1de97d8c06d9d8d38e85dc5b0cf3630372e702c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 11:55:21 -0800 Subject: [PATCH 051/139] Bluetooth: Add management setting for use of debug keys When the controller has been enabled to allow usage of debug keys, then clearly identify that in the current settings information. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/mgmt.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index e19049fb6c46..f87f5d784c3b 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -95,6 +95,7 @@ struct mgmt_rp_read_index_list { #define MGMT_SETTING_LE 0x00000200 #define MGMT_SETTING_ADVERTISING 0x00000400 #define MGMT_SETTING_SECURE_CONN 0x00000800 +#define MGMT_SETTING_DEBUG_KEYS 0x00001000 #define MGMT_OP_READ_INFO 0x0004 #define MGMT_READ_INFO_SIZE 0 diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 111b1296a2b8..91ffecd1727e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -364,6 +364,7 @@ static u32 get_supported_settings(struct hci_dev *hdev) settings |= MGMT_SETTING_POWERED; settings |= MGMT_SETTING_PAIRABLE; + settings |= MGMT_SETTING_DEBUG_KEYS; if (lmp_bredr_capable(hdev)) { settings |= MGMT_SETTING_CONNECTABLE; @@ -431,6 +432,9 @@ static u32 get_current_settings(struct hci_dev *hdev) if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) settings |= MGMT_SETTING_SECURE_CONN; + if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags)) + settings |= MGMT_SETTING_DEBUG_KEYS; + return settings; } @@ -2207,6 +2211,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, { struct mgmt_cp_load_link_keys *cp = data; u16 key_count, expected_len; + bool changed; int i; BT_DBG("request for %s", hdev->name); @@ -2246,9 +2251,12 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, hci_link_keys_clear(hdev); if (cp->debug_keys) - set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); else - clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + + if (changed) + new_settings(hdev, NULL); for (i = 0; i < key_count; i++) { struct mgmt_link_key_info *key = &cp->keys[i]; From 4e39ac81366583486b857c88656409e56befefdf Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 11:55:22 -0800 Subject: [PATCH 052/139] Bluetooth: Add management command to allow use of debug keys Originally allowing the use of debug keys was done via the Load Link Keys management command. However this is BR/EDR specific and to be flexible and allow extending this to LE as well, make this an independent command. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 2 ++ net/bluetooth/mgmt.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index f87f5d784c3b..dfab094fab73 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -387,6 +387,8 @@ struct mgmt_cp_set_scan_params { #define MGMT_OP_SET_SECURE_CONN 0x002D +#define MGMT_OP_SET_DEBUG_KEYS 0x002E + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 91ffecd1727e..70a3a7e917b7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -80,6 +80,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_SET_STATIC_ADDRESS, MGMT_OP_SET_SCAN_PARAMS, MGMT_OP_SET_SECURE_CONN, + MGMT_OP_SET_DEBUG_KEYS, }; static const u16 mgmt_events[] = { @@ -4111,6 +4112,38 @@ failed: return err; } +static int set_debug_keys(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_mode *cp = data; + bool changed; + int err; + + BT_DBG("request for %s", hdev->name); + + if (cp->val != 0x00 && cp->val != 0x01) + return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + if (cp->val) + changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + else + changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags); + + err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev); + if (err < 0) + goto unlock; + + if (changed) + err = new_settings(hdev, sk); + +unlock: + hci_dev_unlock(hdev); + return err; +} + static bool ltk_is_valid(struct mgmt_ltk_info *key) { if (key->authenticated != 0x00 && key->authenticated != 0x01) @@ -4240,6 +4273,7 @@ static const struct mgmt_handler { { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE }, { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE }, { set_secure_conn, false, MGMT_SETTING_SIZE }, + { set_debug_keys, false, MGMT_SETTING_SIZE }, }; From 626bee82b8f306baf8d37fb3f9208b861708a1a5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 11:55:23 -0800 Subject: [PATCH 053/139] Bluetooth: Remove use_debug_keys debugfs entry Since the use of debug keys can now be identified from the current settings information, this debugfs entry is no longer necessary. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d370b432aea6..7a44c8c1037a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -285,24 +285,6 @@ static const struct file_operations link_keys_fops = { .release = single_release, }; -static ssize_t use_debug_keys_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct hci_dev *hdev = file->private_data; - char buf[3]; - - buf[0] = test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) ? 'Y': 'N'; - buf[1] = '\n'; - buf[2] = '\0'; - return simple_read_from_buffer(user_buf, count, ppos, buf, 2); -} - -static const struct file_operations use_debug_keys_fops = { - .open = simple_open, - .read = use_debug_keys_read, - .llseek = default_llseek, -}; - static int dev_class_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; @@ -1494,8 +1476,6 @@ static int __hci_init(struct hci_dev *hdev) hdev, &inquiry_cache_fops); debugfs_create_file("link_keys", 0400, hdev->debugfs, hdev, &link_keys_fops); - debugfs_create_file("use_debug_keys", 0444, hdev->debugfs, - hdev, &use_debug_keys_fops); debugfs_create_file("dev_class", 0444, hdev->debugfs, hdev, &dev_class_fops); debugfs_create_file("voice_setting", 0444, hdev->debugfs, From dc8357cc72976f2fbe955e2ad4bba9e0e8ba5022 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 16:24:27 -0800 Subject: [PATCH 054/139] Bluetooth: Remove one level of indentation from hci_encrypt_change_evt The function already has an unlock label which means the one extra level on indentation is not useful and just makes the code more complex. So remove it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 51 ++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7bb8094a3ff2..62aea2edc231 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1988,35 +1988,36 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); - if (conn) { - if (!ev->status) { - if (ev->encrypt) { - /* Encryption implies authentication */ - conn->link_mode |= HCI_LM_AUTH; - conn->link_mode |= HCI_LM_ENCRYPT; - conn->sec_level = conn->pending_sec_level; - } else - conn->link_mode &= ~HCI_LM_ENCRYPT; - } + if (!conn) + goto unlock; - clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); - - if (ev->status && conn->state == BT_CONNECTED) { - hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE); - hci_conn_drop(conn); - goto unlock; - } - - if (conn->state == BT_CONFIG) { - if (!ev->status) - conn->state = BT_CONNECTED; - - hci_proto_connect_cfm(conn, ev->status); - hci_conn_drop(conn); + if (!ev->status) { + if (ev->encrypt) { + /* Encryption implies authentication */ + conn->link_mode |= HCI_LM_AUTH; + conn->link_mode |= HCI_LM_ENCRYPT; + conn->sec_level = conn->pending_sec_level; } else - hci_encrypt_cfm(conn, ev->status, ev->encrypt); + conn->link_mode &= ~HCI_LM_ENCRYPT; } + clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + + if (ev->status && conn->state == BT_CONNECTED) { + hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE); + hci_conn_drop(conn); + goto unlock; + } + + if (conn->state == BT_CONFIG) { + if (!ev->status) + conn->state = BT_CONNECTED; + + hci_proto_connect_cfm(conn, ev->status); + hci_conn_drop(conn); + } else + hci_encrypt_cfm(conn, ev->status, ev->encrypt); + unlock: hci_dev_unlock(hdev); } From abf76bad8fb503fb21fb0eba854fa048c75ff123 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 16:24:28 -0800 Subject: [PATCH 055/139] Bluetooth: Track the AES-CCM encryption status of LE and BR/EDR links When encryption for LE links has been enabled, it will always be use AES-CCM encryption. In case of BR/EDR Secure Connections, the link will also use AES-CCM encryption. In both cases track the AES-CCM status in the connection flags. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2e1d184bd8d3..6854384b1f25 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -448,6 +448,7 @@ enum { HCI_CONN_MGMT_CONNECTED, HCI_CONN_SSP_ENABLED, HCI_CONN_SC_ENABLED, + HCI_CONN_AES_CCM, HCI_CONN_POWER_SAVE, HCI_CONN_REMOTE_OOB, HCI_CONN_6LOWPAN, diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 62aea2edc231..36c9a488ac56 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1997,8 +1997,14 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->link_mode |= HCI_LM_AUTH; conn->link_mode |= HCI_LM_ENCRYPT; conn->sec_level = conn->pending_sec_level; - } else + + if ((conn->type == ACL_LINK && ev->encrypt == 0x02) || + conn->type == LE_LINK) + set_bit(HCI_CONN_AES_CCM, &conn->flags); + } else { conn->link_mode &= ~HCI_LM_ENCRYPT; + clear_bit(HCI_CONN_AES_CCM, &conn->flags); + } } clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); From f8159247755e77d8264ccce84054ff893275115e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 18:42:16 -0800 Subject: [PATCH 056/139] Bluetooth: Remove check for valid LTK authenticated parameter The LTK authenticated parameter is the key type of the LTK and similar to link keys there is no need to check the currently supported values. For possible future improvements, the kernel will only use key types it knows about and just ignore all the other ones. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 70a3a7e917b7..8030eeb44382 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4146,8 +4146,6 @@ unlock: static bool ltk_is_valid(struct mgmt_ltk_info *key) { - if (key->authenticated != 0x00 && key->authenticated != 0x01) - return false; if (key->master != 0x00 && key->master != 0x01) return false; if (!bdaddr_type_is_le(key->addr.type)) From d40f3eef0b9b70d15d5fd0031c0633d4a9ed78cd Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 18:42:17 -0800 Subject: [PATCH 057/139] Bluetooth: Rename authentication to key_type in mgmt_ltk_info The field is not a boolean, it is actually a field for a key type. So name it properly. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 2 +- net/bluetooth/mgmt.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index dfab094fab73..4303fa90b7c1 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -182,7 +182,7 @@ struct mgmt_cp_load_link_keys { struct mgmt_ltk_info { struct mgmt_addr_info addr; - __u8 authenticated; + __u8 type; __u8 master; __u8 enc_size; __le16 ediv; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8030eeb44382..8c94841072a8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4207,7 +4207,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, type = HCI_SMP_LTK_SLAVE; hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, - type, 0, key->authenticated, key->val, + type, 0, key->type, key->val, key->enc_size, key->ediv, key->rand); } @@ -4648,7 +4648,7 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) ev.store_hint = persistent; bacpy(&ev.key.addr.bdaddr, &key->bdaddr); ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type); - ev.key.authenticated = key->authenticated; + ev.key.type = key->authenticated; ev.key.enc_size = key->enc_size; ev.key.ediv = key->ediv; From 03c515d7486b7a519728340d4b04baaad16bf806 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 18:42:18 -0800 Subject: [PATCH 058/139] Bluetooth: Remove __packed from struct smp_ltk The struct smp_ltk does not need to be packed and so remove __packed. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6854384b1f25..4e878780fa01 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -101,7 +101,7 @@ struct smp_ltk { __le16 ediv; u8 rand[8]; u8 val[16]; -} __packed; +}; struct link_key { struct list_head list; From 0ab04a9c0e8e37ca495fb08c8b83615c5f144551 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 1 Feb 2014 09:19:57 -0800 Subject: [PATCH 059/139] Bluetooth: Add management command for Secure Connection Only Mode With support for Secure Connections it is possible to switch the controller into a mode that is called Secure Connections Only. In this mode only security level 4 connections are allowed (with the exception of security level 0 approved services). This patch just introduces the management command and setting of the right internal flags to enable this mode. It does not yet enforce it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8c94841072a8..ce7ef339b1c4 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4043,7 +4043,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, { struct mgmt_mode *cp = data; struct pending_cmd *cmd; - u8 status; + u8 val, status; int err; BT_DBG("request for %s", hdev->name); @@ -4058,7 +4058,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, MGMT_STATUS_NOT_SUPPORTED); - if (cp->val != 0x00 && cp->val != 0x01) + if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02) return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, MGMT_STATUS_INVALID_PARAMS); @@ -4067,12 +4067,18 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { bool changed; - if (cp->val) + if (cp->val) { changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags); - else + if (cp->val == 0x02) + set_bit(HCI_SC_ONLY, &hdev->dev_flags); + else + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + } else { changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags); + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + } err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev); if (err < 0) @@ -4090,7 +4096,10 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, goto failed; } - if (!!cp->val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { + val = !!cp->val; + + if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags) && + (cp->val == 0x02) == test_bit(HCI_SC_ONLY, &hdev->dev_flags)) { err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev); goto failed; } @@ -4101,12 +4110,17 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, goto failed; } - err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &cp->val); + err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val); if (err < 0) { mgmt_pending_remove(cmd); goto failed; } + if (cp->val == 0x02) + set_bit(HCI_SC_ONLY, &hdev->dev_flags); + else + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + failed: hci_dev_unlock(hdev); return err; @@ -5063,19 +5077,24 @@ void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) if (status) { u8 mgmt_err = mgmt_status(status); - if (enable && test_and_clear_bit(HCI_SC_ENABLED, - &hdev->dev_flags)) - new_settings(hdev, NULL); + if (enable) { + if (test_and_clear_bit(HCI_SC_ENABLED, + &hdev->dev_flags)) + new_settings(hdev, NULL); + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + } mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev, cmd_status_rsp, &mgmt_err); return; } - if (enable) + if (enable) { changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags); - else + } else { changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags); + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + } mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev, settings_rsp, &match); From 9cb2e030e6a0787f5c216702e6e78dd85ffe04c4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 1 Feb 2014 11:32:25 -0800 Subject: [PATCH 060/139] Bluetooth: Include security level 4 in connections check This check is only used for RFCOMM connections and most likely no RFCOMM based profile will require security level 4 secure connection security policy. In case it ever does make sure that seucrity level 4 is treated as sufficient security level. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7ef5bffb61aa..801820f12226 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -860,13 +860,17 @@ int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level) { BT_DBG("hcon %p", conn); - if (sec_level != BT_SECURITY_HIGH) - return 1; /* Accept if non-secure is required */ - - if (conn->sec_level == BT_SECURITY_HIGH) + /* Accept if non-secure or higher security level is required */ + if (sec_level != BT_SECURITY_HIGH && sec_level != BT_SECURITY_FIPS) return 1; - return 0; /* Reject not secure link */ + /* Accept if secure or higher security level is already present */ + if (conn->sec_level == BT_SECURITY_HIGH || + conn->sec_level == BT_SECURITY_FIPS) + return 1; + + /* Reject not secure link */ + return 0; } EXPORT_SYMBOL(hci_conn_check_secure); From 914a6ffe42259267239a23d4f23ef06b0a0369a4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 1 Feb 2014 11:52:02 -0800 Subject: [PATCH 061/139] Bluetooth: Track if link is using P-256 authenticated combination key When the ACL link is using P-256 authenticated combination key, mark the link mode as HCI_LM_FIPS. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 36c9a488ac56..d2c6878a9d6a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1998,6 +1998,10 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->link_mode |= HCI_LM_ENCRYPT; conn->sec_level = conn->pending_sec_level; + /* P-256 authentication key implies FIPS */ + if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256) + conn->link_mode |= HCI_LM_FIPS; + if ((conn->type == ACL_LINK && ev->encrypt == 0x02) || conn->type == LE_LINK) set_bit(HCI_CONN_AES_CCM, &conn->flags); From 424ef94311512ef48a5464d173ef83862e4653cb Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 31 Jan 2014 19:02:30 -0800 Subject: [PATCH 062/139] Bluetooth: Add constants for LTK key types The LTK key types available right now are unauthenticated and authenticated ones. Provide two simple constants for it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 232c07804ca8..352d3d7d06bb 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -346,6 +346,10 @@ enum { #define HCI_SMP_LTK 0x82 #define HCI_SMP_LTK_SLAVE 0x83 +/* Long Term Key types */ +#define HCI_LTK_UNAUTH 0x00 +#define HCI_LTK_AUTH 0x01 + /* ---- HCI Error Codes ---- */ #define HCI_ERROR_AUTH_FAILURE 0x05 #define HCI_ERROR_CONNECTION_TIMEOUT 0x08 From 15819a7065ac46eb804498bb7ccbba60d8f7d4d5 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 3 Feb 2014 13:56:18 -0300 Subject: [PATCH 063/139] Bluetooth: Introduce connection parameters list This patch adds to hdev the connection parameters list (hdev->le_ conn_params). The elements from this list (struct hci_conn_params) contains the connection parameters (for now, minimum and maximum connection interval) that should be used during the connection establishment. Moreover, this patch adds helper functions to manipulate hdev->le_ conn_params list. Some of these functions are also declared in hci_core.h since they will be used outside hci_core.c in upcoming patches. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 18 ++++++++ net/bluetooth/hci_core.c | 77 ++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4e878780fa01..92fa75fce29d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -269,6 +269,7 @@ struct hci_dev { struct list_head link_keys; struct list_head long_term_keys; struct list_head remote_oob_data; + struct list_head le_conn_params; struct hci_dev_stats stat; @@ -373,6 +374,16 @@ struct hci_chan { __u8 state; }; +struct hci_conn_params { + struct list_head list; + + bdaddr_t addr; + u8 addr_type; + + u16 conn_min_interval; + u16 conn_max_interval; +}; + extern struct list_head hci_dev_list; extern struct list_head hci_cb_list; extern rwlock_t hci_dev_list_lock; @@ -751,6 +762,13 @@ int hci_blacklist_clear(struct hci_dev *hdev); int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); +struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, + bdaddr_t *addr, u8 addr_type); +void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, + u16 conn_min_interval, u16 conn_max_interval); +void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); +void hci_conn_params_clear(struct hci_dev *hdev); + int hci_uuids_clear(struct hci_dev *hdev); int hci_link_keys_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7a44c8c1037a..e7746690d620 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2924,6 +2924,81 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) return mgmt_device_unblocked(hdev, bdaddr, type); } +/* This function requires the caller holds hdev->lock */ +struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, + bdaddr_t *addr, u8 addr_type) +{ + struct hci_conn_params *params; + + list_for_each_entry(params, &hdev->le_conn_params, list) { + if (bacmp(¶ms->addr, addr) == 0 && + params->addr_type == addr_type) { + return params; + } + } + + return NULL; +} + +/* This function requires the caller holds hdev->lock */ +void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, + u16 conn_min_interval, u16 conn_max_interval) +{ + struct hci_conn_params *params; + + params = hci_conn_params_lookup(hdev, addr, addr_type); + if (params) { + params->conn_min_interval = conn_min_interval; + params->conn_max_interval = conn_max_interval; + return; + } + + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + BT_ERR("Out of memory"); + return; + } + + bacpy(¶ms->addr, addr); + params->addr_type = addr_type; + params->conn_min_interval = conn_min_interval; + params->conn_max_interval = conn_max_interval; + + list_add(¶ms->list, &hdev->le_conn_params); + + BT_DBG("addr %pMR (type %u) conn_min_interval 0x%.4x " + "conn_max_interval 0x%.4x", addr, addr_type, conn_min_interval, + conn_max_interval); +} + +/* This function requires the caller holds hdev->lock */ +void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) +{ + struct hci_conn_params *params; + + params = hci_conn_params_lookup(hdev, addr, addr_type); + if (!params) + return; + + list_del(¶ms->list); + kfree(params); + + BT_DBG("addr %pMR (type %u)", addr, addr_type); +} + +/* This function requires the caller holds hdev->lock */ +void hci_conn_params_clear(struct hci_dev *hdev) +{ + struct hci_conn_params *params, *tmp; + + list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { + list_del(¶ms->list); + kfree(params); + } + + BT_DBG("All LE connection parameters were removed"); +} + static void inquiry_complete(struct hci_dev *hdev, u8 status) { if (status) { @@ -3034,6 +3109,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->link_keys); INIT_LIST_HEAD(&hdev->long_term_keys); INIT_LIST_HEAD(&hdev->remote_oob_data); + INIT_LIST_HEAD(&hdev->le_conn_params); INIT_LIST_HEAD(&hdev->conn_hash.list); INIT_WORK(&hdev->rx_work, hci_rx_work); @@ -3219,6 +3295,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_link_keys_clear(hdev); hci_smp_ltks_clear(hdev); hci_remote_oob_data_clear(hdev); + hci_conn_params_clear(hdev); hci_dev_unlock(hdev); hci_dev_put(hdev); From 4292f1f3370193fd3f2e4f849211fd9596ce832f Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 3 Feb 2014 13:56:19 -0300 Subject: [PATCH 064/139] Bluetooth: Use connection parameters if any This patch changes hci_connect_le() so it uses the connection parameters specified for the certain device. If no parameters were configured, we use the default values. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 801820f12226..67972928a623 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -586,6 +586,7 @@ static int hci_create_le_conn(struct hci_conn *conn) static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, u8 auth_type) { + struct hci_conn_params *params; struct hci_conn *conn; int err; @@ -632,8 +633,15 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, conn->sec_level = BT_SECURITY_LOW; conn->pending_sec_level = sec_level; conn->auth_type = auth_type; - conn->le_conn_min_interval = hdev->le_conn_min_interval; - conn->le_conn_max_interval = hdev->le_conn_max_interval; + + params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); + if (params) { + conn->le_conn_min_interval = params->conn_min_interval; + conn->le_conn_max_interval = params->conn_max_interval; + } else { + conn->le_conn_min_interval = hdev->le_conn_min_interval; + conn->le_conn_max_interval = hdev->le_conn_max_interval; + } err = hci_create_le_conn(conn); if (err) From 9b7655eafeeec9e74e97e9056e820ede8d18093e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 14 Feb 2014 07:40:51 +0200 Subject: [PATCH 065/139] Bluetooth: Enable LE L2CAP CoC support by default Now that the LE L2CAP Connection Oriented Channel support has undergone a decent amount of testing we can make it officially supported. This patch removes the enable_lecoc module parameter which was previously needed to enable support for LE L2CAP CoC. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap_core.c | 11 ----------- net/bluetooth/l2cap_sock.c | 29 ----------------------------- 3 files changed, 41 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index ae482f41594a..13bec91785f4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -857,7 +857,6 @@ static inline long l2cap_chan_no_get_sndtimeo(struct l2cap_chan *chan) } extern bool disable_ertm; -extern bool enable_lecoc; int l2cap_init_sockets(void); void l2cap_cleanup_sockets(void); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 66fbac91eaed..6e6b3a9c8e6d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5544,17 +5544,6 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, { int err = 0; - if (!enable_lecoc) { - switch (cmd->code) { - case L2CAP_LE_CONN_REQ: - case L2CAP_LE_CONN_RSP: - case L2CAP_LE_CREDITS: - case L2CAP_DISCONN_REQ: - case L2CAP_DISCONN_RSP: - return -EINVAL; - } - } - switch (cmd->code) { case L2CAP_COMMAND_REJ: l2cap_le_command_rej(conn, cmd, cmd_len, data); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 27d3d6d48b6e..b247f9d27fed 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -36,8 +36,6 @@ #include "smp.h" -bool enable_lecoc; - static struct bt_sock_list l2cap_sk_list = { .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) }; @@ -111,8 +109,6 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) } if (bdaddr_type_is_le(la.l2_bdaddr_type)) { - if (!enable_lecoc && la.l2_psm) - return -EINVAL; /* We only allow ATT user space socket */ if (la.l2_cid && la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) @@ -229,8 +225,6 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, return -EINVAL; if (bdaddr_type_is_le(la.l2_bdaddr_type)) { - if (!enable_lecoc && la.l2_psm) - return -EINVAL; /* We only allow ATT user space socket */ if (la.l2_cid && la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT)) @@ -578,11 +572,6 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, break; case BT_SNDMTU: - if (!enable_lecoc) { - err = -EPROTONOSUPPORT; - break; - } - if (!bdaddr_type_is_le(chan->src_type)) { err = -EINVAL; break; @@ -598,11 +587,6 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, break; case BT_RCVMTU: - if (!enable_lecoc) { - err = -EPROTONOSUPPORT; - break; - } - if (!bdaddr_type_is_le(chan->src_type)) { err = -EINVAL; break; @@ -919,11 +903,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, break; case BT_SNDMTU: - if (!enable_lecoc) { - err = -EPROTONOSUPPORT; - break; - } - if (!bdaddr_type_is_le(chan->src_type)) { err = -EINVAL; break; @@ -936,11 +915,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, break; case BT_RCVMTU: - if (!enable_lecoc) { - err = -EPROTONOSUPPORT; - break; - } - if (!bdaddr_type_is_le(chan->src_type)) { err = -EINVAL; break; @@ -1643,6 +1617,3 @@ void l2cap_cleanup_sockets(void) bt_sock_unregister(BTPROTO_L2CAP); proto_unregister(&l2cap_proto); } - -module_param(enable_lecoc, bool, 0644); -MODULE_PARM_DESC(enable_lecoc, "Enable support for LE CoC"); From 7f717b91dd68db1fa01d396d03997ed1b748659f Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:01 -0500 Subject: [PATCH 066/139] Revert "Bluetooth: Remove rfcomm_carrier_raised()" This reverts commit f86772af6a0f643d3e13eb3f4f9213ae0c333ee4. This is the first of a 3-patch revert, together with Revert "Bluetooth: Always wait for a connection on RFCOMM open()" and Revert "Bluetooth: Move rfcomm_get_device() before rfcomm_dev_activate()". Commit 4a2fb3ecc7467c775b154813861f25a0ddc11aa0, "Bluetooth: Always wait for a connection on RFCOMM open()" open-codes blocking on tty open(), rather than using the default behavior implemented by the tty port. The reasons for reverting that patch are detailed in that changelog; this patch restores required functionality for that revert. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index f9c0980abeea..aeabadeef82b 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -160,6 +160,14 @@ static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty) return err; } +/* we block the open until the dlc->state becomes BT_CONNECTED */ +static int rfcomm_dev_carrier_raised(struct tty_port *port) +{ + struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); + + return (dev->dlc->state == BT_CONNECTED); +} + /* device-specific cleanup: close the dlc */ static void rfcomm_dev_shutdown(struct tty_port *port) { From 136c373bf0e8c445fc028427674817333df602e3 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:02 -0500 Subject: [PATCH 067/139] Revert "Bluetooth: Always wait for a connection on RFCOMM open()" This reverts commit 4a2fb3ecc7467c775b154813861f25a0ddc11aa0. This is the second of a 3-patch revert, together with Revert "Bluetooth: Remove rfcomm_carrier_raised()" and Revert "Bluetooth: Move rfcomm_get_device() before rfcomm_dev_activate()". Before commit cad348a17e170451ea8688b532a6ca3e98c63b60, Bluetooth: Implement .activate, .shutdown and .carrier_raised methods, tty_port_block_til_ready() was open-coded in rfcomm_tty_install() as part of the RFCOMM tty open(). Unfortunately, it did not implement non-blocking open nor CLOCAL open, but rather always blocked for carrier. This is not the expected or typical behavior for ttys, and prevents several common terminal programming idioms from working (eg., opening in non-blocking mode to initialize desired termios settings then re-opening for connection). Commit cad348a17e170451ea8688b532a6ca3e98c63b60, Bluetooth: Implement .activate, .shutdown and .carrier_raised methods, added the necessary tty_port methods to use the default tty_port_open(). However, this triggered two important user-space regressions. The first regression involves the complicated mechanism for reparenting the rfcomm tty device to the ACL link device which represents an open link to a specific bluetooth host. This regression causes ModemManager to conclude the rfcomm tty device does not front a modem so it makes no attempt to initialize an attached modem. This regression is caused by the lack of a device_move() if the dlc is already open (and not specifically related to the open-coded block_til_ready()). A more appropriate solution is submitted in "Bluetooth: Fix unsafe RFCOMM device parenting" and "Bluetooth: Fix RFCOMM parent device for reused dlc" The second regression involves "rfcomm bind" and wvdial (a ppp dialer). rfcomm bind creates a device node for a /dev/rfcomm. wvdial opens that device in non-blocking mode (because it expects the connection to have already been established). In addition, subsequent writes to the rfcomm tty device fail (because the link is not yet connected; rfcomm connection begins with the actual tty open()). However, restoring the original behavior (in the patch which this reverts) was undesirable. Firstly, the original reporter notes that a trivial userspace "workaround" already exists: rfcomm connect, which creates the device node and establishes the expected connection. Secondly, the failed writes occur because the rfcomm tty driver does not buffer writes to an unconnected device; this contrasts with the dozen of other tty drivers (in fact, all of them) that do just that. The submitted patch "Bluetooth: Don't fail RFCOMM tty writes" corrects this. Thirdly, it was a long-standing bug to block on non-blocking open, which is re-fixed by revert. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 46 +++++++------------------------------- 1 file changed, 8 insertions(+), 38 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index aeabadeef82b..32ef9f91965c 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -58,7 +58,6 @@ struct rfcomm_dev { uint modem_status; struct rfcomm_dlc *dlc; - wait_queue_head_t conn_wait; struct device *tty_dev; @@ -124,40 +123,8 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev) static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty) { struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); - DEFINE_WAIT(wait); - int err; - err = rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel); - if (err) - return err; - - while (1) { - prepare_to_wait(&dev->conn_wait, &wait, TASK_INTERRUPTIBLE); - - if (dev->dlc->state == BT_CLOSED) { - err = -dev->err; - break; - } - - if (dev->dlc->state == BT_CONNECTED) - break; - - if (signal_pending(current)) { - err = -ERESTARTSYS; - break; - } - - tty_unlock(tty); - schedule(); - tty_lock(tty); - } - finish_wait(&dev->conn_wait, &wait); - - if (!err) - device_move(dev->tty_dev, rfcomm_get_device(dev), - DPM_ORDER_DEV_AFTER_PARENT); - - return err; + return rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel); } /* we block the open until the dlc->state becomes BT_CONNECTED */ @@ -184,6 +151,7 @@ static const struct tty_port_operations rfcomm_port_ops = { .destruct = rfcomm_dev_destruct, .activate = rfcomm_dev_activate, .shutdown = rfcomm_dev_shutdown, + .carrier_raised = rfcomm_dev_carrier_raised, }; static struct rfcomm_dev *__rfcomm_dev_get(int id) @@ -290,7 +258,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) tty_port_init(&dev->port); dev->port.ops = &rfcomm_port_ops; - init_waitqueue_head(&dev->conn_wait); skb_queue_head_init(&dev->pending); @@ -609,9 +576,12 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) BT_DBG("dlc %p dev %p err %d", dlc, dev, err); dev->err = err; - wake_up_interruptible(&dev->conn_wait); + if (dlc->state == BT_CONNECTED) { + device_move(dev->tty_dev, rfcomm_get_device(dev), + DPM_ORDER_DEV_AFTER_PARENT); - if (dlc->state == BT_CLOSED) + wake_up_interruptible(&dev->port.open_wait); + } else if (dlc->state == BT_CLOSED) tty_port_tty_hangup(&dev->port, false); } @@ -1133,7 +1103,7 @@ int __init rfcomm_init_ttys(void) rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL; rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; rfcomm_tty_driver->init_termios = tty_std_termios; - rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON; tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); From f87c24e74e88d767e7024c4464d0d1fb3642fb5e Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:03 -0500 Subject: [PATCH 068/139] Revert "Bluetooth: Move rfcomm_get_device() before rfcomm_dev_activate()" This reverts commit e228b63390536f5b737056059a9a04ea016b1abf. This is the third of a 3-patch revert, together with Revert "Bluetooth: Remove rfcomm_carrier_raised()" and Revert "Bluetooth: Always wait for a connection on RFCOMM open()". Commit 4a2fb3ecc7467c775b154813861f25a0ddc11aa0, "Bluetooth: Always wait for a connection on RFCOMM open()" open-codes blocking on tty open(), rather than using the default behavior implemented by the tty port. The reasons for reverting that patch are detailed in that changelog; this patch restores required functionality for that revert. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 32ef9f91965c..a535ef148ef6 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -103,22 +103,6 @@ static void rfcomm_dev_destruct(struct tty_port *port) module_put(THIS_MODULE); } -static struct device *rfcomm_get_device(struct rfcomm_dev *dev) -{ - struct hci_dev *hdev; - struct hci_conn *conn; - - hdev = hci_get_route(&dev->dst, &dev->src); - if (!hdev) - return NULL; - - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst); - - hci_dev_put(hdev); - - return conn ? &conn->dev : NULL; -} - /* device-specific initialization: open the dlc */ static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty) { @@ -185,6 +169,22 @@ static struct rfcomm_dev *rfcomm_dev_get(int id) return dev; } +static struct device *rfcomm_get_device(struct rfcomm_dev *dev) +{ + struct hci_dev *hdev; + struct hci_conn *conn; + + hdev = hci_get_route(&dev->dst, &dev->src); + if (!hdev) + return NULL; + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst); + + hci_dev_put(hdev); + + return conn ? &conn->dev : NULL; +} + static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf) { struct rfcomm_dev *dev = dev_get_drvdata(tty_dev); From c0fdfb80382e4901473ce0e31d1e7833c1d297be Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:04 -0500 Subject: [PATCH 069/139] tty: Fix ref counting for port krefs The tty core supports two models for handling tty_port lifetimes; the tty_port can use the kref supplied by tty_port (which will automatically destruct the tty_port when the ref count drops to zero) or it can destruct the tty_port manually. For tty drivers that choose to use the port kref to manage the tty_port lifetime, it is not possible to safely acquire a port reference conditionally. If the last reference is released after evaluating the condition but before acquiring the reference, a bogus reference will be held while the tty_port destruction commences. Rather, only acquire a port reference if the ref count is non-zero and allow the caller to distinguish if a reference has successfully been acquired. Cc: Jiri Slaby Signed-off-by: Peter Hurley Acked-by: Greg Kroah-Hartman Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- include/linux/tty.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/tty.h b/include/linux/tty.h index 90b4fdc8a61f..4781d7b27dd3 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -518,9 +518,9 @@ extern void tty_port_put(struct tty_port *port); static inline struct tty_port *tty_port_get(struct tty_port *port) { - if (port) - kref_get(&port->kref); - return port; + if (port && kref_get_unless_zero(&port->kref)) + return port; + return NULL; } /* If the cts flow control is enabled, return true. */ From 082a1532fc7607727f759c069eb8dd9fa5ae3f37 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:05 -0500 Subject: [PATCH 070/139] Bluetooth: Fix racy acquire of rfcomm_dev reference rfcomm_dev_get() can return a rfcomm_dev reference for a device for which destruction may be commencing. This can happen on tty destruction, which calls rfcomm_tty_cleanup(), the last port reference may have been released but RFCOMM_TTY_RELEASED was not set. The following race is also possible: CPU 0 | CPU 1 | rfcomm_release_dev rfcomm_dev_get | . spin_lock | . dev = __rfcomm_dev_get | . if dev | . if test_bit(TTY_RELEASED) | . | !test_and_set_bit(TTY_RELEASED) | tty_port_put <<<< last reference else | tty_port_get | The reference acquire is bogus because destruction will commence with the release of the last reference. Ignore the external state change of TTY_RELEASED and instead rely on the reference acquire itself to determine if the reference is valid. Cc: Jiri Slaby Cc: Greg Kroah-Hartman Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index a535ef148ef6..7cf193f0eea7 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -157,12 +157,8 @@ static struct rfcomm_dev *rfcomm_dev_get(int id) dev = __rfcomm_dev_get(id); - if (dev) { - if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) - dev = NULL; - else - tty_port_get(&dev->port); - } + if (dev && !tty_port_get(&dev->port)) + dev = NULL; spin_unlock(&rfcomm_dev_lock); From 960603a54aa0d5f4f1c4f1037bcaee571d03cb1e Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:06 -0500 Subject: [PATCH 071/139] Bluetooth: Exclude released devices from RFCOMMGETDEVLIST ioctl When enumerating RFCOMM devices in the rfcomm_dev_list, holding the rfcomm_dev_lock only guarantees the existence of the enumerated rfcomm_dev in memory, and not safe access to its state. Testing the device state (such as RFCOMM_TTY_RELEASED) does not guarantee the device will remain in that state for the subsequent access to the rfcomm_dev's fields, nor guarantee that teardown has not commenced. Obtain an rfcomm_dev reference for the duration of rfcomm_dev access. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 7cf193f0eea7..b385d9985656 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -468,7 +468,7 @@ static int rfcomm_get_dev_list(void __user *arg) spin_lock(&rfcomm_dev_lock); list_for_each_entry(dev, &rfcomm_dev_list, list) { - if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) + if (!tty_port_get(&dev->port)) continue; (di + n)->id = dev->id; (di + n)->flags = dev->flags; @@ -476,6 +476,7 @@ static int rfcomm_get_dev_list(void __user *arg) (di + n)->channel = dev->channel; bacpy(&(di + n)->src, &dev->src); bacpy(&(di + n)->dst, &dev->dst); + tty_port_put(&dev->port); if (++n >= dev_num) break; } From 1c64834e0624c61735308138e67cc3b527f41621 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:07 -0500 Subject: [PATCH 072/139] Bluetooth: Release rfcomm_dev only once No logic prevents an rfcomm_dev from being released multiple times. For example, if the rfcomm_dev ref count is large due to pending tx, then multiple RFCOMMRELEASEDEV ioctls may mistakenly release the rfcomm_dev too many times. Note that concurrent ioctls are not required to create this condition. Introduce RFCOMM_DEV_RELEASED status bit which guarantees the rfcomm_dev can only be released once. NB: Since the flags are exported to userspace, introduce the status field to track state for which userspace should not be aware. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- include/net/bluetooth/rfcomm.h | 6 +++++- net/bluetooth/rfcomm/tty.c | 11 +++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index c312cfc4e922..b9759eb17cdd 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -324,11 +324,15 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, #define RFCOMMGETDEVINFO _IOR('R', 211, int) #define RFCOMMSTEALDLC _IOW('R', 220, int) +/* rfcomm_dev.flags bit definitions */ #define RFCOMM_REUSE_DLC 0 #define RFCOMM_RELEASE_ONHUP 1 #define RFCOMM_HANGUP_NOW 2 #define RFCOMM_TTY_ATTACHED 3 -#define RFCOMM_TTY_RELEASED 4 +#define RFCOMM_DEFUNCT_BIT4 4 /* don't reuse this bit - userspace visible */ + +/* rfcomm_dev.status bit definitions */ +#define RFCOMM_DEV_RELEASED 0 struct rfcomm_dev_req { s16 dev_id; diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index b385d9985656..d9d4bc89e638 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -51,6 +51,8 @@ struct rfcomm_dev { unsigned long flags; int err; + unsigned long status; /* don't export to userspace */ + bdaddr_t src; bdaddr_t dst; u8 channel; @@ -423,6 +425,12 @@ static int rfcomm_release_dev(void __user *arg) return -EPERM; } + /* only release once */ + if (test_and_set_bit(RFCOMM_DEV_RELEASED, &dev->status)) { + tty_port_put(&dev->port); + return -EALREADY; + } + if (req.flags & (1 << RFCOMM_HANGUP_NOW)) rfcomm_dlc_close(dev->dlc, 0); @@ -433,8 +441,7 @@ static int rfcomm_release_dev(void __user *arg) tty_kref_put(tty); } - if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) && - !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags)) + if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) tty_port_put(&dev->port); tty_port_put(&dev->port); From 80ea73378af46b0023eb2f400d26c2a60248ffaa Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:08 -0500 Subject: [PATCH 073/139] Bluetooth: Fix unreleased rfcomm_dev reference When RFCOMM_RELEASE_ONHUP is set, the rfcomm tty driver 'takes over' the initial rfcomm_dev reference created by the RFCOMMCREATEDEV ioctl. The assumption is that the rfcomm tty driver will release the rfcomm_dev reference when the tty is freed (in rfcomm_tty_cleanup()). However, if the tty is never opened, the 'take over' never occurs, so when RFCOMMRELEASEDEV ioctl is called, the reference is not released. Track the state of the reference 'take over' so that the release is guaranteed by either the RFCOMMRELEASEDEV ioctl or the rfcomm tty driver. Note that the synchronous hangup in rfcomm_release_dev() ensures that rfcomm_tty_install() cannot race with the RFCOMMRELEASEDEV ioctl. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- include/net/bluetooth/rfcomm.h | 1 + net/bluetooth/rfcomm/tty.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index b9759eb17cdd..0d69936831fa 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -333,6 +333,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, /* rfcomm_dev.status bit definitions */ #define RFCOMM_DEV_RELEASED 0 +#define RFCOMM_TTY_OWNED 1 struct rfcomm_dev_req { s16 dev_id; diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index d9d4bc89e638..bb570d95adca 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -441,7 +441,7 @@ static int rfcomm_release_dev(void __user *arg) tty_kref_put(tty); } - if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) + if (!test_bit(RFCOMM_TTY_OWNED, &dev->status)) tty_port_put(&dev->port); tty_port_put(&dev->port); @@ -685,8 +685,10 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty) * when the last process closes the tty. The behaviour is expected by * userspace. */ - if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) + if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { + set_bit(RFCOMM_TTY_OWNED, &dev->status); tty_port_put(&dev->port); + } return 0; } From c949c224cfd7d5445ef947e8b93c0657323d5be5 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:09 -0500 Subject: [PATCH 074/139] Bluetooth: Fix RFCOMM tty teardown race RFCOMM tty device teardown can race with new tty device registration for the same device id: CPU 0 | CPU 1 rfcomm_dev_add | rfcomm_dev_destruct | spin_lock | list_del <== dev_id no longer used | spin_unlock spin_lock | . [search rfcomm_dev_list] | . [dev_id not in use] | . [initialize new rfcomm_dev] | . spin_unlock | . | . tty_port_register_device | tty_unregister_device Don't remove rfcomm_dev from the device list until after tty device unregistration has completed. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index bb570d95adca..6ea08b05b53a 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -84,10 +84,6 @@ static void rfcomm_dev_destruct(struct tty_port *port) BT_DBG("dev %p dlc %p", dev, dlc); - spin_lock(&rfcomm_dev_lock); - list_del(&dev->list); - spin_unlock(&rfcomm_dev_lock); - rfcomm_dlc_lock(dlc); /* Detach DLC if it's owned by this dev */ if (dlc->owner == dev) @@ -98,6 +94,10 @@ static void rfcomm_dev_destruct(struct tty_port *port) tty_unregister_device(rfcomm_tty_driver, dev->id); + spin_lock(&rfcomm_dev_lock); + list_del(&dev->list); + spin_unlock(&rfcomm_dev_lock); + kfree(dev); /* It's safe to call module_put() here because socket still From c10a848cea89a8f0418fa0efec33c4e8507aab4b Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:10 -0500 Subject: [PATCH 075/139] Bluetooth: Verify dlci not in use before rfcomm_dev create Only one session/channel combination may be in use at any one time. However, the failure does not occur until the tty is opened (in rfcomm_dlc_open()). Because these settings are actually bound at rfcomm device creation (via RFCOMMCREATEDEV ioctl), validate and fail before creating the rfcomm tty device. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- include/net/bluetooth/rfcomm.h | 1 + net/bluetooth/rfcomm/core.c | 26 +++++++++++++++++++++++++- net/bluetooth/rfcomm/tty.c | 8 ++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index 0d69936831fa..f8262a2783ec 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -241,6 +241,7 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb); int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig); int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); void rfcomm_dlc_accept(struct rfcomm_dlc *d); +struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel); #define rfcomm_dlc_lock(d) spin_lock(&d->lock) #define rfcomm_dlc_unlock(d) spin_unlock(&d->lock) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index ba115d472f7b..b378bbb6f8a7 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -360,6 +360,11 @@ static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci) return NULL; } +static int rfcomm_check_channel(u8 channel) +{ + return channel < 1 || channel > 30; +} + static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel) { struct rfcomm_session *s; @@ -369,7 +374,7 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, BT_DBG("dlc %p state %ld %pMR -> %pMR channel %d", d, d->state, src, dst, channel); - if (channel < 1 || channel > 30) + if (rfcomm_check_channel(channel)) return -EINVAL; if (d->state != BT_OPEN && d->state != BT_CLOSED) @@ -514,6 +519,25 @@ no_session: return r; } +struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel) +{ + struct rfcomm_session *s; + struct rfcomm_dlc *dlc = NULL; + u8 dlci; + + if (rfcomm_check_channel(channel)) + return ERR_PTR(-EINVAL); + + rfcomm_lock(); + s = rfcomm_session_get(src, dst); + if (s) { + dlci = __dlci(!s->initiator, channel); + dlc = rfcomm_dlc_get(s, dlci); + } + rfcomm_unlock(); + return dlc; +} + int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb) { int len = skb->len; diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 6ea08b05b53a..a58d693e1e61 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -385,6 +385,14 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg) dlc = rfcomm_pi(sk)->dlc; rfcomm_dlc_hold(dlc); } else { + /* Validate the channel is unused */ + dlc = rfcomm_dlc_exists(&req.src, &req.dst, req.channel); + if (IS_ERR(dlc)) + return PTR_ERR(dlc); + else if (dlc) { + rfcomm_dlc_put(dlc); + return -EBUSY; + } dlc = rfcomm_dlc_alloc(GFP_KERNEL); if (!dlc) return -ENOMEM; From 4339c25afb0d49878fba5a989618ffe807aa46cd Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:11 -0500 Subject: [PATCH 076/139] Bluetooth: Simplify RFCOMM session state eval Merge conditional test for BT_LISTEN session state into following switch statement (which is functionally equivalent). Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index b378bbb6f8a7..e8898624cbaf 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1968,12 +1968,11 @@ static void rfcomm_process_sessions(void) continue; } - if (s->state == BT_LISTEN) { + switch (s->state) { + case BT_LISTEN: rfcomm_accept_connection(s); continue; - } - switch (s->state) { case BT_BOUND: s = rfcomm_check_connection(s); break; From 5998e04063563ff2ffc779510f072ff0ff94163b Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:12 -0500 Subject: [PATCH 077/139] Bluetooth: Refactor deferred setup test in rfcomm_dlc_close() Prepare for directly closing dlc if the RFCOMM session has not yet been started; refactor the deferred setup test for only those dlc states to which the test applies. Retains functional equivalence. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/core.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index e8898624cbaf..3ce5ae493d1d 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -443,11 +443,18 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) switch (d->state) { case BT_CONNECT: case BT_CONFIG: + case BT_OPEN: + case BT_CONNECT2: if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) { set_bit(RFCOMM_AUTH_REJECT, &d->flags); rfcomm_schedule(); - break; + return 0; } + } + + switch (d->state) { + case BT_CONNECT: + case BT_CONFIG: /* Fall through */ case BT_CONNECTED: @@ -461,15 +468,6 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) } break; - case BT_OPEN: - case BT_CONNECT2: - if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) { - set_bit(RFCOMM_AUTH_REJECT, &d->flags); - rfcomm_schedule(); - break; - } - /* Fall through */ - default: rfcomm_dlc_clear_timer(d); From f622357a5e83e3a812ca985a78e86d750c98228b Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:13 -0500 Subject: [PATCH 078/139] Bluetooth: Refactor dlc disconnect logic in rfcomm_dlc_close() Prepare for directly closing dlc if the RFCOMM session has not yet been started; refactor the dlc disconnect logic into a separate local function, __rfcomm_dlc_disconn(). Retains functional equivalence. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/core.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 3ce5ae493d1d..5acc82fa0200 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -431,6 +431,20 @@ int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 chann return r; } +static void __rfcomm_dlc_disconn(struct rfcomm_dlc *d) +{ + struct rfcomm_session *s = d->session; + + d->state = BT_DISCONN; + if (skb_queue_empty(&d->tx_queue)) { + rfcomm_send_disc(s, d->dlci); + rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT); + } else { + rfcomm_queue_disc(d); + rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2); + } +} + static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) { struct rfcomm_session *s = d->session; @@ -458,14 +472,7 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) /* Fall through */ case BT_CONNECTED: - d->state = BT_DISCONN; - if (skb_queue_empty(&d->tx_queue)) { - rfcomm_send_disc(s, d->dlci); - rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT); - } else { - rfcomm_queue_disc(d); - rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2); - } + __rfcomm_dlc_disconn(d); break; default: From c4fd318d6ebc16bd64ca7b9c06f21b7f33bb462e Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:14 -0500 Subject: [PATCH 079/139] Bluetooth: Directly close dlc for not yet started RFCOMM session If the RFCOMM session has not yet been started (ie., session is still in BT_BOUND state) when a dlc is closed, directly close and unlink the dlc rather than sending a DISC frame that is never sent. This allows the dlci to be immediately reused rather than waiting for a 20 second timeout. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/core.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 5acc82fa0200..b727cd97c5a2 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -468,13 +468,19 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) switch (d->state) { case BT_CONNECT: - case BT_CONFIG: - /* Fall through */ - case BT_CONNECTED: __rfcomm_dlc_disconn(d); break; + case BT_CONFIG: + if (s->state != BT_BOUND) { + __rfcomm_dlc_disconn(d); + break; + } + /* if closing a dlc in a session that hasn't been started, + * just close and unlink the dlc + */ + default: rfcomm_dlc_clear_timer(d); From b92483d54abb4ff288accc36bf1daef44dea9fbe Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:15 -0500 Subject: [PATCH 080/139] Bluetooth: Fix unsafe RFCOMM device parenting Accessing the results of hci_conn_hash_lookup_ba() is unsafe without holding the hci_dev_lock() during the lookup. For example: CPU 0 | CPU 1 hci_conn_hash_lookup_ba | hci_conn_del rcu_read_lock | hci_conn_hash_del list_for_each_entry_rcu | list_del_rcu if (.....) | synchronize_rcu rcu_read_unlock | | hci_conn_del_sysfs | hci_dev_put | hci_conn_put | put_device (last reference) | bt_link_release | kfree(conn) return p << just freed | Even if a hci_conn reference were taken (via hci_conn_get), would not guarantee the lifetime of the sysfs device, but only safe access to the in-memory structure. Ensure the hci_conn device stays valid while the rfcomm device is reparented; rename rfcomm_get_device() to rfcomm_reparent_device() and perform the reparenting within the function while holding the hci_dev_lock. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index a58d693e1e61..2975bc4b9188 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -167,20 +167,29 @@ static struct rfcomm_dev *rfcomm_dev_get(int id) return dev; } -static struct device *rfcomm_get_device(struct rfcomm_dev *dev) +static void rfcomm_reparent_device(struct rfcomm_dev *dev) { struct hci_dev *hdev; struct hci_conn *conn; hdev = hci_get_route(&dev->dst, &dev->src); if (!hdev) - return NULL; + return; + /* The lookup results are unsafe to access without the + * hci device lock (FIXME: why is this not documented?) + */ + hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst); - hci_dev_put(hdev); + /* Just because the acl link is in the hash table is no + * guarantee the sysfs device has been added ... + */ + if (conn && device_is_registered(&conn->dev)) + device_move(dev->tty_dev, &conn->dev, DPM_ORDER_DEV_AFTER_PARENT); - return conn ? &conn->dev : NULL; + hci_dev_unlock(hdev); + hci_dev_put(hdev); } static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf) @@ -589,8 +598,7 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) dev->err = err; if (dlc->state == BT_CONNECTED) { - device_move(dev->tty_dev, rfcomm_get_device(dev), - DPM_ORDER_DEV_AFTER_PARENT); + rfcomm_reparent_device(dev); wake_up_interruptible(&dev->port.open_wait); } else if (dlc->state == BT_CLOSED) From b4d21f193985218c6c75969376249f69e49eb6ee Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:16 -0500 Subject: [PATCH 081/139] Bluetooth: Fix RFCOMM parent device for reused dlc The RFCOMM tty device is parented to the acl link device when the dlc state_change(BT_CONNECTED) notification is received. However, if the dlc from the RFCOMM socket is being reused (RFCOMM_REUSE_DLC is set), then the dlc may already be connected, and no notification will occur. Instead, always parent the RFCOMM tty device to the acl link device at registration time. If the acl link device is not available (eg, because the dlc is not connected) then the tty will remain unparented until the BT_CONNECTED notification is received. Fixes regression with ModemManager when the rfcomm device is created with the flag RFCOMM_REUSE_DLC. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 2975bc4b9188..fa1226f17e86 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -316,6 +316,7 @@ out: goto free; } + rfcomm_reparent_device(dev); dev_set_drvdata(dev->tty_dev, dev); if (device_create_file(dev->tty_dev, &dev_attr_address) < 0) From 7611fcedd6caae0586397508a2414788d87a231c Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:17 -0500 Subject: [PATCH 082/139] Bluetooth: Rename __rfcomm_dev_get() to __rfcomm_dev_lookup() Functions which search lists for matching id's are more commonly named *_lookup, which is the convention in the bluetooth core as well. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index fa1226f17e86..4a38b5454ab0 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -140,7 +140,7 @@ static const struct tty_port_operations rfcomm_port_ops = { .carrier_raised = rfcomm_dev_carrier_raised, }; -static struct rfcomm_dev *__rfcomm_dev_get(int id) +static struct rfcomm_dev *__rfcomm_dev_lookup(int id) { struct rfcomm_dev *dev; @@ -157,7 +157,7 @@ static struct rfcomm_dev *rfcomm_dev_get(int id) spin_lock(&rfcomm_dev_lock); - dev = __rfcomm_dev_get(id); + dev = __rfcomm_dev_lookup(id); if (dev && !tty_port_get(&dev->port)) dev = NULL; From 033ace99c444daa4141b84419f670513ce637b77 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:18 -0500 Subject: [PATCH 083/139] Bluetooth: Serialize RFCOMMCREATEDEV and RFCOMMRELEASEDEV ioctls At least two different race conditions exist with multiple concurrent RFCOMMCREATEDEV and RFCOMMRELEASEDEV ioctls: * Multiple concurrent RFCOMMCREATEDEVs with RFCOMM_REUSE_DLC can mistakenly share the same DLC. * RFCOMMRELEASEDEV can destruct the rfcomm_dev still being constructed by RFCOMMCREATEDEV. Introduce rfcomm_ioctl_mutex to serialize these add/remove operations. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 4a38b5454ab0..ef2769553dab 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -40,6 +40,7 @@ #define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */ #define RFCOMM_TTY_MINOR 0 +static DEFINE_MUTEX(rfcomm_ioctl_mutex); static struct tty_driver *rfcomm_tty_driver; struct rfcomm_dev { @@ -373,7 +374,7 @@ static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size #define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP)) -static int rfcomm_create_dev(struct sock *sk, void __user *arg) +static int __rfcomm_create_dev(struct sock *sk, void __user *arg) { struct rfcomm_dev_req req; struct rfcomm_dlc *dlc; @@ -423,7 +424,7 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg) return id; } -static int rfcomm_release_dev(void __user *arg) +static int __rfcomm_release_dev(void __user *arg) { struct rfcomm_dev_req req; struct rfcomm_dev *dev; @@ -466,6 +467,28 @@ static int rfcomm_release_dev(void __user *arg) return 0; } +static int rfcomm_create_dev(struct sock *sk, void __user *arg) +{ + int ret; + + mutex_lock(&rfcomm_ioctl_mutex); + ret = __rfcomm_create_dev(sk, arg); + mutex_unlock(&rfcomm_ioctl_mutex); + + return ret; +} + +static int rfcomm_release_dev(void __user *arg) +{ + int ret; + + mutex_lock(&rfcomm_ioctl_mutex); + ret = __rfcomm_release_dev(arg); + mutex_unlock(&rfcomm_ioctl_mutex); + + return ret; +} + static int rfcomm_get_dev_list(void __user *arg) { struct rfcomm_dev *dev; From f355095756c2a0b77a5b0aa0384c0c09d9735252 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:19 -0500 Subject: [PATCH 084/139] Bluetooth: Refactor rfcomm_dev_add() Move rfcomm_dev allocation and initialization into new function, __rfcomm_dev_add(), to simplify resource release in error handling. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index ef2769553dab..0537a0501595 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -208,17 +208,16 @@ static ssize_t show_channel(struct device *tty_dev, struct device_attribute *att static DEVICE_ATTR(address, S_IRUGO, show_address, NULL); static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL); -static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) +static struct rfcomm_dev *__rfcomm_dev_add(struct rfcomm_dev_req *req, + struct rfcomm_dlc *dlc) { struct rfcomm_dev *dev, *entry; struct list_head *head = &rfcomm_dev_list; int err = 0; - BT_DBG("id %d channel %d", req->dev_id, req->channel); - dev = kzalloc(sizeof(struct rfcomm_dev), GFP_KERNEL); if (!dev) - return -ENOMEM; + return ERR_PTR(-ENOMEM); spin_lock(&rfcomm_dev_lock); @@ -301,22 +300,37 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) holds reference to this module. */ __module_get(THIS_MODULE); + spin_unlock(&rfcomm_dev_lock); + return dev; + out: spin_unlock(&rfcomm_dev_lock); + kfree(dev); + return ERR_PTR(err); +} - if (err < 0) - goto free; +static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) +{ + struct rfcomm_dev *dev; + struct device *tty; - dev->tty_dev = tty_port_register_device(&dev->port, rfcomm_tty_driver, + BT_DBG("id %d channel %d", req->dev_id, req->channel); + + dev = __rfcomm_dev_add(req, dlc); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + tty = tty_port_register_device(&dev->port, rfcomm_tty_driver, dev->id, NULL); - if (IS_ERR(dev->tty_dev)) { - err = PTR_ERR(dev->tty_dev); + if (IS_ERR(tty)) { spin_lock(&rfcomm_dev_lock); list_del(&dev->list); spin_unlock(&rfcomm_dev_lock); - goto free; + kfree(dev); + return PTR_ERR(tty); } + dev->tty_dev = tty; rfcomm_reparent_device(dev); dev_set_drvdata(dev->tty_dev, dev); @@ -327,10 +341,6 @@ out: BT_ERR("Failed to create channel attribute"); return dev->id; - -free: - kfree(dev); - return err; } /* ---- Send buffer ---- */ From fb856e50900a84dd9f8d50d3882eb4a26ba6ea54 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:20 -0500 Subject: [PATCH 085/139] Bluetooth: Cleanup RFCOMM device registration error handling If RFCOMM tty device registration fails, cleanup by releasing the tty_port reference to trigger rfcomm_dev destruction (rather than open-coding it). The dlc reference release is moved into rfcomm_dev_add(), which ensures cleanup in both error paths -- ie., if __rfcomm_dev_add() fails or if tty_port_register_device() fails. Fixes releasing the module reference if device registration fails. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 0537a0501595..375b60dae04d 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -93,7 +93,8 @@ static void rfcomm_dev_destruct(struct tty_port *port) rfcomm_dlc_put(dlc); - tty_unregister_device(rfcomm_tty_driver, dev->id); + if (dev->tty_dev) + tty_unregister_device(rfcomm_tty_driver, dev->id); spin_lock(&rfcomm_dev_lock); list_del(&dev->list); @@ -317,16 +318,15 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) BT_DBG("id %d channel %d", req->dev_id, req->channel); dev = __rfcomm_dev_add(req, dlc); - if (IS_ERR(dev)) + if (IS_ERR(dev)) { + rfcomm_dlc_put(dlc); return PTR_ERR(dev); + } tty = tty_port_register_device(&dev->port, rfcomm_tty_driver, dev->id, NULL); if (IS_ERR(tty)) { - spin_lock(&rfcomm_dev_lock); - list_del(&dev->list); - spin_unlock(&rfcomm_dev_lock); - kfree(dev); + tty_port_put(&dev->port); return PTR_ERR(tty); } @@ -420,10 +420,8 @@ static int __rfcomm_create_dev(struct sock *sk, void __user *arg) } id = rfcomm_dev_add(&req, dlc); - if (id < 0) { - rfcomm_dlc_put(dlc); + if (id < 0) return id; - } if (req.flags & (1 << RFCOMM_REUSE_DLC)) { /* DLC is now used by device. From 5326a4ee982703ddba14a9821fe5cb10d122e1b0 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:21 -0500 Subject: [PATCH 086/139] Bluetooth: Force -EIO from tty read/write if .activate() fails If rfcomm_dlc_open() fails, set tty into error state which returns -EIO from reads and writes. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 375b60dae04d..f6b9f0c4c29e 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -111,8 +111,12 @@ static void rfcomm_dev_destruct(struct tty_port *port) static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty) { struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); + int err; - return rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel); + err = rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel); + if (err) + set_bit(TTY_IO_ERROR, &tty->flags); + return err; } /* we block the open until the dlc->state becomes BT_CONNECTED */ From 72e5108c6d637ea2f4c0e64b09621a79f363b664 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:22 -0500 Subject: [PATCH 087/139] Bluetooth: Don't fail RFCOMM tty writes The tty driver api design prefers no-fail writes if the driver write_room() method has previously indicated space is available to accept writes. Since this is trivially possible for the RFCOMM tty driver, do so. Introduce rfcomm_dlc_send_noerror(), which queues but does not schedule the krfcomm thread if the dlc is not yet connected (and thus does not error based on the connection state). The mtu size test is also unnecessary since the caller already chunks the written data into mtu size. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- include/net/bluetooth/rfcomm.h | 1 + net/bluetooth/rfcomm/core.c | 14 ++++++++++++++ net/bluetooth/rfcomm/tty.c | 23 +++++++---------------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index f8262a2783ec..2611cc389d7d 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -238,6 +238,7 @@ int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel); int rfcomm_dlc_close(struct rfcomm_dlc *d, int reason); int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb); +void rfcomm_dlc_send_noerror(struct rfcomm_dlc *d, struct sk_buff *skb); int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig); int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); void rfcomm_dlc_accept(struct rfcomm_dlc *d); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index b727cd97c5a2..21e15318937c 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -569,6 +569,20 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb) return len; } +void rfcomm_dlc_send_noerror(struct rfcomm_dlc *d, struct sk_buff *skb) +{ + int len = skb->len; + + BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len); + + rfcomm_make_uih(skb, d->addr); + skb_queue_tail(&d->tx_queue, skb); + + if (d->state == BT_CONNECTED && + !test_bit(RFCOMM_TX_THROTTLED, &d->flags)) + rfcomm_schedule(); +} + void __rfcomm_dlc_throttle(struct rfcomm_dlc *d) { BT_DBG("dlc %p state %ld", d, d->state); diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index f6b9f0c4c29e..af775f35c019 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -374,14 +374,10 @@ static void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev) static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, gfp_t priority) { - if (atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) { - struct sk_buff *skb = alloc_skb(size, priority); - if (skb) { - rfcomm_set_owner_w(skb, dev); - return skb; - } - } - return NULL; + struct sk_buff *skb = alloc_skb(size, priority); + if (skb) + rfcomm_set_owner_w(skb, dev); + return skb; } /* ---- Device IOCTLs ---- */ @@ -786,7 +782,7 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; struct rfcomm_dlc *dlc = dev->dlc; struct sk_buff *skb; - int err = 0, sent = 0, size; + int sent = 0, size; BT_DBG("tty %p count %d", tty, count); @@ -794,7 +790,6 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in size = min_t(uint, count, dlc->mtu); skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC); - if (!skb) break; @@ -802,17 +797,13 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in memcpy(skb_put(skb, size), buf + sent, size); - err = rfcomm_dlc_send(dlc, skb); - if (err < 0) { - kfree_skb(skb); - break; - } + rfcomm_dlc_send_noerror(dlc, skb); sent += size; count -= size; } - return sent ? sent : err; + return sent; } static int rfcomm_tty_write_room(struct tty_struct *tty) From b16b4351313fb89ccb4c227d432d16aa32ffec72 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:23 -0500 Subject: [PATCH 088/139] Bluetooth: Refactor write_room() calculation Compute the amount of space available for a single write() within rfcomm_room(); clamp to 0 for negative values. Note this patch does not change the result of the computation. Report the amount of room returned in the debug printk. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index af775f35c019..3f44195c04ad 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -348,11 +348,18 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) } /* ---- Send buffer ---- */ -static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc) +static inline unsigned int rfcomm_room(struct rfcomm_dev *dev) { - /* We can't let it be zero, because we don't get a callback - when tx_credits becomes nonzero, hence we'd never wake up */ - return dlc->mtu * (dlc->tx_credits?:1); + struct rfcomm_dlc *dlc = dev->dlc; + + /* The limit is bogus; the number of packets which can + * currently be sent by the krfcommd thread has no relevance + * to the number of packets which can be queued on the dlc's + * tx queue. + */ + int limit = dlc->mtu * (dlc->tx_credits?:1); + + return max(0, limit - atomic_read(&dev->wmem_alloc)); } static void rfcomm_wfree(struct sk_buff *skb) @@ -809,16 +816,12 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in static int rfcomm_tty_write_room(struct tty_struct *tty) { struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; - int room; + int room = 0; - BT_DBG("tty %p", tty); + if (dev && dev->dlc) + room = rfcomm_room(dev); - if (!dev || !dev->dlc) - return 0; - - room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc); - if (room < 0) - room = 0; + BT_DBG("tty %p room %d", tty, room); return room; } From 8981be9b2fe5553af35a43865d9ab4271c3aa2e2 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 9 Feb 2014 20:59:24 -0500 Subject: [PATCH 089/139] Bluetooth: Fix write_room() calculation The skb truesize of a 12-byte payload with a 10-byte head/tail reserve is 768 bytes. Consequently, even with 40 tx_credits, at most 6 packets could be queued at any one time: 40 tx_credits * 127-byte mtu < 768-byte truesize * 7 This error could also cause the tx queue to apparently stall if credit flow control is disabled (where tx_credits is fixed at 5), or if the receiver only granted a limited number of tx credits (eg., less than 7). Instead, track the outstanding number of queued packets not yet sent in wmem_alloc and allow for a maximum of 40 queued packets. Report the space avail for a single write() as the mtu * number of packets left before reaching the maximum. Signed-off-by: Peter Hurley Tested-By: Alexander Holler Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 3f44195c04ad..403ec09f480a 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -352,20 +352,16 @@ static inline unsigned int rfcomm_room(struct rfcomm_dev *dev) { struct rfcomm_dlc *dlc = dev->dlc; - /* The limit is bogus; the number of packets which can - * currently be sent by the krfcommd thread has no relevance - * to the number of packets which can be queued on the dlc's - * tx queue. - */ - int limit = dlc->mtu * (dlc->tx_credits?:1); + /* Limit the outstanding number of packets not yet sent to 40 */ + int pending = 40 - atomic_read(&dev->wmem_alloc); - return max(0, limit - atomic_read(&dev->wmem_alloc)); + return max(0, pending) * dlc->mtu; } static void rfcomm_wfree(struct sk_buff *skb) { struct rfcomm_dev *dev = (void *) skb->sk; - atomic_sub(skb->truesize, &dev->wmem_alloc); + atomic_dec(&dev->wmem_alloc); if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags)) tty_port_tty_wakeup(&dev->port); tty_port_put(&dev->port); @@ -374,7 +370,7 @@ static void rfcomm_wfree(struct sk_buff *skb) static void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev) { tty_port_get(&dev->port); - atomic_add(skb->truesize, &dev->wmem_alloc); + atomic_inc(&dev->wmem_alloc); skb->sk = (void *) dev; skb->destructor = rfcomm_wfree; } From 9113bfd82dc8ece9cbb898df8794f58a78a36e97 Mon Sep 17 00:00:00 2001 From: Jurgen Kramer Date: Sat, 15 Feb 2014 12:01:09 +0100 Subject: [PATCH 090/139] Bluetooth: btusb: Add IMC Networks (Broadcom based) Add support for IMC Networks (Broadcom based) to btusb driver. Below the output of /sys/kernel/debug/usb/devices for this device: T: Bus=01 Lev=02 Prnt=02 Port=04 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3404 Rev= 1.12 S: Manufacturer=Broadcom Corp S: Product=BCM20702A0 S: SerialNumber=240A649F8246 C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) Signed-off-by: Jurgen Kramer Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 5926a9db44b4..e5680fa173c2 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -116,6 +116,9 @@ static const struct usb_device_id btusb_table[] = { /* Belkin F8065bf - Broadcom based */ { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) }, + /* IMC Networks - Broadcom based */ + { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) }, + { } /* Terminating entry */ }; From 490cb0b318a0619ae545e63d6773f01caf29d4a0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 16 Feb 2014 12:59:05 -0800 Subject: [PATCH 091/139] Bluetooth: Restrict long term keys to public and static addresses The long term keys should be associated with an identity address. Valid identity addresses are public addresses or static addresses. So only allow these two as valid address information for long term keys. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ce7ef339b1c4..70bef3d5db57 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4162,9 +4162,19 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key) { if (key->master != 0x00 && key->master != 0x01) return false; - if (!bdaddr_type_is_le(key->addr.type)) - return false; - return true; + + switch (key->addr.type) { + case BDADDR_LE_PUBLIC: + return true; + + case BDADDR_LE_RANDOM: + /* Two most significant bits shall be set */ + if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0) + return false; + return true; + } + + return false; } static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, From 0fe442ff854b7bf93e57c7f3964b05a6438de3db Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 16 Feb 2014 12:59:06 -0800 Subject: [PATCH 092/139] Bluetooth: Fix sending wrong store hint for new long term keys The long term keys should only be stored when they belong to an indentity address. The identity address can either be a public address or a random static address. For all other addresses (unresovable or resolvable) tell userspace that the long term key is not persistent. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e7746690d620..58d2f9bf241f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2685,6 +2685,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, { struct smp_ltk *key, *old_key; bool master = ltk_type_master(type); + u8 persistent; old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, master); if (old_key) @@ -2708,8 +2709,13 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, if (!new_key) return 0; + if (addr_type == ADDR_LE_DEV_RANDOM && (bdaddr->b[5] & 0xc0) != 0xc0) + persistent = 0; + else + persistent = 1; + if (type == HCI_SMP_LTK || type == HCI_SMP_LTK_SLAVE) - mgmt_new_ltk(hdev, key, 1); + mgmt_new_ltk(hdev, key, persistent); return 0; } From c6521401d668538784e27d5746e7035fcf1107a8 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 17 Feb 2014 09:21:18 -0800 Subject: [PATCH 093/139] Bluetooth: Add missing index added event on user channel failure When the setup of user channel fails, the index added event is not sent and will cause issues with user interaction. This problem can be easily triggered with a LE only controller without a public address. In that case hci_dev_open() fails and that error case is not sending an event saying that the controller is available for normal use again. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 7552f9e3089c..68e51a84e72d 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -716,6 +716,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, err = hci_dev_open(hdev->id); if (err) { clear_bit(HCI_USER_CHANNEL, &hdev->dev_flags); + mgmt_index_added(hdev); hci_dev_put(hdev); goto done; } From c6beca0e0dc70c439894337e82609ec3b79ed900 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 17 Feb 2014 09:21:19 -0800 Subject: [PATCH 094/139] Bluetooth: Allow HCI User Channel usage for controllers without address Trying to setup HCI User Channel usage for LE only controllers without a public address or configured static address will fail with an error saying that no address is available. In case of HCI User Channel the requirement for a valid address is not needed. So allow skipping this extra validation step. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 58d2f9bf241f..b40d52446f8f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1937,10 +1937,15 @@ static int hci_dev_do_open(struct hci_dev *hdev) * be able to determine if there is a public address * or not. * + * In case of user channel usage, it is not important + * if a public address or static random address is + * available. + * * This check is only valid for BR/EDR controllers * since AMP controllers do not have an address. */ - if (hdev->dev_type == HCI_BREDR && + if (!test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) && + hdev->dev_type == HCI_BREDR && !bacmp(&hdev->bdaddr, BDADDR_ANY) && !bacmp(&hdev->static_addr, BDADDR_ANY)) { ret = -EADDRNOTAVAIL; From c46b98bea5691c0ed99da85cf0cb87bc146468e9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:29 +0200 Subject: [PATCH 095/139] Bluetooth: Fix missing PDU length checks for SMP For each received SMP PDU we need to check that we have enough data to fit the specified size of the PDU. This patch adds the necessary checks for each SMP PDU handler and ensures that buffer overflows do not occur if to little data has been received. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index efe51ccdc615..1730bb2b6259 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -565,6 +565,9 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); + if (skb->len < sizeof(*req)) + return SMP_UNSPECIFIED; + if (conn->hcon->link_mode & HCI_LM_MASTER) return SMP_CMD_NOTSUPP; @@ -617,6 +620,9 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); + if (skb->len < sizeof(*rsp)) + return SMP_UNSPECIFIED; + if (!(conn->hcon->link_mode & HCI_LM_MASTER)) return SMP_CMD_NOTSUPP; @@ -661,6 +667,9 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); + if (skb->len < sizeof(smp->pcnf)) + return SMP_UNSPECIFIED; + memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf)); skb_pull(skb, sizeof(smp->pcnf)); @@ -686,6 +695,9 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); + if (skb->len < sizeof(smp->rrnd)) + return SMP_UNSPECIFIED; + swap128(skb->data, smp->rrnd); skb_pull(skb, sizeof(smp->rrnd)); @@ -725,6 +737,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("conn %p", conn); + if (skb->len < sizeof(*rp)) + return SMP_UNSPECIFIED; + if (!(conn->hcon->link_mode & HCI_LM_MASTER)) return SMP_CMD_NOTSUPP; @@ -814,6 +829,11 @@ 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; + BT_DBG("conn %p", conn); + + if (skb->len < sizeof(*rp)) + return SMP_UNSPECIFIED; + skb_pull(skb, sizeof(*rp)); memcpy(smp->tk, rp->ltk, sizeof(smp->tk)); @@ -829,6 +849,11 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) struct hci_conn *hcon = conn->hcon; u8 authenticated; + BT_DBG("conn %p", conn); + + if (skb->len < sizeof(*rp)) + return SMP_UNSPECIFIED; + skb_pull(skb, sizeof(*rp)); hci_dev_lock(hdev); From 6bfdfe3cd68d5a797e0ebfb57068fe7f9c20c93a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:30 +0200 Subject: [PATCH 096/139] Bluetooth: Fix minor whitespace issues in SMP code This patch fixes a couple of unnecessary empty lines in the SMP code. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 1 - net/bluetooth/smp.h | 1 - 2 files changed, 2 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1730bb2b6259..ae487e17380e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -990,7 +990,6 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) *keydist &= req->resp_key_dist; } - BT_DBG("keydist 0x%x", *keydist); if (*keydist & SMP_DIST_ENC_KEY) { diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index a700bcb490d7..777ee93a6c9b 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -132,7 +132,6 @@ struct smp_chan { struct crypto_blkcipher *tfm; struct work_struct confirm; struct work_struct random; - }; /* SMP Commands */ From 60478054a6af7aa8cceb8218d29d27f165f1c9d3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:31 +0200 Subject: [PATCH 097/139] Bluetooth: Add smp_irk_matches helper function This patch adds a helper function to check whether a given IRK matches a given Resolvable Private Address (RPA). The function will be needed for implementing the rest of address resolving support. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ net/bluetooth/smp.h | 3 +++ 2 files changed, 49 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index ae487e17380e..5f500b479f45 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -78,6 +78,52 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r) return err; } +static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3]) +{ + u8 _res[16], k[16]; + int err; + + /* r' = padding || r */ + memset(_res, 0, 13); + _res[13] = r[2]; + _res[14] = r[1]; + _res[15] = r[0]; + + swap128(irk, k); + err = smp_e(tfm, k, _res); + if (err) { + BT_ERR("Encrypt error"); + return err; + } + + /* The output of the random address function ah is: + * ah(h, r) = e(k, r') mod 2^24 + * The output of the security function e is then truncated to 24 bits + * by taking the least significant 24 bits of the output of e as the + * result of ah. + */ + res[0] = _res[15]; + res[1] = _res[14]; + res[2] = _res[13]; + + return 0; +} + +bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], + bdaddr_t *bdaddr) +{ + u8 hash[3]; + int err; + + BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk); + + err = smp_ah(tfm, irk, &bdaddr->b[3], hash); + if (err) + return false; + + return !memcmp(bdaddr->b, hash, 3); +} + static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16], u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia, u8 _rat, bdaddr_t *ra, u8 res[16]) diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 777ee93a6c9b..950d039c2ea2 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -143,4 +143,7 @@ int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey); void smp_chan_destroy(struct l2cap_conn *conn); +bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], + bdaddr_t *bdaddr); + #endif /* __SMP_H */ From 99780a7b639e73d8f8f291fa1a981db883aec47f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:40:07 +0200 Subject: [PATCH 098/139] Bluetooth: Add AES crypto context for each HCI device Previously the crypto context has only been available for LE SMP sessions, but now that we'll need to perform operations also during discovery it makes sense to have this context part of the hci_dev struct. Later, the context can be removed from the SMP context. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 92fa75fce29d..b344890b18f5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -259,6 +259,7 @@ struct hci_dev { __u32 req_status; __u32 req_result; + struct crypto_blkcipher *tfm_aes; struct discovery_state discovery; struct hci_conn_hash conn_hash; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b40d52446f8f..df25af5502ef 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -3205,9 +3206,18 @@ int hci_register_dev(struct hci_dev *hdev) dev_set_name(&hdev->dev, "%s", hdev->name); + hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(hdev->tfm_aes)) { + BT_ERR("Unable to create crypto context"); + error = PTR_ERR(hdev->tfm_aes); + hdev->tfm_aes = NULL; + goto err_wqueue; + } + error = device_add(&hdev->dev); if (error < 0) - goto err_wqueue; + goto err_tfm; hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, @@ -3243,6 +3253,8 @@ int hci_register_dev(struct hci_dev *hdev) return id; +err_tfm: + crypto_free_blkcipher(hdev->tfm_aes); err_wqueue: destroy_workqueue(hdev->workqueue); destroy_workqueue(hdev->req_workqueue); @@ -3293,6 +3305,9 @@ void hci_unregister_dev(struct hci_dev *hdev) rfkill_destroy(hdev->rfkill); } + if (hdev->tfm_aes) + crypto_free_blkcipher(hdev->tfm_aes); + device_del(&hdev->dev); debugfs_remove_recursive(hdev->debugfs); From 970c4e46037ab8ece3940afc9fcf916d3ed7e003 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:33 +0200 Subject: [PATCH 099/139] Bluetooth: Add basic IRK management support This patch adds the initial IRK storage and management functions to the HCI core. This includes storing a list of IRKs per HCI device and the ability to add, remove and lookup entries in that list. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 16 ++++++++ net/bluetooth/hci_core.c | 70 ++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b344890b18f5..eac422337582 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -103,6 +103,14 @@ struct smp_ltk { u8 val[16]; }; +struct smp_irk { + struct list_head list; + bdaddr_t rpa; + bdaddr_t bdaddr; + u8 addr_type; + u8 val[16]; +}; + struct link_key { struct list_head list; bdaddr_t bdaddr; @@ -269,6 +277,7 @@ struct hci_dev { struct list_head uuids; struct list_head link_keys; struct list_head long_term_keys; + struct list_head identity_resolving_keys; struct list_head remote_oob_data; struct list_head le_conn_params; @@ -787,6 +796,13 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); +struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa); +struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type); +int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, + u8 val[16], bdaddr_t *rpa); +void hci_smp_irks_clear(struct hci_dev *hdev); + int hci_remote_oob_data_clear(struct hci_dev *hdev); struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index df25af5502ef..59a76b2566eb 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -35,6 +35,8 @@ #include #include +#include "smp.h" + static void hci_rx_work(struct work_struct *work); static void hci_cmd_work(struct work_struct *work); static void hci_tx_work(struct work_struct *work); @@ -2544,6 +2546,16 @@ int hci_smp_ltks_clear(struct hci_dev *hdev) return 0; } +void hci_smp_irks_clear(struct hci_dev *hdev) +{ + struct smp_irk *k, *tmp; + + list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) { + list_del(&k->list); + kfree(k); + } +} + struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) { struct link_key *k; @@ -2632,6 +2644,39 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, return NULL; } +struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa) +{ + struct smp_irk *irk; + + list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { + if (!bacmp(&irk->rpa, rpa)) + return irk; + } + + list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { + if (smp_irk_matches(hdev->tfm_aes, irk->val, rpa)) { + bacpy(&irk->rpa, rpa); + return irk; + } + } + + return NULL; +} + +struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type) +{ + struct smp_irk *irk; + + list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { + if (addr_type == irk->addr_type && + bacmp(bdaddr, &irk->bdaddr) == 0) + return irk; + } + + return NULL; +} + int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) { @@ -2726,6 +2771,29 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, return 0; } +int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, + u8 val[16], bdaddr_t *rpa) +{ + struct smp_irk *irk; + + irk = hci_find_irk_by_addr(hdev, bdaddr, addr_type); + if (!irk) { + irk = kzalloc(sizeof(*irk), GFP_KERNEL); + if (!irk) + return -ENOMEM; + + bacpy(&irk->bdaddr, bdaddr); + irk->addr_type = addr_type; + + list_add(&irk->list, &hdev->identity_resolving_keys); + } + + memcpy(irk->val, val, 16); + bacpy(&irk->rpa, rpa); + + return 0; +} + int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) { struct link_key *key; @@ -3120,6 +3188,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->uuids); INIT_LIST_HEAD(&hdev->link_keys); INIT_LIST_HEAD(&hdev->long_term_keys); + INIT_LIST_HEAD(&hdev->identity_resolving_keys); INIT_LIST_HEAD(&hdev->remote_oob_data); INIT_LIST_HEAD(&hdev->le_conn_params); INIT_LIST_HEAD(&hdev->conn_hash.list); @@ -3320,6 +3389,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_uuids_clear(hdev); hci_link_keys_clear(hdev); hci_smp_ltks_clear(hdev); + hci_smp_irks_clear(hdev); hci_remote_oob_data_clear(hdev); hci_conn_params_clear(hdev); hci_dev_unlock(hdev); From 301cb2d85eb89140eaff8c22066a4bfd774960a3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:34 +0200 Subject: [PATCH 100/139] Bluetooth: Add hci_bdaddr_is_rpa convenience function When implementing support for Resolvable Private Addresses (RPAs) we'll need to in several places be able to identify such addresses. This patch adds a simple convenience function to do the identification of the address type. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index eac422337582..86ea4bab9e77 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1071,6 +1071,17 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) return false; } +static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type) +{ + if (addr_type != 0x01) + return false; + + if ((bdaddr->b[5] & 0xc0) == 0x40) + return true; + + return false; +} + int hci_register_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb); From 41edf1601af3b25461d91e73834dc89510bca8e5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:35 +0200 Subject: [PATCH 101/139] Bluetooth: Implement mgmt_load_irks command This patch implements the Load IRKs command for the management interface. The command is used to load the kernel with the initial set of IRKs. It also sets a HCI_RPA_RESOLVING flag to indicate that we can start requesting devices to distribute their IRK to us. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 1 + include/net/bluetooth/mgmt.h | 12 ++++++ net/bluetooth/mgmt.c | 79 ++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 352d3d7d06bb..d3a8fff50f69 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -125,6 +125,7 @@ enum { HCI_SSP_ENABLED, HCI_SC_ENABLED, HCI_SC_ONLY, + HCI_RPA_RESOLVING, HCI_HS_ENABLED, HCI_LE_ENABLED, HCI_ADVERTISING, diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 4303fa90b7c1..e4fa13e559e2 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -389,6 +389,18 @@ struct mgmt_cp_set_scan_params { #define MGMT_OP_SET_DEBUG_KEYS 0x002E +struct mgmt_irk_info { + struct mgmt_addr_info addr; + __u8 val[16]; +} __packed; + +#define MGMT_OP_LOAD_IRKS 0x0030 +struct mgmt_cp_load_irks { + __le16 irk_count; + struct mgmt_irk_info irks[0]; +} __packed; +#define MGMT_LOAD_IRKS_SIZE 2 + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 70bef3d5db57..782e2bb10881 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -81,6 +81,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_SET_SCAN_PARAMS, MGMT_OP_SET_SECURE_CONN, MGMT_OP_SET_DEBUG_KEYS, + MGMT_OP_LOAD_IRKS, }; static const u16 mgmt_events[] = { @@ -4158,6 +4159,82 @@ unlock: return err; } +static bool irk_is_valid(struct mgmt_irk_info *irk) +{ + switch (irk->addr.type) { + case BDADDR_LE_PUBLIC: + return true; + + case BDADDR_LE_RANDOM: + /* Two most significant bits shall be set */ + if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0) + return false; + return true; + } + + return false; +} + +static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data, + u16 len) +{ + struct mgmt_cp_load_irks *cp = cp_data; + u16 irk_count, expected_len; + int i, err; + + BT_DBG("request for %s", hdev->name); + + if (!lmp_le_capable(hdev)) + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS, + MGMT_STATUS_NOT_SUPPORTED); + + irk_count = __le16_to_cpu(cp->irk_count); + + expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info); + if (expected_len != len) { + BT_ERR("load_irks: expected %u bytes, got %u bytes", + len, expected_len); + return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS, + MGMT_STATUS_INVALID_PARAMS); + } + + BT_DBG("%s irk_count %u", hdev->name, irk_count); + + for (i = 0; i < irk_count; i++) { + struct mgmt_irk_info *key = &cp->irks[i]; + + if (!irk_is_valid(key)) + return cmd_status(sk, hdev->id, + MGMT_OP_LOAD_IRKS, + MGMT_STATUS_INVALID_PARAMS); + } + + hci_dev_lock(hdev); + + hci_smp_irks_clear(hdev); + + for (i = 0; i < irk_count; i++) { + struct mgmt_irk_info *irk = &cp->irks[i]; + u8 addr_type; + + if (irk->addr.type == BDADDR_LE_PUBLIC) + addr_type = ADDR_LE_DEV_PUBLIC; + else + addr_type = ADDR_LE_DEV_RANDOM; + + hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val, + BDADDR_ANY); + } + + set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags); + + err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0); + + hci_dev_unlock(hdev); + + return err; +} + static bool ltk_is_valid(struct mgmt_ltk_info *key) { if (key->master != 0x00 && key->master != 0x01) @@ -4296,6 +4373,8 @@ static const struct mgmt_handler { { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE }, { set_secure_conn, false, MGMT_SETTING_SIZE }, { set_debug_keys, false, MGMT_SETTING_SIZE }, + { }, + { load_irks, true, MGMT_LOAD_IRKS_SIZE }, }; From fd349c020c5b6f7a6e17cb8b4e821ff9b6f71ba6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:36 +0200 Subject: [PATCH 102/139] Bluetooth: Enable support for remote IRK distribution This patch does the necessary changes to request the remote device to distribute its IRK to us during the SMP pairing procedure. This includes setting the right key distribution values in the pairing request/response and handling of the two related SMP PDUs, i.e. Identity Information and Identity Address Information. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 80 +++++++++++++++++++++++++++++++++++++++++---- net/bluetooth/smp.h | 4 +++ 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 5f500b479f45..024baa789eb9 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -249,31 +249,42 @@ static void build_pairing_cmd(struct l2cap_conn *conn, struct smp_cmd_pairing *req, struct smp_cmd_pairing *rsp, __u8 authreq) { - u8 dist_keys = 0; + struct smp_chan *smp = conn->smp_chan; + struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; + u8 local_dist = 0, remote_dist = 0; if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) { - dist_keys = SMP_DIST_ENC_KEY; + local_dist = SMP_DIST_ENC_KEY; + remote_dist = SMP_DIST_ENC_KEY; authreq |= SMP_AUTH_BONDING; } else { authreq &= ~SMP_AUTH_BONDING; } + if (test_bit(HCI_RPA_RESOLVING, &hdev->dev_flags)) + remote_dist |= SMP_DIST_ID_KEY; + if (rsp == NULL) { req->io_capability = conn->hcon->io_capability; req->oob_flag = SMP_OOB_NOT_PRESENT; req->max_key_size = SMP_MAX_ENC_KEY_SIZE; - req->init_key_dist = dist_keys; - req->resp_key_dist = dist_keys; + req->init_key_dist = local_dist; + req->resp_key_dist = remote_dist; req->auth_req = (authreq & AUTH_REQ_MASK); + + smp->remote_key_dist = remote_dist; return; } rsp->io_capability = conn->hcon->io_capability; rsp->oob_flag = SMP_OOB_NOT_PRESENT; 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->init_key_dist = req->init_key_dist & remote_dist; + rsp->resp_key_dist = req->resp_key_dist & local_dist; rsp->auth_req = (authreq & AUTH_REQ_MASK); + + smp->remote_key_dist = rsp->init_key_dist; } static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) @@ -907,12 +918,61 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, 1, authenticated, smp->tk, smp->enc_key_size, rp->ediv, rp->rand); - smp_distribute_keys(conn, 1); + if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) + smp_distribute_keys(conn, 1); hci_dev_unlock(hdev); return 0; } +static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb) +{ + struct smp_cmd_ident_info *info = (void *) skb->data; + struct smp_chan *smp = conn->smp_chan; + + BT_DBG(""); + + if (skb->len < sizeof(*info)) + return SMP_UNSPECIFIED; + + skb_pull(skb, sizeof(*info)); + + memcpy(smp->irk, info->irk, 16); + + return 0; +} + +static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, + struct sk_buff *skb) +{ + struct smp_cmd_ident_addr_info *info = (void *) skb->data; + struct smp_chan *smp = conn->smp_chan; + struct hci_conn *hcon = conn->hcon; + bdaddr_t rpa; + + BT_DBG(""); + + if (skb->len < sizeof(*info)) + return SMP_UNSPECIFIED; + + skb_pull(skb, sizeof(*info)); + + bacpy(&smp->id_addr, &info->bdaddr); + smp->id_addr_type = info->addr_type; + + if (hci_bdaddr_is_rpa(&hcon->dst, hcon->dst_type)) + bacpy(&rpa, &hcon->dst); + else + bacpy(&rpa, BDADDR_ANY); + + hci_add_irk(conn->hcon->hdev, &smp->id_addr, smp->id_addr_type, + smp->irk, &rpa); + + smp_distribute_keys(conn, 1); + + return 0; +} + int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) { struct hci_conn *hcon = conn->hcon; @@ -987,7 +1047,13 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) break; case SMP_CMD_IDENT_INFO: + reason = smp_cmd_ident_info(conn, skb); + break; + case SMP_CMD_IDENT_ADDR_INFO: + reason = smp_cmd_ident_addr_info(conn, skb); + break; + case SMP_CMD_SIGN_INFO: /* Just ignored */ reason = 0; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 950d039c2ea2..4f373bc56ad7 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -128,6 +128,10 @@ struct smp_chan { u8 pcnf[16]; /* SMP Pairing Confirm */ u8 tk[16]; /* SMP Temporary Key */ u8 enc_key_size; + u8 remote_key_dist; + bdaddr_t id_addr; + u8 id_addr_type; + u8 irk[16]; unsigned long smp_flags; struct crypto_blkcipher *tfm; struct work_struct confirm; From 6131ddc8eb9bad8c4ff37e097b2537c819b76cc0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 10:19:37 +0200 Subject: [PATCH 103/139] Bluetooth: Fix properly ignoring unexpected SMP PDUs If we didn't request certain pieces of information during the key distribution negotiation we should properly ignore those PDUs if the peer incorrectly sends them. This includes the Encryption Information and Master Identification PDUs if the EncKey bit was not set, and the Identity Information and Identity Address Information PDUs if the IdKey bit was not set. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 024baa789eb9..5867c1c3f436 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -891,6 +891,10 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rp)) return SMP_UNSPECIFIED; + /* Ignore this PDU if it wasn't requested */ + if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY)) + return 0; + skb_pull(skb, sizeof(*rp)); memcpy(smp->tk, rp->ltk, sizeof(smp->tk)); @@ -911,6 +915,10 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rp)) return SMP_UNSPECIFIED; + /* Ignore this PDU if it wasn't requested */ + if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY)) + return 0; + skb_pull(skb, sizeof(*rp)); hci_dev_lock(hdev); @@ -935,6 +943,10 @@ static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*info)) return SMP_UNSPECIFIED; + /* Ignore this PDU if it wasn't requested */ + if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) + return 0; + skb_pull(skb, sizeof(*info)); memcpy(smp->irk, info->irk, 16); @@ -955,6 +967,10 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, if (skb->len < sizeof(*info)) return SMP_UNSPECIFIED; + /* Ignore this PDU if it wasn't requested */ + if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) + return 0; + skb_pull(skb, sizeof(*info)); bacpy(&smp->id_addr, &info->bdaddr); From e0b2b27e622da0ba8a3d253b985d3d8f174b4313 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 17:14:31 +0200 Subject: [PATCH 104/139] Bluetooth: Fix missing address type check for removing LTKs When removing Long Term Keys we should also be checking that the given address type (public vs random) matches. This patch updates the hci_remove_ltk function to take an extra parameter and uses it for address type matching. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 4 ++-- net/bluetooth/mgmt.c | 14 +++++++++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 86ea4bab9e77..ab94abdeb3c1 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -792,7 +792,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, __le16 ediv, u8 rand[8]); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, bool master); -int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); +int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type); int hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 59a76b2566eb..957c8f4cc4c7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2810,12 +2810,12 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) return 0; } -int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr) +int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type) { struct smp_ltk *k, *tmp; list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { - if (bacmp(bdaddr, &k->bdaddr)) + if (bacmp(bdaddr, &k->bdaddr) || k->bdaddr_type != bdaddr_type) continue; BT_DBG("%s removing %pMR", hdev->name, bdaddr); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 782e2bb10881..473f8687b28b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2318,10 +2318,18 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, goto unlock; } - if (cp->addr.type == BDADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) { err = hci_remove_link_key(hdev, &cp->addr.bdaddr); - else - err = hci_remove_ltk(hdev, &cp->addr.bdaddr); + } else { + u8 addr_type; + + if (cp->addr.type == BDADDR_LE_PUBLIC) + addr_type = ADDR_LE_DEV_PUBLIC; + else + addr_type = ADDR_LE_DEV_RANDOM; + + err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type); + } if (err < 0) { err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, From 35f7498a87794ca531335f7c782e5b9495fec6d6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 17:14:32 +0200 Subject: [PATCH 105/139] Bluetooth: Remove return values from functions that don't need them There are many functions that never fail but still declare an integer return value for no reason. This patch converts these functions to use a void return value to avoid any confusion of whether they can fail or not. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 10 +++++----- net/bluetooth/hci_core.c | 26 +++++++++----------------- net/bluetooth/mgmt.c | 2 +- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ab94abdeb3c1..964a7888ad0c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -768,7 +768,7 @@ int hci_inquiry(void __user *arg); struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); -int hci_blacklist_clear(struct hci_dev *hdev); +void hci_blacklist_clear(struct hci_dev *hdev); int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); @@ -779,9 +779,9 @@ void hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type, void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type); void hci_conn_params_clear(struct hci_dev *hdev); -int hci_uuids_clear(struct hci_dev *hdev); +void hci_uuids_clear(struct hci_dev *hdev); -int hci_link_keys_clear(struct hci_dev *hdev); +void hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); @@ -793,7 +793,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, bool master); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type); -int hci_smp_ltks_clear(struct hci_dev *hdev); +void hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa); @@ -803,7 +803,7 @@ int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 val[16], bdaddr_t *rpa); void hci_smp_irks_clear(struct hci_dev *hdev); -int hci_remote_oob_data_clear(struct hci_dev *hdev); +void hci_remote_oob_data_clear(struct hci_dev *hdev); struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 957c8f4cc4c7..fd5bb4086613 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2506,7 +2506,7 @@ static void hci_discov_off(struct work_struct *work) mgmt_discoverable_timeout(hdev); } -int hci_uuids_clear(struct hci_dev *hdev) +void hci_uuids_clear(struct hci_dev *hdev) { struct bt_uuid *uuid, *tmp; @@ -2514,11 +2514,9 @@ int hci_uuids_clear(struct hci_dev *hdev) list_del(&uuid->list); kfree(uuid); } - - return 0; } -int hci_link_keys_clear(struct hci_dev *hdev) +void hci_link_keys_clear(struct hci_dev *hdev) { struct list_head *p, *n; @@ -2530,11 +2528,9 @@ int hci_link_keys_clear(struct hci_dev *hdev) list_del(p); kfree(key); } - - return 0; } -int hci_smp_ltks_clear(struct hci_dev *hdev) +void hci_smp_ltks_clear(struct hci_dev *hdev) { struct smp_ltk *k, *tmp; @@ -2542,8 +2538,6 @@ int hci_smp_ltks_clear(struct hci_dev *hdev) list_del(&k->list); kfree(k); } - - return 0; } void hci_smp_irks_clear(struct hci_dev *hdev) @@ -2873,7 +2867,7 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr) return 0; } -int hci_remote_oob_data_clear(struct hci_dev *hdev) +void hci_remote_oob_data_clear(struct hci_dev *hdev) { struct oob_data *data, *n; @@ -2881,8 +2875,6 @@ int hci_remote_oob_data_clear(struct hci_dev *hdev) list_del(&data->list); kfree(data); } - - return 0; } int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, @@ -2951,7 +2943,7 @@ struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, return NULL; } -int hci_blacklist_clear(struct hci_dev *hdev) +void hci_blacklist_clear(struct hci_dev *hdev) { struct list_head *p, *n; @@ -2961,8 +2953,6 @@ int hci_blacklist_clear(struct hci_dev *hdev) list_del(p); kfree(b); } - - return 0; } int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) @@ -2991,8 +2981,10 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) { struct bdaddr_list *entry; - if (!bacmp(bdaddr, BDADDR_ANY)) - return hci_blacklist_clear(hdev); + if (!bacmp(bdaddr, BDADDR_ANY)) { + hci_blacklist_clear(hdev); + return 0; + } entry = hci_blacklist_lookup(hdev, bdaddr, type); if (!entry) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 473f8687b28b..fbb76a0de580 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2073,7 +2073,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, } if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { - err = hci_uuids_clear(hdev); + hci_uuids_clear(hdev); if (enable_service_cache(hdev)) { err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, From c51ffa0b2fb23ec19b2d01597506d8c953ed1218 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 17:14:33 +0200 Subject: [PATCH 106/139] Bluetooth: Fix hci_remove_ltk failure when no match is found There is code (in mgmt.c) that depends on the hci_remove_ltk function to fail if no match is found. This patch adds tracking of removed LTKs (there can be up to two: one for master and another for slave) in the hci_remove_ltk function and returns -ENOENT of no matches were found. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fd5bb4086613..69b7145bfce2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2807,6 +2807,7 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type) { struct smp_ltk *k, *tmp; + int removed = 0; list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { if (bacmp(bdaddr, &k->bdaddr) || k->bdaddr_type != bdaddr_type) @@ -2816,9 +2817,10 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type) list_del(&k->list); kfree(k); + removed++; } - return 0; + return removed ? 0 : -ENOENT; } /* HCI command timer function */ From b7d448d74a09af412d778918415fe2ea4d5c2de4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 17:14:34 +0200 Subject: [PATCH 107/139] Bluetooth: Fix completing SMP as peripheral when no keys are expected When we're the acceptors (peripheral/slave) of an SMP procedure and we've completed distributing our keys we should only stick around waiting for keys from the remote side if any of the initiator distribution bits were actually set. This patch fixes the smp_distribute_keys function to clear the SMP context when this situation occurs. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 5867c1c3f436..0c0dd1b52b66 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1175,7 +1175,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) *keydist &= ~SMP_DIST_SIGN; } - if (conn->hcon->out || force) { + if (conn->hcon->out || force || !(rsp->init_key_dist & 0x07)) { clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); From a7ec73386ce2a8ab351ee8ab6a1e5475f72617dc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 17:14:35 +0200 Subject: [PATCH 108/139] Bluetooth: Fix removing any IRKs when unpairing devices When mgmt_unpair_device is called we should also remove any associated IRKs. This patch adds a hci_remove_irk convenience function and ensures that it's called when mgmt_unpair_device is called. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 15 +++++++++++++++ net/bluetooth/mgmt.c | 2 ++ 3 files changed, 18 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 964a7888ad0c..ac468de11cb7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -801,6 +801,7 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type); int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 val[16], bdaddr_t *rpa); +void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type); void hci_smp_irks_clear(struct hci_dev *hdev); void hci_remote_oob_data_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 69b7145bfce2..cdba4709f012 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2823,6 +2823,21 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type) return removed ? 0 : -ENOENT; } +void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type) +{ + struct smp_irk *k, *tmp; + + list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { + if (bacmp(bdaddr, &k->bdaddr) || k->addr_type != addr_type) + continue; + + BT_DBG("%s removing %pMR", hdev->name, bdaddr); + + list_del(&k->list); + kfree(k); + } +} + /* HCI command timer function */ static void hci_cmd_timeout(unsigned long arg) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index fbb76a0de580..90aac905a98b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2328,6 +2328,8 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, else addr_type = ADDR_LE_DEV_RANDOM; + hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type); + err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type); } From 2426f3a5945ce1dfdb04aaf26748a987be49ff7c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 17:14:36 +0200 Subject: [PATCH 109/139] Bluetooth: Add convenience function for fetching IRKs There are many situations where we need to check if an LE address is an RPA and if so try to look up the IRK for it. To simplify such cases this patch adds a convenience function for the job. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ac468de11cb7..4461c0051228 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1083,6 +1083,15 @@ static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type) return false; } +static inline struct smp_irk *hci_get_irk(struct hci_dev *hdev, + bdaddr_t *bdaddr, u8 addr_type) +{ + if (!hci_bdaddr_is_rpa(bdaddr, addr_type)) + return NULL; + + return hci_find_irk_by_rpa(hdev, bdaddr); +} + int hci_register_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb); From b075dd40c95d11c2c8690f6c4d6232fc0d9e7f56 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 18 Feb 2014 02:19:26 -0300 Subject: [PATCH 110/139] Bluetooth: allocate static minor for vhci Commit bfacbb9 (Bluetooth: Use devname:vhci module alias for virtual HCI driver) added the module alias to hci_vhci module so it's possible to create the /dev/vhci node. However creating an alias without specifying the minor doesn't allow us to create the node ahead, triggerring module auto-load when it's first accessed. Starting with depmod from kmod 16 we started to warn if there's a devname alias without specifying the major and minor. Let's do the same done for uhid, kvm, fuse and others, specifying a fixed minor. In systems with systemd as the init the following will happen: on early boot systemd will call "kmod static-nodes" to read /lib/modules/$(uname -r)/modules.devname and then create the nodes. When first accessed these "dead" nodes will trigger the module loading. Signed-off-by: Lucas De Marchi Acked-by: Greg Kroah-Hartman Signed-off-by: Marcel Holtmann --- Documentation/devices.txt | 1 + drivers/bluetooth/hci_vhci.c | 3 ++- include/linux/miscdevice.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devices.txt b/Documentation/devices.txt index 10378cc48374..04356f5bc3af 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -353,6 +353,7 @@ Your cooperation is appreciated. 133 = /dev/exttrp External device trap 134 = /dev/apm_bios Advanced Power Management BIOS 135 = /dev/rtc Real Time Clock + 137 = /dev/vhci Bluetooth virtual HCI driver 139 = /dev/openprom SPARC OpenBoot PROM 140 = /dev/relay8 Berkshire Products Octal relay card 141 = /dev/relay16 Berkshire Products ISO-16 relay card diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 1ef6990a5c7e..add1c6a72063 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -359,7 +359,7 @@ static const struct file_operations vhci_fops = { static struct miscdevice vhci_miscdev= { .name = "vhci", .fops = &vhci_fops, - .minor = MISC_DYNAMIC_MINOR, + .minor = VHCI_MINOR, }; static int __init vhci_init(void) @@ -385,3 +385,4 @@ MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); MODULE_ALIAS("devname:vhci"); +MODULE_ALIAS_MISCDEV(VHCI_MINOR); diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index 3737f7218f51..7bb6148d990f 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -23,6 +23,7 @@ #define TEMP_MINOR 131 /* Temperature Sensor */ #define RTC_MINOR 135 #define EFI_RTC_MINOR 136 /* EFI Time services */ +#define VHCI_MINOR 137 #define SUN_OPENPROM_MINOR 139 #define DMAPI_MINOR 140 /* DMAPI */ #define NVRAM_MINOR 144 From 0b8800623d3f12dd40a039aa191d52bfa4eef5b4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Feb 2014 18:26:19 +0200 Subject: [PATCH 111/139] Bluetooth: sort the list of IDs in the source code This will help to manage table of supported IDs. There is no functional change. Signed-off-by: Andy Shevchenko Signed-off-by: Marcel Holtmann --- drivers/bluetooth/ath3k.c | 80 +++++++++++++++++++-------------------- drivers/bluetooth/btusb.c | 52 ++++++++++++------------- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 41ec6f9a8252..fc93ade5fcac 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -62,52 +62,52 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0CF3, 0x3000) }, /* Atheros AR3011 with sflash firmware*/ + { USB_DEVICE(0x0489, 0xE027) }, + { USB_DEVICE(0x0489, 0xE03D) }, + { USB_DEVICE(0x0930, 0x0215) }, { USB_DEVICE(0x0CF3, 0x3002) }, { USB_DEVICE(0x0CF3, 0xE019) }, { USB_DEVICE(0x13d3, 0x3304) }, - { USB_DEVICE(0x0930, 0x0215) }, - { USB_DEVICE(0x0489, 0xE03D) }, - { USB_DEVICE(0x0489, 0xE027) }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03F0, 0x311D) }, /* Atheros AR3012 with sflash firmware*/ + { USB_DEVICE(0x0489, 0xe04d) }, + { USB_DEVICE(0x0489, 0xe04e) }, + { USB_DEVICE(0x0489, 0xe057) }, + { USB_DEVICE(0x0489, 0xe056) }, + { USB_DEVICE(0x0489, 0xe05f) }, + { USB_DEVICE(0x04c5, 0x1330) }, + { USB_DEVICE(0x04CA, 0x3004) }, + { USB_DEVICE(0x04CA, 0x3005) }, + { USB_DEVICE(0x04CA, 0x3006) }, + { USB_DEVICE(0x04CA, 0x3008) }, + { USB_DEVICE(0x04CA, 0x300b) }, + { USB_DEVICE(0x0930, 0x0219) }, + { USB_DEVICE(0x0930, 0x0220) }, { USB_DEVICE(0x0CF3, 0x0036) }, { USB_DEVICE(0x0CF3, 0x3004) }, { USB_DEVICE(0x0CF3, 0x3008) }, { USB_DEVICE(0x0CF3, 0x311D) }, { USB_DEVICE(0x0CF3, 0x311E) }, { USB_DEVICE(0x0CF3, 0x311F) }, + { USB_DEVICE(0x0cf3, 0x3121) }, { USB_DEVICE(0x0CF3, 0x817a) }, - { USB_DEVICE(0x13d3, 0x3375) }, - { USB_DEVICE(0x04CA, 0x3004) }, - { USB_DEVICE(0x04CA, 0x3005) }, - { USB_DEVICE(0x04CA, 0x3006) }, - { USB_DEVICE(0x04CA, 0x3008) }, - { USB_DEVICE(0x04CA, 0x300b) }, - { USB_DEVICE(0x13d3, 0x3362) }, + { USB_DEVICE(0x0cf3, 0xe003) }, { USB_DEVICE(0x0CF3, 0xE004) }, { USB_DEVICE(0x0CF3, 0xE005) }, - { USB_DEVICE(0x0930, 0x0219) }, - { USB_DEVICE(0x0930, 0x0220) }, - { USB_DEVICE(0x0489, 0xe057) }, + { USB_DEVICE(0x13d3, 0x3362) }, + { USB_DEVICE(0x13d3, 0x3375) }, { USB_DEVICE(0x13d3, 0x3393) }, - { USB_DEVICE(0x0489, 0xe04e) }, - { USB_DEVICE(0x0489, 0xe056) }, - { USB_DEVICE(0x0489, 0xe04d) }, - { USB_DEVICE(0x04c5, 0x1330) }, { USB_DEVICE(0x13d3, 0x3402) }, - { USB_DEVICE(0x0cf3, 0x3121) }, - { USB_DEVICE(0x0cf3, 0xe003) }, - { USB_DEVICE(0x0489, 0xe05f) }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, /* Atheros AR5BBU22 with sflash firmware */ - { USB_DEVICE(0x0489, 0xE03C) }, { USB_DEVICE(0x0489, 0xE036) }, + { USB_DEVICE(0x0489, 0xE03C) }, { } /* Terminating entry */ }; @@ -120,38 +120,38 @@ MODULE_DEVICE_TABLE(usb, ath3k_table); static const struct usb_device_id ath3k_blist_tbl[] = { /* Atheros AR3012 with sflash firmware*/ + { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311F), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU22 with sflash firmware */ - { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, { } /* Terminating entry */ }; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e5680fa173c2..46640e98fa03 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -101,16 +101,16 @@ static const struct usb_device_id btusb_table[] = { { USB_DEVICE(0x0c10, 0x0000) }, /* Broadcom BCM20702A0 */ + { USB_DEVICE(0x0489, 0xe042) }, + { USB_DEVICE(0x04ca, 0x2003) }, { USB_DEVICE(0x0b05, 0x17b5) }, { USB_DEVICE(0x0b05, 0x17cb) }, - { USB_DEVICE(0x04ca, 0x2003) }, - { USB_DEVICE(0x0489, 0xe042) }, { USB_DEVICE(0x413c, 0x8197) }, /* Foxconn - Hon Hai */ { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) }, - /*Broadcom devices with vendor specific id */ + /* Broadcom devices with vendor specific id */ { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, /* Belkin F8065bf - Broadcom based */ @@ -132,57 +132,57 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE }, /* Atheros 3011 with sflash firmware */ + { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE }, - { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE }, - { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE }, - { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, /* Atheros 3012 with sflash firmware */ + { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311f), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, /* Atheros AR5BBU12 with sflash firmware */ - { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, /* Broadcom BCM2035 */ - { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, + { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, /* Broadcom BCM2045 */ { USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU }, From a735f9e22432899cee188d167966782c29246390 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 18 Feb 2014 18:26:20 +0200 Subject: [PATCH 112/139] Bluetooth: append new supported device to the list [0b05:17d0] The device found on Asus Z87 Expert motherboard requires firmware to work correctly. T: Bus=03 Lev=01 Prnt=01 Port=03 Cnt=02 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0b05 ProdID=17d0 Rev=00.02 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Signed-off-by: Andy Shevchenko Signed-off-by: Marcel Holtmann --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index fc93ade5fcac..4f78a9d39dc8 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -86,6 +86,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x04CA, 0x300b) }, { USB_DEVICE(0x0930, 0x0219) }, { USB_DEVICE(0x0930, 0x0220) }, + { USB_DEVICE(0x0b05, 0x17d0) }, { USB_DEVICE(0x0CF3, 0x0036) }, { USB_DEVICE(0x0CF3, 0x3004) }, { USB_DEVICE(0x0CF3, 0x3008) }, @@ -133,6 +134,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 46640e98fa03..199b9d42489c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -156,6 +156,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, From 893ce8b1b3d92cbddcf34bb92c7d24720efc7fed Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:31 +0200 Subject: [PATCH 113/139] Bluetooth: Remove SMP data specific crypto context Now that each HCI device has its own AES crypto context we don't need the one stored in the SMP data any more. This patch removes the variable from struct smp_chan and updates the SMP code to use the per-hdev crypto context. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 27 +++++++++++++++------------ net/bluetooth/smp.h | 1 - 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 0c0dd1b52b66..8517d1f0984d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -413,20 +413,16 @@ 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 hci_dev *hdev = conn->hcon->hdev; + struct crypto_blkcipher *tfm = hdev->tfm_aes; 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; + /* Prevent mutual access to hdev->tfm_aes */ + hci_dev_lock(hdev); if (conn->hcon->out) ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, @@ -436,6 +432,9 @@ static void confirm_work(struct work_struct *work) ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, conn->hcon->dst_type, &conn->hcon->dst, conn->hcon->src_type, &conn->hcon->src, res); + + hci_dev_unlock(hdev); + if (ret) { reason = SMP_UNSPECIFIED; goto error; @@ -457,7 +456,8 @@ 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; + struct hci_dev *hdev = hcon->hdev; + struct crypto_blkcipher *tfm = hdev->tfm_aes; u8 reason, confirm[16], res[16], key[16]; int ret; @@ -468,6 +468,9 @@ static void random_work(struct work_struct *work) BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); + /* Prevent mutual access to hdev->tfm_aes */ + hci_dev_lock(hdev); + if (hcon->out) ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, hcon->src_type, &hcon->src, @@ -476,6 +479,9 @@ static void random_work(struct work_struct *work) ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, hcon->dst_type, &hcon->dst, hcon->src_type, &hcon->src, res); + + hci_dev_unlock(hdev); + if (ret) { reason = SMP_UNSPECIFIED; goto error; @@ -562,9 +568,6 @@ void smp_chan_destroy(struct l2cap_conn *conn) BUG_ON(!smp); - if (smp->tfm) - crypto_free_blkcipher(smp->tfm); - kfree(smp); conn->smp_chan = NULL; conn->hcon->smp_conn = NULL; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 4f373bc56ad7..8f54c9b152de 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -133,7 +133,6 @@ struct smp_chan { u8 id_addr_type; u8 irk[16]; unsigned long smp_flags; - struct crypto_blkcipher *tfm; struct work_struct confirm; struct work_struct random; }; From 68d6f6ded5bdaa89f9da0144359a7c5565991f8d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:32 +0200 Subject: [PATCH 114/139] Bluetooth: Track the LE Identity Address in struct hci_conn Since we want user space to see and use the LE Identity Address whenever interfacing with the kernel it makes sense to track that instead of the real address (the two will only be different in the case of an RPA). This patch adds the necessary updates to when an LE connection gets established and when receiving the Identity Address from a remote device. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 8 ++++++++ net/bluetooth/smp.c | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d2c6878a9d6a..49a2d4d841df 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3568,6 +3568,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_le_conn_complete *ev = (void *) skb->data; struct hci_conn *conn; + struct smp_irk *irk; BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); @@ -3600,6 +3601,13 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) } } + /* Track the connection based on the Identity Address from now on */ + irk = hci_get_irk(hdev, &ev->bdaddr, ev->bdaddr_type); + if (irk) { + bacpy(&conn->dst, &irk->bdaddr); + conn->dst_type = irk->addr_type; + } + if (ev->status) { mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type, ev->status); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 8517d1f0984d..af29afed0cca 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -987,6 +987,10 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, hci_add_irk(conn->hcon->hdev, &smp->id_addr, smp->id_addr_type, smp->irk, &rpa); + /* Track the connection based on the Identity Address from now on */ + bacpy(&hcon->dst, &smp->id_addr); + hcon->dst_type = smp->id_addr_type; + smp_distribute_keys(conn, 1); return 0; From 387a33e304caeeabf0c2439607fa6e726666bdf0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:33 +0200 Subject: [PATCH 115/139] Bluetooth: Fix updating Identity Address in L2CAP channels When we receive a remote identity address during SMP key distribution we should ensure that any associated L2CAP channel instances get their address information correspondingly updated (so that e.g. doing getpeername on associated sockets returns the correct address). This patch adds a new L2CAP core function l2cap_conn_update_id_addr() which is used to iterate through all L2CAP channels associated with a connection and update their address information. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 17 +++++++++++++++++ net/bluetooth/smp.c | 2 ++ 3 files changed, 20 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 13bec91785f4..4abdcb220e3a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -881,6 +881,7 @@ int l2cap_ertm_init(struct l2cap_chan *chan); void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); void l2cap_chan_del(struct l2cap_chan *chan, int err); +void l2cap_conn_update_id_addr(struct hci_conn *hcon); void l2cap_send_conn_req(struct l2cap_chan *chan); void l2cap_move_start(struct l2cap_chan *chan); void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6e6b3a9c8e6d..c3bda6445f3d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -609,6 +609,23 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) return; } +void l2cap_conn_update_id_addr(struct hci_conn *hcon) +{ + struct l2cap_conn *conn = hcon->l2cap_data; + struct l2cap_chan *chan; + + mutex_lock(&conn->chan_lock); + + list_for_each_entry(chan, &conn->chan_l, list) { + l2cap_chan_lock(chan); + bacpy(&chan->dst, &hcon->dst); + chan->dst_type = bdaddr_type(hcon, hcon->dst_type); + l2cap_chan_unlock(chan); + } + + mutex_unlock(&conn->chan_lock); +} + static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index af29afed0cca..b6a2a8942b2d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -991,6 +991,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, bacpy(&hcon->dst, &smp->id_addr); hcon->dst_type = smp->id_addr_type; + l2cap_conn_update_id_addr(hcon); + smp_distribute_keys(conn, 1); return 0; From f4a407bef20c0e63fcd910a9404418522abff4ab Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:34 +0200 Subject: [PATCH 116/139] Bluetooth: Wait for SMP key distribution completion when pairing When we initiate pairing through mgmt_pair_device the code has so far been waiting for a successful HCI Encrypt Change event in order to respond to the mgmt command. However, putting privacy into the play we actually want the key distribution to be complete before replying so that we can include the Identity Address in the mgmt response. This patch updates the various hci_conn callbacks for LE in mgmt.c to only respond in the case of failure, and adds a new mgmt_smp_complete function that the SMP code will call once key distribution has been completed. Since the smp_chan_destroy function that's used to indicate completion and clean up the SMP context can be called from various places, including outside of smp.c, the easiest way to track failure vs success is a new flag that we set once key distribution has been successfully completed. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/mgmt.c | 25 +++++++++++++++++++------ net/bluetooth/smp.c | 5 +++++ net/bluetooth/smp.h | 1 + 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4461c0051228..64c4e3f0a515 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1212,6 +1212,7 @@ int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent); void mgmt_reenable_advertising(struct hci_dev *hdev); +void mgmt_smp_complete(struct hci_conn *conn, bool complete); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 90aac905a98b..24a85fe76cd8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2655,6 +2655,16 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) mgmt_pending_remove(cmd); } +void mgmt_smp_complete(struct hci_conn *conn, bool complete) +{ + u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED; + struct pending_cmd *cmd; + + cmd = find_pairing(conn); + if (cmd) + pairing_complete(cmd, status); +} + static void pairing_complete_cb(struct hci_conn *conn, u8 status) { struct pending_cmd *cmd; @@ -2668,7 +2678,7 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) pairing_complete(cmd, mgmt_status(status)); } -static void le_connect_complete_cb(struct hci_conn *conn, u8 status) +static void le_pairing_complete_cb(struct hci_conn *conn, u8 status) { struct pending_cmd *cmd; @@ -2755,13 +2765,16 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, } /* For LE, just connecting isn't a proof that the pairing finished */ - if (cp->addr.type == BDADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) { conn->connect_cfm_cb = pairing_complete_cb; - else - conn->connect_cfm_cb = le_connect_complete_cb; + conn->security_cfm_cb = pairing_complete_cb; + conn->disconn_cfm_cb = pairing_complete_cb; + } else { + conn->connect_cfm_cb = le_pairing_complete_cb; + conn->security_cfm_cb = le_pairing_complete_cb; + conn->disconn_cfm_cb = le_pairing_complete_cb; + } - conn->security_cfm_cb = pairing_complete_cb; - conn->disconn_cfm_cb = pairing_complete_cb; conn->io_capability = cp->io_cap; cmd->user_data = conn; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index b6a2a8942b2d..27eebca260fa 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -565,9 +565,13 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) void smp_chan_destroy(struct l2cap_conn *conn) { struct smp_chan *smp = conn->smp_chan; + bool complete; BUG_ON(!smp); + complete = test_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); + mgmt_smp_complete(conn->hcon, complete); + kfree(smp); conn->smp_chan = NULL; conn->hcon->smp_conn = NULL; @@ -1187,6 +1191,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) if (conn->hcon->out || force || !(rsp->init_key_dist & 0x07)) { clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); cancel_delayed_work_sync(&conn->security_timer); + set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); smp_chan_destroy(conn); } diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 8f54c9b152de..675fd3b21d2c 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -118,6 +118,7 @@ struct smp_cmd_security_req { #define SMP_FLAG_TK_VALID 1 #define SMP_FLAG_CFM_PENDING 2 #define SMP_FLAG_MITM_AUTH 3 +#define SMP_FLAG_COMPLETE 4 struct smp_chan { struct l2cap_conn *conn; From 6cfc9988bd3e5d2931365da76db9b5a7334494b6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:35 +0200 Subject: [PATCH 117/139] Bluetooth: Don't try to look up private addresses as Identity Address Identity Addresses are either public or static random. When looking up addresses based on the Identity Address it doesn't make sense to go through the IRK list if we're given a private random address. This patch fixes (or rather improves) the hci_find_irk_by_addr function to bail out early if given a private random address. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cdba4709f012..e4c5b9d6083c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2662,6 +2662,10 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, { struct smp_irk *irk; + /* Identity Address must be public or static random */ + if (addr_type == ADDR_LE_DEV_RANDOM && (bdaddr->b[5] & 0xc0) != 0xc0) + return NULL; + list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { if (addr_type == irk->addr_type && bacmp(bdaddr, &irk->bdaddr) == 0) From 1ebfcc1f5884509925522ab76c17db9befe0aac9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:36 +0200 Subject: [PATCH 118/139] Bluetooth: Look up RPA for connection requests with Identity Address We need to check whether there's a matching IRK and RPA when we're requested to connect to a remote LE device based on its Identity Address. This patch updates the hci_connect_le function to do an extra call to hci_find_irk_by_addr and uses the RPA if it's cached. This is particularly important once we start exposing the Identity Address to user space instead of the RPA in events such as Device Connected and Device Found. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 67972928a623..40ec37355d6f 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -588,6 +588,7 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, { struct hci_conn_params *params; struct hci_conn *conn; + struct smp_irk *irk; int err; if (test_bit(HCI_ADVERTISING, &hdev->flags)) @@ -616,15 +617,23 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, if (conn) return ERR_PTR(-EBUSY); + /* Convert from L2CAP channel address type to HCI address type */ + if (dst_type == BDADDR_LE_PUBLIC) + dst_type = ADDR_LE_DEV_PUBLIC; + else + dst_type = ADDR_LE_DEV_RANDOM; + + irk = hci_find_irk_by_addr(hdev, dst, dst_type); + if (irk && bacmp(&irk->rpa, BDADDR_ANY)) { + dst = &irk->rpa; + dst_type = ADDR_LE_DEV_RANDOM; + } + conn = hci_conn_add(hdev, LE_LINK, dst); if (!conn) return ERR_PTR(-ENOMEM); - if (dst_type == BDADDR_LE_PUBLIC) - conn->dst_type = ADDR_LE_DEV_PUBLIC; - else - conn->dst_type = ADDR_LE_DEV_RANDOM; - + conn->dst_type = dst_type; conn->src_type = hdev->own_addr_type; conn->state = BT_CONNECT; From 5cedbb8d7aee79a8bbfc8e5b91bc1353ffb0f7b0 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 18 Feb 2014 21:41:37 +0200 Subject: [PATCH 119/139] Bluetooth: Use Identity Address in Device Found event Whenever a device uses an RPA we want to have user space identify it by its Identity Address if we've got an IRK available for it. This patch updates the Device Found mgmt event to contain the Identity Address if an IRK is available for the device in question. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 24a85fe76cd8..747cb9bbc331 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -5325,6 +5325,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, { char buf[512]; struct mgmt_ev_device_found *ev = (void *) buf; + struct smp_irk *irk; size_t ev_size; if (!hci_discovery_active(hdev)) @@ -5336,8 +5337,15 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, memset(buf, 0, sizeof(buf)); - bacpy(&ev->addr.bdaddr, bdaddr); - ev->addr.type = link_to_bdaddr(link_type, addr_type); + irk = hci_get_irk(hdev, bdaddr, addr_type); + if (irk) { + bacpy(&ev->addr.bdaddr, &irk->bdaddr); + ev->addr.type = link_to_bdaddr(link_type, irk->addr_type); + } else { + bacpy(&ev->addr.bdaddr, bdaddr); + ev->addr.type = link_to_bdaddr(link_type, addr_type); + } + ev->rssi = rssi; if (cfm_name) ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME); From 2c96e03def3b1ba47a5d0ec0c8ef7935a9bfb3a0 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 18 Feb 2014 20:48:34 +0100 Subject: [PATCH 120/139] Bluetooth: Print error when dropping L2CAP data Silently dropping L2CAP data (i.e. due to remote device not obeying negotiated MTU) is confusing and makes debugging harder. Signed-off-by: Szymon Janc Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c3bda6445f3d..6ace116f3b39 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6776,8 +6776,10 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, * But we don't have any other choice. L2CAP doesn't * provide flow control mechanism. */ - if (chan->imtu < skb->len) + if (chan->imtu < skb->len) { + BT_ERR("Dropping L2CAP data: receive buffer overflow"); goto drop; + } if (!chan->ops->recv(chan, skb)) goto done; From 01fdb0fc6e937eeff7b20d0e217408cee9ec05af Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 18 Feb 2014 14:22:19 -0800 Subject: [PATCH 121/139] Bluetooth: Report identity address when remote device connects When the remote device has been successfully connected, report the identity address (public address or static random address). Currently the address from the HCI_LE_Connection_Complete event is used. This was no problem so far, but since now known resolvable random addresses are converted into identities, it is important to use the identity of the connection and not the address report by HCI event. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 49a2d4d841df..d7c709519e31 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3618,7 +3618,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) } if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) - mgmt_device_connected(hdev, &ev->bdaddr, conn->type, + mgmt_device_connected(hdev, &conn->dst, conn->type, conn->dst_type, 0, NULL, 0, NULL); conn->sec_level = BT_SECURITY_LOW; From 64c7b77c124c71166d1dd49fc7e8d6fee7d9b01b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 18 Feb 2014 14:22:20 -0800 Subject: [PATCH 122/139] Bluetooth: Use connection address for reporting connection failures When reporting connect failed events to userspace, use the address of the connection and not the address from the HCI event. This change is strictly speaking not needed since BR/EDR does not have the concept of resolvable random addresses. It is more for making the code consistent. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d7c709519e31..22bfc5c17e7f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1704,7 +1704,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) } else { conn->state = BT_CLOSED; if (conn->type == ACL_LINK) - mgmt_connect_failed(hdev, &ev->bdaddr, conn->type, + mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type, ev->status); } From edb4b46651c87f1579154298c41f9c1a753565a3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 18 Feb 2014 15:13:43 -0800 Subject: [PATCH 123/139] Bluetooth: Fix wrong identity address during connection failures When the connection attempt fails, the address information are not provided in the HCI_LE_Connection_Complete event. So use the original information from the connection to reconstruct the identity address. This is important when a connection attempt has been made using the identity address, but the cached resolvable random address has changed in the meantime. The failure event needs to use the identity address and not the resolvable random address. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 13 +++++++++++++ net/bluetooth/hci_event.c | 12 ++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 40ec37355d6f..a027951d0da5 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -623,6 +623,19 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, else dst_type = ADDR_LE_DEV_RANDOM; + /* When given an identity address with existing identity + * resolving key, the connection needs to be established + * to a resolvable random address. + * + * This uses the cached random resolvable address from + * a previous scan. When no cached address is available, + * try connecting to the identity address instead. + * + * Storing the resolvable random address is required here + * to handle connection failures. The address will later + * be resolved back into the original identity address + * from the connect request. + */ irk = hci_find_irk_by_addr(hdev, dst, dst_type); if (irk && bacmp(&irk->rpa, BDADDR_ANY)) { dst = &irk->rpa; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 22bfc5c17e7f..7228fa100b1f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3601,8 +3601,16 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) } } - /* Track the connection based on the Identity Address from now on */ - irk = hci_get_irk(hdev, &ev->bdaddr, ev->bdaddr_type); + /* Lookup the identity address from the stored connection + * address and address type. + * + * When establishing connections to an identity address, the + * connection procedure will store the resolvable random + * address first. Now if it can be converted back into the + * identity address, start using the identity address from + * now on. + */ + irk = hci_get_irk(hdev, &conn->dst, conn->dst_type); if (irk) { bacpy(&conn->dst, &irk->bdaddr); conn->dst_type = irk->addr_type; From 3698d70469d165d01fefcad9a56172742157ff95 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 18 Feb 2014 21:54:49 -0800 Subject: [PATCH 124/139] Bluetooth: Expose current list of identity resolving keys via debugfs For debugging purposes expose the current list of identity resolving keys via debugfs. This file is read-only and limited to root access. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e4c5b9d6083c..e8f61b3fe87c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -599,6 +599,36 @@ static int own_address_type_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(own_address_type_fops, own_address_type_get, own_address_type_set, "%llu\n"); +static int identity_resolving_keys_show(struct seq_file *f, void *ptr) +{ + struct hci_dev *hdev = f->private; + struct list_head *p, *n; + + hci_dev_lock(hdev); + list_for_each_safe(p, n, &hdev->identity_resolving_keys) { + struct smp_irk *irk = list_entry(p, struct smp_irk, list); + seq_printf(f, "%pMR (type %u) %*phN %pMR\n", + &irk->bdaddr, irk->addr_type, + 16, irk->val, &irk->rpa); + } + hci_dev_unlock(hdev); + + return 0; +} + +static int identity_resolving_keys_open(struct inode *inode, struct file *file) +{ + return single_open(file, identity_resolving_keys_show, + inode->i_private); +} + +static const struct file_operations identity_resolving_keys_fops = { + .open = identity_resolving_keys_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int long_term_keys_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; @@ -1512,6 +1542,9 @@ static int __hci_init(struct hci_dev *hdev) hdev, &static_address_fops); debugfs_create_file("own_address_type", 0644, hdev->debugfs, hdev, &own_address_type_fops); + debugfs_create_file("identity_resolving_keys", 0400, + hdev->debugfs, hdev, + &identity_resolving_keys_fops); debugfs_create_file("long_term_keys", 0400, hdev->debugfs, hdev, &long_term_keys_fops); debugfs_create_file("conn_min_interval", 0644, hdev->debugfs, From d66c295031aec712e179d21de66602d631390f34 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 18 Feb 2014 22:27:14 -0800 Subject: [PATCH 125/139] Bluetooth: Use same LE min/max connection event length during update During LE connection establishment the value 0x0000 is used for min/max connection event length. So use the same value when the peripheral is requesting an update of the the connection paramters. For some reason the value 0x0001 got used in the connection update and 0x0000 in the connection creation. Using the same value for both just makes sense. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_conn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index a027951d0da5..bd66c52eff95 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -225,8 +225,8 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, cp.conn_interval_max = cpu_to_le16(max); cp.conn_latency = cpu_to_le16(latency); cp.supervision_timeout = cpu_to_le16(to_multiplier); - cp.min_ce_len = __constant_cpu_to_le16(0x0001); - cp.max_ce_len = __constant_cpu_to_le16(0x0001); + cp.min_ce_len = __constant_cpu_to_le16(0x0000); + cp.max_ce_len = __constant_cpu_to_le16(0x0000); hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp); } From 0a14ab416d7754be0bb0d4306c996f72f52fa5bf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 19 Feb 2014 14:57:43 +0200 Subject: [PATCH 126/139] Bluetooth: Avoid using GFP_ATOMIC where not necessary The various pieces of data cached in the hci_dev structure do not need to be allocated using GFP_ATOMIC since they are never added from interrupt context. This patch updates these allocations to use GFP_KERNEL instead. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e8f61b3fe87c..7e679e085506 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2721,7 +2721,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, key = old_key; } else { old_key_type = conn ? conn->key_type : 0xff; - key = kzalloc(sizeof(*key), GFP_ATOMIC); + key = kzalloc(sizeof(*key), GFP_KERNEL); if (!key) return -ENOMEM; list_add(&key->list, &hdev->link_keys); @@ -2773,7 +2773,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, if (old_key) key = old_key; else { - key = kzalloc(sizeof(*key), GFP_ATOMIC); + key = kzalloc(sizeof(*key), GFP_KERNEL); if (!key) return -ENOMEM; list_add(&key->list, &hdev->long_term_keys); @@ -2938,7 +2938,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, data = hci_find_remote_oob_data(hdev, bdaddr); if (!data) { - data = kmalloc(sizeof(*data), GFP_ATOMIC); + data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -2965,7 +2965,7 @@ int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr, data = hci_find_remote_oob_data(hdev, bdaddr); if (!data) { - data = kmalloc(sizeof(*data), GFP_ATOMIC); + data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; From ca9142b8825c159897cc4a246ea27585c82add4b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 19 Feb 2014 14:57:44 +0200 Subject: [PATCH 127/139] Bluetooth: Return added key when adding LTKs and IRKs The SMP code will need to postpone the mgmt event emission for the IRK and LTKs. To avoid extra lookups at the end of the key distribution simply return the added value from the add_ltk and add_irk functions. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 11 ++++++----- net/bluetooth/hci_core.c | 21 +++++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 64c4e3f0a515..5366dc9e25eb 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -787,9 +787,10 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8], bool master); -int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], u8 enc_size, - __le16 ediv, u8 rand[8]); +struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type, u8 type, int new_key, + u8 authenticated, u8 tk[16], u8 enc_size, + __le16 ediv, u8 rand[8]); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, bool master); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type); @@ -799,8 +800,8 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa); struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type); -int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, - u8 val[16], bdaddr_t *rpa); +struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type, u8 val[16], bdaddr_t *rpa); void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type); void hci_smp_irks_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7e679e085506..e23c718d668b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2761,9 +2761,10 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, return 0; } -int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], u8 enc_size, __le16 - ediv, u8 rand[8]) +struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type, u8 type, int new_key, + u8 authenticated, u8 tk[16], u8 enc_size, + __le16 ediv, u8 rand[8]) { struct smp_ltk *key, *old_key; bool master = ltk_type_master(type); @@ -2775,7 +2776,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, else { key = kzalloc(sizeof(*key), GFP_KERNEL); if (!key) - return -ENOMEM; + return NULL; list_add(&key->list, &hdev->long_term_keys); } @@ -2789,7 +2790,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, memcpy(key->rand, rand, sizeof(key->rand)); if (!new_key) - return 0; + return key; if (addr_type == ADDR_LE_DEV_RANDOM && (bdaddr->b[5] & 0xc0) != 0xc0) persistent = 0; @@ -2799,11 +2800,11 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, if (type == HCI_SMP_LTK || type == HCI_SMP_LTK_SLAVE) mgmt_new_ltk(hdev, key, persistent); - return 0; + return key; } -int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, - u8 val[16], bdaddr_t *rpa) +struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, + u8 addr_type, u8 val[16], bdaddr_t *rpa) { struct smp_irk *irk; @@ -2811,7 +2812,7 @@ int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, if (!irk) { irk = kzalloc(sizeof(*irk), GFP_KERNEL); if (!irk) - return -ENOMEM; + return NULL; bacpy(&irk->bdaddr, bdaddr); irk->addr_type = addr_type; @@ -2822,7 +2823,7 @@ int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, memcpy(irk->val, val, 16); bacpy(&irk->rpa, rpa); - return 0; + return irk; } int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) From ba74b666b5e581ef3d4912af73774fab48c03198 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 19 Feb 2014 14:57:45 +0200 Subject: [PATCH 128/139] Bluetooth: Move New LTK store hint evaluation into mgmt_new_ltk It's simpler (one less if-statement) to just evaluate the appropriate value for store_hint in the mgmt_new_ltk function than to pass a boolean parameter to the function. Furthermore, this simplifies moving the mgmt event emission out from hci_add_ltk in subsequent patches. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 8 +------- net/bluetooth/mgmt.c | 9 +++++++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5366dc9e25eb..8ca95e5e3765 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1211,7 +1211,7 @@ void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_discovering(struct hci_dev *hdev, u8 discovering); int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); -void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent); +void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key); void mgmt_reenable_advertising(struct hci_dev *hdev); void mgmt_smp_complete(struct hci_conn *conn, bool complete); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e23c718d668b..60c875267c19 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2768,7 +2768,6 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, { struct smp_ltk *key, *old_key; bool master = ltk_type_master(type); - u8 persistent; old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, master); if (old_key) @@ -2792,13 +2791,8 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, if (!new_key) return key; - if (addr_type == ADDR_LE_DEV_RANDOM && (bdaddr->b[5] & 0xc0) != 0xc0) - persistent = 0; - else - persistent = 1; - if (type == HCI_SMP_LTK || type == HCI_SMP_LTK_SLAVE) - mgmt_new_ltk(hdev, key, persistent); + mgmt_new_ltk(hdev, key); return key; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 747cb9bbc331..ad51da1b6dc2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4765,13 +4765,18 @@ void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); } -void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) +void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key) { struct mgmt_ev_new_long_term_key ev; memset(&ev, 0, sizeof(ev)); - ev.store_hint = persistent; + if (key->bdaddr_type == ADDR_LE_DEV_RANDOM && + (key->bdaddr.b[5] & 0xc0) != 0xc0) + ev.store_hint = 0x00; + else + ev.store_hint = 0x01; + bacpy(&ev.key.addr.bdaddr, &key->bdaddr); ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type); ev.key.type = key->authenticated; From 23d0e128e38049734c7ecc0987de02486d1ded3e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 19 Feb 2014 14:57:46 +0200 Subject: [PATCH 129/139] Bluetooth: Track SMP keys in the SMP context As preparation to do mgmt notification in a single place at the end of the key distribution, store the keys that need to be notified within the SMP context. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 21 +++++++++++++-------- net/bluetooth/smp.h | 3 +++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 27eebca260fa..eaac54be91b1 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -915,6 +915,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) struct smp_chan *smp = conn->smp_chan; struct hci_dev *hdev = conn->hcon->hdev; struct hci_conn *hcon = conn->hcon; + struct smp_ltk *ltk; u8 authenticated; BT_DBG("conn %p", conn); @@ -930,9 +931,10 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) hci_dev_lock(hdev); authenticated = (hcon->sec_level == BT_SECURITY_HIGH); - hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, 1, - authenticated, smp->tk, smp->enc_key_size, - rp->ediv, rp->rand); + ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, 1, + authenticated, smp->tk, smp->enc_key_size, + rp->ediv, rp->rand); + smp->ltk = ltk; if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) smp_distribute_keys(conn, 1); hci_dev_unlock(hdev); @@ -988,8 +990,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, else bacpy(&rpa, BDADDR_ANY); - hci_add_irk(conn->hcon->hdev, &smp->id_addr, smp->id_addr_type, - smp->irk, &rpa); + smp->remote_irk = hci_add_irk(conn->hcon->hdev, &smp->id_addr, + smp->id_addr_type, smp->irk, &rpa); /* Track the connection based on the Identity Address from now on */ bacpy(&hcon->dst, &smp->id_addr); @@ -1137,6 +1139,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) struct smp_cmd_encrypt_info enc; struct smp_cmd_master_ident ident; struct hci_conn *hcon = conn->hcon; + struct smp_ltk *ltk; u8 authenticated; __le16 ediv; @@ -1147,9 +1150,11 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); authenticated = hcon->sec_level == BT_SECURITY_HIGH; - hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, - HCI_SMP_LTK_SLAVE, 1, authenticated, - enc.ltk, smp->enc_key_size, ediv, ident.rand); + ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, + HCI_SMP_LTK_SLAVE, 1, authenticated, + enc.ltk, smp->enc_key_size, ediv, + ident.rand); + smp->slave_ltk = ltk; ident.ediv = ediv; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 675fd3b21d2c..d8cc543f523c 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -133,6 +133,9 @@ struct smp_chan { bdaddr_t id_addr; u8 id_addr_type; u8 irk[16]; + struct smp_ltk *ltk; + struct smp_ltk *slave_ltk; + struct smp_irk *remote_irk; unsigned long smp_flags; struct work_struct confirm; struct work_struct random; From 35d702719d6464a9de2bf98d536c6e054f0a8f7e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 19 Feb 2014 14:57:47 +0200 Subject: [PATCH 130/139] Bluetooth: Move SMP LTK notification after key distribution This patch moves the SMP Long Term Key notification over mgmt from the hci_add_ltk function to smp.c when both sides have completed their key distribution. This way we are also able to update the identity address into the mgmt_new_ltk event. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 5 ++--- net/bluetooth/hci_core.c | 11 ++--------- net/bluetooth/mgmt.c | 6 +++--- net/bluetooth/smp.c | 29 ++++++++++++++++++++++++----- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8ca95e5e3765..59ae04c2684f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -788,9 +788,8 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8], bool master); struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type, u8 type, int new_key, - u8 authenticated, u8 tk[16], u8 enc_size, - __le16 ediv, u8 rand[8]); + u8 addr_type, u8 type, u8 authenticated, + u8 tk[16], u8 enc_size, __le16 ediv, u8 rand[8]); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, bool master); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 60c875267c19..3711c7626cb2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2762,9 +2762,8 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, } struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type, u8 type, int new_key, - u8 authenticated, u8 tk[16], u8 enc_size, - __le16 ediv, u8 rand[8]) + u8 addr_type, u8 type, u8 authenticated, + u8 tk[16], u8 enc_size, __le16 ediv, u8 rand[8]) { struct smp_ltk *key, *old_key; bool master = ltk_type_master(type); @@ -2788,12 +2787,6 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, key->type = type; memcpy(key->rand, rand, sizeof(key->rand)); - if (!new_key) - return key; - - if (type == HCI_SMP_LTK || type == HCI_SMP_LTK_SLAVE) - mgmt_new_ltk(hdev, key); - return key; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ad51da1b6dc2..bcfc6da67a5c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4330,9 +4330,9 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, else type = HCI_SMP_LTK_SLAVE; - hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, - type, 0, key->type, key->val, - key->enc_size, key->ediv, key->rand); + hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type, + key->type, key->val, key->enc_size, key->ediv, + key->rand); } err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0, diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index eaac54be91b1..f05c1b71d99a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -532,7 +532,7 @@ static void random_work(struct work_struct *work) SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, - HCI_SMP_STK_SLAVE, 0, 0, stk, smp->enc_key_size, + HCI_SMP_STK_SLAVE, 0, stk, smp->enc_key_size, ediv, rand); } @@ -931,7 +931,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) hci_dev_lock(hdev); authenticated = (hcon->sec_level == BT_SECURITY_HIGH); - ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, 1, + ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, authenticated, smp->tk, smp->enc_key_size, rp->ediv, rp->rand); smp->ltk = ltk; @@ -1106,6 +1106,25 @@ done: return err; } +static void smp_notify_keys(struct l2cap_conn *conn) +{ + struct smp_chan *smp = conn->smp_chan; + struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; + + if (smp->ltk) { + smp->ltk->bdaddr_type = hcon->dst_type; + bacpy(&smp->ltk->bdaddr, &hcon->dst); + mgmt_new_ltk(hdev, smp->ltk); + } + + if (smp->slave_ltk) { + smp->slave_ltk->bdaddr_type = hcon->dst_type; + bacpy(&smp->slave_ltk->bdaddr, &hcon->dst); + mgmt_new_ltk(hdev, smp->slave_ltk); + } +} + int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) { struct smp_cmd_pairing *req, *rsp; @@ -1151,9 +1170,8 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) authenticated = hcon->sec_level == BT_SECURITY_HIGH; ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, - HCI_SMP_LTK_SLAVE, 1, authenticated, - enc.ltk, smp->enc_key_size, ediv, - ident.rand); + HCI_SMP_LTK_SLAVE, authenticated, enc.ltk, + smp->enc_key_size, ediv, ident.rand); smp->slave_ltk = ltk; ident.ediv = ediv; @@ -1197,6 +1215,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags); cancel_delayed_work_sync(&conn->security_timer); set_bit(SMP_FLAG_COMPLETE, &smp->smp_flags); + smp_notify_keys(conn); smp_chan_destroy(conn); } From 95fbac8a8e459262c580ee4172e4713cdc60929b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 19 Feb 2014 15:18:31 +0200 Subject: [PATCH 131/139] Bluetooth: Add support for sending New IRK event This patch adds the necessary helper function to send the New IRK mgmt event and makes sure that the function is called at when SMP key distribution has completed. The event is sent before the New LTK event so user space knows which remote device to associate with the keys. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/mgmt.h | 7 +++++++ net/bluetooth/mgmt.c | 15 +++++++++++++++ net/bluetooth/smp.c | 3 +++ 4 files changed, 26 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 59ae04c2684f..3be2905010cd 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1211,6 +1211,7 @@ void mgmt_discovering(struct hci_dev *hdev, u8 discovering); int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key); +void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk); void mgmt_reenable_advertising(struct hci_dev *hdev); void mgmt_smp_complete(struct hci_conn *conn, bool complete); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index e4fa13e559e2..2e46251e8aec 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -536,3 +536,10 @@ struct mgmt_ev_passkey_notify { __le32 passkey; __u8 entered; } __packed; + +#define MGMT_EV_NEW_IRK 0x0018 +struct mgmt_ev_new_irk { + __u8 store_hint; + bdaddr_t rpa; + struct mgmt_irk_info irk; +} __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bcfc6da67a5c..1daa837da091 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4792,6 +4792,21 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key) mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL); } +void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk) +{ + struct mgmt_ev_new_irk ev; + + memset(&ev, 0, sizeof(ev)); + + ev.store_hint = 0x01; + bacpy(&ev.rpa, &irk->rpa); + bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr); + ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type); + memcpy(ev.irk.val, irk->val, sizeof(irk->val)); + + mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL); +} + static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, u8 data_len) { diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index f05c1b71d99a..f06068072bdd 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1112,6 +1112,9 @@ static void smp_notify_keys(struct l2cap_conn *conn) struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; + if (smp->remote_irk) + mgmt_new_irk(hdev, smp->remote_irk); + if (smp->ltk) { smp->ltk->bdaddr_type = hcon->dst_type; bacpy(&smp->ltk->bdaddr, &hcon->dst); From bab6d1e594ef4dd76ee5a369da96d572c43c7489 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 19 Feb 2014 11:51:54 -0800 Subject: [PATCH 132/139] Bluetooth: Don't send store hint for devices using identity addresses The identity resolving keys should only be stored for devices using resolvable random addresses. If the device is already using an identity address, inform it about the new identity resolving key, but tell userspace that this key is not persistent. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1daa837da091..e8b9d2f261ee 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4798,7 +4798,22 @@ void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk) memset(&ev, 0, sizeof(ev)); - ev.store_hint = 0x01; + /* For identity resolving keys from devices that are already + * using a public address or static random address, do not + * ask for storing this key. The identity resolving key really + * is only mandatory for devices using resovlable random + * addresses. + * + * Storing all identity resolving keys has the downside that + * they will be also loaded on next boot of they system. More + * identity resolving keys, means more time during scanning is + * needed to actually resolve these addresses. + */ + if (bacmp(&irk->rpa, BDADDR_ANY)) + ev.store_hint = 0x01; + else + ev.store_hint = 0x00; + bacpy(&ev.rpa, &irk->rpa); bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr); ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type); From 5192d30114771ac5956d750ec506dc574411cc70 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 19 Feb 2014 17:11:58 -0800 Subject: [PATCH 133/139] Bluetooth: Add comment explainging store hint for long term keys The code itself is not descriptive on what store hint is used for long term keys and why. So add some extensive comment here. Similar to what has already been done for identity resolving key store hint. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e8b9d2f261ee..5f5e388716ec 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4771,6 +4771,17 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key) memset(&ev, 0, sizeof(ev)); + /* Devices using resolvable or non-resolvable random addresses + * without providing an indentity resolving key don't require + * to store long term keys. Their addresses will change the + * next time around. + * + * Only when a remote device provides an identity address + * make sure the long term key is stored. If the remote + * identity is known, the long term keys are internally + * mapped to the identity address. So allow static random + * and public addresses here. + */ if (key->bdaddr_type == ADDR_LE_DEV_RANDOM && (key->bdaddr.b[5] & 0xc0) != 0xc0) ev.store_hint = 0x00; From b32bba6ced5696593a6bae5fdc69dc79c0a97ef5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 19 Feb 2014 19:31:26 -0800 Subject: [PATCH 134/139] Bluetooth: Replace own_address_type with force_static_address debugfs The own_address_type debugfs option does not providing enough flexibity for interacting with the upcoming LE privacy support. What really is needed is an option to force using the static address compared to the public address. The new force_static_address debugfs option does exactly that. In addition it is also only available when the controller does actually have a public address. For single mode LE only controllers this option will not be available. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 99 ++++++++++++++++++++++++------------- 2 files changed, 65 insertions(+), 35 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index d3a8fff50f69..fe4b06bfc150 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -118,6 +118,7 @@ enum { HCI_DEBUG_KEYS, HCI_DUT_MODE, HCI_FORCE_SC, + HCI_FORCE_STATIC_ADDR, HCI_UNREGISTER, HCI_USER_CHANNEL, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3711c7626cb2..b25a36c3064b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -571,33 +571,52 @@ static const struct file_operations static_address_fops = { .release = single_release, }; -static int own_address_type_set(void *data, u64 val) +static ssize_t force_static_address_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { - struct hci_dev *hdev = data; + struct hci_dev *hdev = file->private_data; + char buf[3]; - if (val != 0 && val != 1) + buf[0] = test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) ? 'Y': 'N'; + buf[1] = '\n'; + buf[2] = '\0'; + return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static ssize_t force_static_address_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + char buf[32]; + size_t buf_size = min(count, (sizeof(buf)-1)); + bool enable; + + if (test_bit(HCI_UP, &hdev->flags)) + return -EBUSY; + + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + buf[buf_size] = '\0'; + if (strtobool(buf, &enable)) return -EINVAL; - hci_dev_lock(hdev); - hdev->own_addr_type = val; - hci_dev_unlock(hdev); + if (enable == test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags)) + return -EALREADY; - return 0; + change_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags); + + return count; } -static int own_address_type_get(void *data, u64 *val) -{ - struct hci_dev *hdev = data; - - hci_dev_lock(hdev); - *val = hdev->own_addr_type; - hci_dev_unlock(hdev); - - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(own_address_type_fops, own_address_type_get, - own_address_type_set, "%llu\n"); +static const struct file_operations force_static_address_fops = { + .open = simple_open, + .read = force_static_address_read, + .write = force_static_address_write, + .llseek = default_llseek, +}; static int identity_resolving_keys_show(struct seq_file *f, void *ptr) { @@ -1406,17 +1425,19 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) hci_setup_link_policy(req); if (lmp_le_capable(hdev)) { - if (test_bit(HCI_SETUP, &hdev->dev_flags)) { - /* If the controller has a public BD_ADDR, then - * by default use that one. If this is a LE only - * controller without a public address, default - * to the random address. - */ - if (bacmp(&hdev->bdaddr, BDADDR_ANY)) - hdev->own_addr_type = ADDR_LE_DEV_PUBLIC; - else - hdev->own_addr_type = ADDR_LE_DEV_RANDOM; - } + /* If the controller has a public BD_ADDR, then by default + * use that one. If this is a LE only controller without + * a public address, default to the random address. + * + * For debugging purposes it is possible to force + * controllers with a public address to use the + * random address instead. + */ + if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dev_flags) || + !bacmp(&hdev->bdaddr, BDADDR_ANY)) + hdev->own_addr_type = ADDR_LE_DEV_RANDOM; + else + hdev->own_addr_type = ADDR_LE_DEV_PUBLIC; hci_set_le_support(req); } @@ -1536,12 +1557,20 @@ static int __hci_init(struct hci_dev *hdev) } if (lmp_le_capable(hdev)) { + debugfs_create_file("static_address", 0444, hdev->debugfs, + hdev, &static_address_fops); + + /* For controllers with a public address, provide a debug + * option to force the usage of the configured static + * address. By default the public address is used. + */ + if (bacmp(&hdev->bdaddr, BDADDR_ANY)) + debugfs_create_file("force_static_address", 0644, + hdev->debugfs, hdev, + &force_static_address_fops); + debugfs_create_u8("white_list_size", 0444, hdev->debugfs, &hdev->le_white_list_size); - debugfs_create_file("static_address", 0444, hdev->debugfs, - hdev, &static_address_fops); - debugfs_create_file("own_address_type", 0644, hdev->debugfs, - hdev, &own_address_type_fops); debugfs_create_file("identity_resolving_keys", 0400, hdev->debugfs, hdev, &identity_resolving_keys_fops); From 7a4cd51dec96b42d899ed7b2207c9ef810534451 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 19 Feb 2014 19:52:13 -0800 Subject: [PATCH 135/139] Bluetooth: Track the current configured random address For Bluetooth controllers with LE support, track the value of the currently configured random address. It is important to know what the current random address is to avoid unneeded attempts to set a new address. This will become important when introducing the LE privacy support in the future. In addition expose the current configured random address via debugfs for debugging purposes. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 26 ++++++++++++++++++++++++++ net/bluetooth/hci_event.c | 24 ++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3be2905010cd..3a8e22e9b25d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -151,6 +151,7 @@ struct hci_dev { __u8 bus; __u8 dev_type; bdaddr_t bdaddr; + bdaddr_t random_addr; bdaddr_t static_addr; __u8 own_addr_type; __u8 dev_name[HCI_MAX_NAME_LENGTH]; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b25a36c3064b..877330b4876f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -548,6 +548,29 @@ static int sniff_max_interval_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(sniff_max_interval_fops, sniff_max_interval_get, sniff_max_interval_set, "%llu\n"); +static int random_address_show(struct seq_file *f, void *p) +{ + struct hci_dev *hdev = f->private; + + hci_dev_lock(hdev); + seq_printf(f, "%pMR\n", &hdev->random_addr); + hci_dev_unlock(hdev); + + return 0; +} + +static int random_address_open(struct inode *inode, struct file *file) +{ + return single_open(file, random_address_show, inode->i_private); +} + +static const struct file_operations random_address_fops = { + .open = random_address_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int static_address_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; @@ -1557,6 +1580,8 @@ static int __hci_init(struct hci_dev *hdev) } if (lmp_le_capable(hdev)) { + debugfs_create_file("random_address", 0444, hdev->debugfs, + hdev, &random_address_fops); debugfs_create_file("static_address", 0444, hdev->debugfs, hdev, &static_address_fops); @@ -2205,6 +2230,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) memset(hdev->eir, 0, sizeof(hdev->eir)); memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); + bacpy(&hdev->random_addr, BDADDR_ANY); hci_req_unlock(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7228fa100b1f..4327b129d38e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -959,6 +959,26 @@ static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev, hci_dev_unlock(hdev); } + +static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb) +{ + __u8 status = *((__u8 *) skb->data); + bdaddr_t *sent; + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_RANDOM_ADDR); + if (!sent) + return; + + hci_dev_lock(hdev); + + if (!status) + bacpy(&hdev->random_addr, sent); + + hci_dev_unlock(hdev); +} + static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) { __u8 *sent, status = *((__u8 *) skb->data); @@ -2308,6 +2328,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_user_passkey_neg_reply(hdev, skb); break; + case HCI_OP_LE_SET_RANDOM_ADDR: + hci_cc_le_set_random_addr(hdev, skb); + break; + case HCI_OP_LE_SET_ADV_ENABLE: hci_cc_le_set_adv_enable(hdev, skb); break; From b1765e7afe8710ef4366dc722cc5bd487eb07973 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Thu, 20 Feb 2014 16:42:01 +0100 Subject: [PATCH 136/139] Bluetooth: Fix channel check when binding RFCOMM sock When binding RFCOMM socket with non-zero channel we're checking if there is already any other socket which has the same channel number assigned and then fail. This check does not consider situation where we have another socket connected to remote device on given channel number in which case we still should be able to bind local socket. This patch changes __rfcomm_get_sock_by_addr() to return only sockets in either BT_BOUND or BT_LISTEN states, also name is updated to better describe what this function does now. Signed-off-by: Andrzej Kaczmarek Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/sock.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 00573fb79030..c024e715512f 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -105,13 +105,18 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err) } /* ---- Socket functions ---- */ -static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src) +static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src) { struct sock *sk = NULL; sk_for_each(sk, &rfcomm_sk_list.head) { - if (rfcomm_pi(sk)->channel == channel && - !bacmp(&rfcomm_pi(sk)->src, src)) + if (rfcomm_pi(sk)->channel != channel) + continue; + + if (bacmp(&rfcomm_pi(sk)->src, src)) + continue; + + if (sk->sk_state == BT_BOUND || sk->sk_state == BT_LISTEN) break; } @@ -331,6 +336,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr { struct sockaddr_rc *sa = (struct sockaddr_rc *) addr; struct sock *sk = sock->sk; + int chan = sa->rc_channel; int err = 0; BT_DBG("sk %p %pMR", sk, &sa->rc_bdaddr); @@ -352,12 +358,12 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr write_lock(&rfcomm_sk_list.lock); - if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) { + if (chan && __rfcomm_get_listen_sock_by_addr(chan, &sa->rc_bdaddr)) { err = -EADDRINUSE; } else { /* Save source address */ bacpy(&rfcomm_pi(sk)->src, &sa->rc_bdaddr); - rfcomm_pi(sk)->channel = sa->rc_channel; + rfcomm_pi(sk)->channel = chan; sk->sk_state = BT_BOUND; } @@ -439,7 +445,7 @@ static int rfcomm_sock_listen(struct socket *sock, int backlog) write_lock(&rfcomm_sk_list.lock); for (channel = 1; channel < 31; channel++) - if (!__rfcomm_get_sock_by_addr(channel, src)) { + if (!__rfcomm_get_listen_sock_by_addr(channel, src)) { rfcomm_pi(sk)->channel = channel; err = 0; break; From 3f959d46a60c20eedf6f228e49d820c5922ec68f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 20 Feb 2014 11:55:56 -0800 Subject: [PATCH 137/139] Bluetooth: Provide option for changing LE advertising channel map For testing purposes it is useful to provide an option to change the advertising channel map. So add a debugfs option to allow this. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 31 +++++++++++++++++++++++++++++++ net/bluetooth/mgmt.c | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3a8e22e9b25d..c0fcc041fbb5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -178,6 +178,7 @@ struct hci_dev { __u16 page_scan_interval; __u16 page_scan_window; __u8 page_scan_type; + __u8 le_adv_channel_map; __u16 le_scan_interval; __u16 le_scan_window; __u16 le_conn_min_interval; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 877330b4876f..67192867c998 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -757,6 +757,34 @@ static int conn_max_interval_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get, conn_max_interval_set, "%llu\n"); +static int adv_channel_map_set(void *data, u64 val) +{ + struct hci_dev *hdev = data; + + if (val < 0x01 || val > 0x07) + return -EINVAL; + + hci_dev_lock(hdev); + hdev->le_adv_channel_map = val; + hci_dev_unlock(hdev); + + return 0; +} + +static int adv_channel_map_get(void *data, u64 *val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock(hdev); + *val = hdev->le_adv_channel_map; + hci_dev_unlock(hdev); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get, + adv_channel_map_set, "%llu\n"); + static ssize_t lowpan_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1605,6 +1633,8 @@ static int __hci_init(struct hci_dev *hdev) hdev, &conn_min_interval_fops); debugfs_create_file("conn_max_interval", 0644, hdev->debugfs, hdev, &conn_max_interval_fops); + debugfs_create_file("adv_channel_map", 0644, hdev->debugfs, + hdev, &adv_channel_map_fops); debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev, &lowpan_debugfs_fops); } @@ -3264,6 +3294,7 @@ struct hci_dev *hci_alloc_dev(void) hdev->sniff_max_interval = 800; hdev->sniff_min_interval = 80; + hdev->le_adv_channel_map = 0x07; hdev->le_scan_interval = 0x0060; hdev->le_scan_window = 0x0030; hdev->le_conn_min_interval = 0x0028; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5f5e388716ec..12fa6399c796 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1374,7 +1374,7 @@ static void enable_advertising(struct hci_request *req) cp.max_interval = __constant_cpu_to_le16(0x0800); cp.type = get_adv_type(hdev); cp.own_address_type = hdev->own_addr_type; - cp.channel_map = 0x07; + cp.channel_map = hdev->le_adv_channel_map; hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp); From a747439957ee2d1696a2a1494e5ce0516e153f10 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 20 Feb 2014 12:44:20 -0800 Subject: [PATCH 138/139] Bluetooth: Increase minor version of core module With the addition of Resolvable Private Address (RPA) resolution support for Bluetooth Low Energy connections, it makes sense to increase the minor version of the Bluetooth core module. The module version is not used anywhere, but it gives a nice extra hint for debugging purposes. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/af_bluetooth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 0c5866bb49b6..2021c481cdb6 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -31,7 +31,7 @@ #include #include -#define VERSION "2.18" +#define VERSION "2.19" /* Bluetooth sockets */ #define BT_MAX_PROTO 8 From 668b7b19820b0801c425d31cc27fd6f499050e5c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 21 Feb 2014 16:03:31 +0200 Subject: [PATCH 139/139] Bluetooth: Fix iterating wrong list in hci_remove_irk() We should be iterating hdev->identity_resolving_keys in the hci_remove_irk() function instead of hdev->long_term_keys. This patch fixes the issue. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 67192867c998..964aa8deb009 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2937,7 +2937,7 @@ void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type) { struct smp_irk *k, *tmp; - list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) { + list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) { if (bacmp(bdaddr, &k->bdaddr) || k->addr_type != addr_type) continue;