summaryrefslogtreecommitdiffstats
path: root/net/bluetooth/mgmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r--net/bluetooth/mgmt.c79
1 files changed, 79 insertions, 0 deletions
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[] = {
81 MGMT_OP_SET_SCAN_PARAMS, 81 MGMT_OP_SET_SCAN_PARAMS,
82 MGMT_OP_SET_SECURE_CONN, 82 MGMT_OP_SET_SECURE_CONN,
83 MGMT_OP_SET_DEBUG_KEYS, 83 MGMT_OP_SET_DEBUG_KEYS,
84 MGMT_OP_LOAD_IRKS,
84}; 85};
85 86
86static const u16 mgmt_events[] = { 87static const u16 mgmt_events[] = {
@@ -4158,6 +4159,82 @@ unlock:
4158 return err; 4159 return err;
4159} 4160}
4160 4161
4162static bool irk_is_valid(struct mgmt_irk_info *irk)
4163{
4164 switch (irk->addr.type) {
4165 case BDADDR_LE_PUBLIC:
4166 return true;
4167
4168 case BDADDR_LE_RANDOM:
4169 /* Two most significant bits shall be set */
4170 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4171 return false;
4172 return true;
4173 }
4174
4175 return false;
4176}
4177
4178static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4179 u16 len)
4180{
4181 struct mgmt_cp_load_irks *cp = cp_data;
4182 u16 irk_count, expected_len;
4183 int i, err;
4184
4185 BT_DBG("request for %s", hdev->name);
4186
4187 if (!lmp_le_capable(hdev))
4188 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4189 MGMT_STATUS_NOT_SUPPORTED);
4190
4191 irk_count = __le16_to_cpu(cp->irk_count);
4192
4193 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4194 if (expected_len != len) {
4195 BT_ERR("load_irks: expected %u bytes, got %u bytes",
4196 len, expected_len);
4197 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4198 MGMT_STATUS_INVALID_PARAMS);
4199 }
4200
4201 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4202
4203 for (i = 0; i < irk_count; i++) {
4204 struct mgmt_irk_info *key = &cp->irks[i];
4205
4206 if (!irk_is_valid(key))
4207 return cmd_status(sk, hdev->id,
4208 MGMT_OP_LOAD_IRKS,
4209 MGMT_STATUS_INVALID_PARAMS);
4210 }
4211
4212 hci_dev_lock(hdev);
4213
4214 hci_smp_irks_clear(hdev);
4215
4216 for (i = 0; i < irk_count; i++) {
4217 struct mgmt_irk_info *irk = &cp->irks[i];
4218 u8 addr_type;
4219
4220 if (irk->addr.type == BDADDR_LE_PUBLIC)
4221 addr_type = ADDR_LE_DEV_PUBLIC;
4222 else
4223 addr_type = ADDR_LE_DEV_RANDOM;
4224
4225 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
4226 BDADDR_ANY);
4227 }
4228
4229 set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
4230
4231 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
4232
4233 hci_dev_unlock(hdev);
4234
4235 return err;
4236}
4237
4161static bool ltk_is_valid(struct mgmt_ltk_info *key) 4238static bool ltk_is_valid(struct mgmt_ltk_info *key)
4162{ 4239{
4163 if (key->master != 0x00 && key->master != 0x01) 4240 if (key->master != 0x00 && key->master != 0x01)
@@ -4296,6 +4373,8 @@ static const struct mgmt_handler {
4296 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE }, 4373 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
4297 { set_secure_conn, false, MGMT_SETTING_SIZE }, 4374 { set_secure_conn, false, MGMT_SETTING_SIZE },
4298 { set_debug_keys, false, MGMT_SETTING_SIZE }, 4375 { set_debug_keys, false, MGMT_SETTING_SIZE },
4376 { },
4377 { load_irks, true, MGMT_LOAD_IRKS_SIZE },
4299}; 4378};
4300 4379
4301 4380