aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/smp.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2014-02-18 03:19:36 -0500
committerMarcel Holtmann <marcel@holtmann.org>2014-02-18 03:47:03 -0500
commitfd349c020c5b6f7a6e17cb8b4e821ff9b6f71ba6 (patch)
treefd713b8b491c9971c4a9a099b14c8d18c501bb2f /net/bluetooth/smp.c
parent41edf1601af3b25461d91e73834dc89510bca8e5 (diff)
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 <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/smp.c')
-rw-r--r--net/bluetooth/smp.c80
1 files changed, 73 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,
249 struct smp_cmd_pairing *req, 249 struct smp_cmd_pairing *req,
250 struct smp_cmd_pairing *rsp, __u8 authreq) 250 struct smp_cmd_pairing *rsp, __u8 authreq)
251{ 251{
252 u8 dist_keys = 0; 252 struct smp_chan *smp = conn->smp_chan;
253 struct hci_conn *hcon = conn->hcon;
254 struct hci_dev *hdev = hcon->hdev;
255 u8 local_dist = 0, remote_dist = 0;
253 256
254 if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) { 257 if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) {
255 dist_keys = SMP_DIST_ENC_KEY; 258 local_dist = SMP_DIST_ENC_KEY;
259 remote_dist = SMP_DIST_ENC_KEY;
256 authreq |= SMP_AUTH_BONDING; 260 authreq |= SMP_AUTH_BONDING;
257 } else { 261 } else {
258 authreq &= ~SMP_AUTH_BONDING; 262 authreq &= ~SMP_AUTH_BONDING;
259 } 263 }
260 264
265 if (test_bit(HCI_RPA_RESOLVING, &hdev->dev_flags))
266 remote_dist |= SMP_DIST_ID_KEY;
267
261 if (rsp == NULL) { 268 if (rsp == NULL) {
262 req->io_capability = conn->hcon->io_capability; 269 req->io_capability = conn->hcon->io_capability;
263 req->oob_flag = SMP_OOB_NOT_PRESENT; 270 req->oob_flag = SMP_OOB_NOT_PRESENT;
264 req->max_key_size = SMP_MAX_ENC_KEY_SIZE; 271 req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
265 req->init_key_dist = dist_keys; 272 req->init_key_dist = local_dist;
266 req->resp_key_dist = dist_keys; 273 req->resp_key_dist = remote_dist;
267 req->auth_req = (authreq & AUTH_REQ_MASK); 274 req->auth_req = (authreq & AUTH_REQ_MASK);
275
276 smp->remote_key_dist = remote_dist;
268 return; 277 return;
269 } 278 }
270 279
271 rsp->io_capability = conn->hcon->io_capability; 280 rsp->io_capability = conn->hcon->io_capability;
272 rsp->oob_flag = SMP_OOB_NOT_PRESENT; 281 rsp->oob_flag = SMP_OOB_NOT_PRESENT;
273 rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE; 282 rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
274 rsp->init_key_dist = req->init_key_dist & dist_keys; 283 rsp->init_key_dist = req->init_key_dist & remote_dist;
275 rsp->resp_key_dist = req->resp_key_dist & dist_keys; 284 rsp->resp_key_dist = req->resp_key_dist & local_dist;
276 rsp->auth_req = (authreq & AUTH_REQ_MASK); 285 rsp->auth_req = (authreq & AUTH_REQ_MASK);
286
287 smp->remote_key_dist = rsp->init_key_dist;
277} 288}
278 289
279static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) 290static 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)
907 hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, 1, 918 hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, 1,
908 authenticated, smp->tk, smp->enc_key_size, 919 authenticated, smp->tk, smp->enc_key_size,
909 rp->ediv, rp->rand); 920 rp->ediv, rp->rand);
910 smp_distribute_keys(conn, 1); 921 if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
922 smp_distribute_keys(conn, 1);
911 hci_dev_unlock(hdev); 923 hci_dev_unlock(hdev);
912 924
913 return 0; 925 return 0;
914} 926}
915 927
928static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb)
929{
930 struct smp_cmd_ident_info *info = (void *) skb->data;
931 struct smp_chan *smp = conn->smp_chan;
932
933 BT_DBG("");
934
935 if (skb->len < sizeof(*info))
936 return SMP_UNSPECIFIED;
937
938 skb_pull(skb, sizeof(*info));
939
940 memcpy(smp->irk, info->irk, 16);
941
942 return 0;
943}
944
945static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
946 struct sk_buff *skb)
947{
948 struct smp_cmd_ident_addr_info *info = (void *) skb->data;
949 struct smp_chan *smp = conn->smp_chan;
950 struct hci_conn *hcon = conn->hcon;
951 bdaddr_t rpa;
952
953 BT_DBG("");
954
955 if (skb->len < sizeof(*info))
956 return SMP_UNSPECIFIED;
957
958 skb_pull(skb, sizeof(*info));
959
960 bacpy(&smp->id_addr, &info->bdaddr);
961 smp->id_addr_type = info->addr_type;
962
963 if (hci_bdaddr_is_rpa(&hcon->dst, hcon->dst_type))
964 bacpy(&rpa, &hcon->dst);
965 else
966 bacpy(&rpa, BDADDR_ANY);
967
968 hci_add_irk(conn->hcon->hdev, &smp->id_addr, smp->id_addr_type,
969 smp->irk, &rpa);
970
971 smp_distribute_keys(conn, 1);
972
973 return 0;
974}
975
916int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) 976int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
917{ 977{
918 struct hci_conn *hcon = conn->hcon; 978 struct hci_conn *hcon = conn->hcon;
@@ -987,7 +1047,13 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
987 break; 1047 break;
988 1048
989 case SMP_CMD_IDENT_INFO: 1049 case SMP_CMD_IDENT_INFO:
1050 reason = smp_cmd_ident_info(conn, skb);
1051 break;
1052
990 case SMP_CMD_IDENT_ADDR_INFO: 1053 case SMP_CMD_IDENT_ADDR_INFO:
1054 reason = smp_cmd_ident_addr_info(conn, skb);
1055 break;
1056
991 case SMP_CMD_SIGN_INFO: 1057 case SMP_CMD_SIGN_INFO:
992 /* Just ignored */ 1058 /* Just ignored */
993 reason = 0; 1059 reason = 0;