aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/mgmt.c
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2015-03-15 01:43:19 -0400
committerJohan Hedberg <johan.hedberg@intel.com>2015-03-15 04:05:29 -0400
commit4f0f155ceaf7e1b59d210a8afb24d4ea63ce13cc (patch)
tree0f72d130822e8d2bda1488ccf25f025226cd3b0b /net/bluetooth/mgmt.c
parent1471aae0d04d4e0df2bf1e5a5af861e28371b8b4 (diff)
Bluetooth: Add simple version of Read Local OOB Extended Data command
This adds support for the simplest possible version of Read Local OOB Extended Data management command. It includes all mandatory fields, but none of the actual pairing related ones. Signed-off-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r--net/bluetooth/mgmt.c111
1 files changed, 110 insertions, 1 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 07c75a04829a..6cb0a304182f 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -96,6 +96,7 @@ static const u16 mgmt_commands[] = {
96 MGMT_OP_SET_EXTERNAL_CONFIG, 96 MGMT_OP_SET_EXTERNAL_CONFIG,
97 MGMT_OP_SET_PUBLIC_ADDRESS, 97 MGMT_OP_SET_PUBLIC_ADDRESS,
98 MGMT_OP_START_SERVICE_DISCOVERY, 98 MGMT_OP_START_SERVICE_DISCOVERY,
99 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
99 MGMT_OP_READ_EXT_INDEX_LIST, 100 MGMT_OP_READ_EXT_INDEX_LIST,
100 MGMT_OP_READ_ADV_FEATURES, 101 MGMT_OP_READ_ADV_FEATURES,
101}; 102};
@@ -6266,6 +6267,114 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
6266 return eir_len; 6267 return eir_len;
6267} 6268}
6268 6269
6270static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6271 void *data, u16 data_len)
6272{
6273 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6274 struct mgmt_rp_read_local_oob_ext_data *rp;
6275 size_t rp_len;
6276 u16 eir_len;
6277 u8 status, flags, role, addr[7];
6278 int err;
6279
6280 BT_DBG("%s", hdev->name);
6281
6282 if (!hdev_is_powered(hdev))
6283 return mgmt_cmd_complete(sk, hdev->id,
6284 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6285 MGMT_STATUS_NOT_POWERED,
6286 &cp->type, sizeof(cp->type));
6287
6288 switch (cp->type) {
6289 case BIT(BDADDR_BREDR):
6290 status = mgmt_bredr_support(hdev);
6291 if (status)
6292 return mgmt_cmd_complete(sk, hdev->id,
6293 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6294 status, &cp->type,
6295 sizeof(cp->type));
6296 eir_len = 5;
6297 break;
6298 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6299 status = mgmt_le_support(hdev);
6300 if (status)
6301 return mgmt_cmd_complete(sk, hdev->id,
6302 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6303 status, &cp->type,
6304 sizeof(cp->type));
6305 eir_len = 15;
6306 break;
6307 default:
6308 return mgmt_cmd_complete(sk, hdev->id,
6309 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6310 MGMT_STATUS_INVALID_PARAMS,
6311 &cp->type, sizeof(cp->type));
6312 }
6313
6314 hci_dev_lock(hdev);
6315
6316 rp_len = sizeof(*rp) + eir_len;
6317 rp = kmalloc(rp_len, GFP_ATOMIC);
6318 if (!rp) {
6319 hci_dev_unlock(hdev);
6320 return -ENOMEM;
6321 }
6322
6323 eir_len = 0;
6324 switch (cp->type) {
6325 case BIT(BDADDR_BREDR):
6326 eir_len = eir_append_data(rp->eir, eir_len, EIR_CLASS_OF_DEV,
6327 hdev->dev_class, 3);
6328 break;
6329 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6330 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
6331 memcpy(addr, &hdev->rpa, 6);
6332 addr[6] = 0x01;
6333 } else if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6334 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6335 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6336 bacmp(&hdev->static_addr, BDADDR_ANY))) {
6337 memcpy(addr, &hdev->static_addr, 6);
6338 addr[6] = 0x01;
6339 } else {
6340 memcpy(addr, &hdev->bdaddr, 6);
6341 addr[6] = 0x00;
6342 }
6343
6344 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6345 addr, sizeof(addr));
6346
6347 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6348 role = 0x02;
6349 else
6350 role = 0x01;
6351
6352 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6353 &role, sizeof(role));
6354
6355 flags = get_adv_discov_flags(hdev);
6356
6357 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6358 flags |= LE_AD_NO_BREDR;
6359
6360 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6361 &flags, sizeof(flags));
6362 break;
6363 }
6364
6365 rp->type = cp->type;
6366 rp->eir_len = cpu_to_le16(eir_len);
6367
6368 hci_dev_unlock(hdev);
6369
6370 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6371 MGMT_STATUS_SUCCESS, rp, rp_len);
6372
6373 kfree(rp);
6374
6375 return err;
6376}
6377
6269static int read_adv_features(struct sock *sk, struct hci_dev *hdev, 6378static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6270 void *data, u16 data_len) 6379 void *data, u16 data_len)
6271{ 6380{
@@ -6379,7 +6488,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
6379 HCI_MGMT_UNCONFIGURED }, 6488 HCI_MGMT_UNCONFIGURED },
6380 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE, 6489 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6381 HCI_MGMT_VAR_LEN }, 6490 HCI_MGMT_VAR_LEN },
6382 { NULL }, 6491 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
6383 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE, 6492 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
6384 HCI_MGMT_NO_HDEV | 6493 HCI_MGMT_NO_HDEV |
6385 HCI_MGMT_UNTRUSTED }, 6494 HCI_MGMT_UNTRUSTED },