Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * BlueZ - Bluetooth protocol stack for Linux
0004  *
0005  * Copyright (C) 2021 Intel Corporation
0006  */
0007 
0008 #include <net/bluetooth/bluetooth.h>
0009 #include <net/bluetooth/hci_core.h>
0010 #include <net/bluetooth/mgmt.h>
0011 
0012 #include "eir.h"
0013 
0014 #define PNP_INFO_SVCLASS_ID     0x1200
0015 
0016 static u8 eir_append_name(u8 *eir, u16 eir_len, u8 type, u8 *data, u8 data_len)
0017 {
0018     u8 name[HCI_MAX_SHORT_NAME_LENGTH + 1];
0019 
0020     /* If data is already NULL terminated just pass it directly */
0021     if (data[data_len - 1] == '\0')
0022         return eir_append_data(eir, eir_len, type, data, data_len);
0023 
0024     memcpy(name, data, HCI_MAX_SHORT_NAME_LENGTH);
0025     name[HCI_MAX_SHORT_NAME_LENGTH] = '\0';
0026 
0027     return eir_append_data(eir, eir_len, type, name, sizeof(name));
0028 }
0029 
0030 u8 eir_append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len)
0031 {
0032     size_t short_len;
0033     size_t complete_len;
0034 
0035     /* no space left for name (+ NULL + type + len) */
0036     if ((HCI_MAX_AD_LENGTH - ad_len) < HCI_MAX_SHORT_NAME_LENGTH + 3)
0037         return ad_len;
0038 
0039     /* use complete name if present and fits */
0040     complete_len = strnlen(hdev->dev_name, sizeof(hdev->dev_name));
0041     if (complete_len && complete_len <= HCI_MAX_SHORT_NAME_LENGTH)
0042         return eir_append_name(ptr, ad_len, EIR_NAME_COMPLETE,
0043                        hdev->dev_name, complete_len + 1);
0044 
0045     /* use short name if present */
0046     short_len = strnlen(hdev->short_name, sizeof(hdev->short_name));
0047     if (short_len)
0048         return eir_append_name(ptr, ad_len, EIR_NAME_SHORT,
0049                        hdev->short_name,
0050                        short_len == HCI_MAX_SHORT_NAME_LENGTH ?
0051                        short_len : short_len + 1);
0052 
0053     /* use shortened full name if present, we already know that name
0054      * is longer then HCI_MAX_SHORT_NAME_LENGTH
0055      */
0056     if (complete_len)
0057         return eir_append_name(ptr, ad_len, EIR_NAME_SHORT,
0058                        hdev->dev_name,
0059                        HCI_MAX_SHORT_NAME_LENGTH);
0060 
0061     return ad_len;
0062 }
0063 
0064 u8 eir_append_appearance(struct hci_dev *hdev, u8 *ptr, u8 ad_len)
0065 {
0066     return eir_append_le16(ptr, ad_len, EIR_APPEARANCE, hdev->appearance);
0067 }
0068 
0069 u8 eir_append_service_data(u8 *eir, u16 eir_len, u16 uuid, u8 *data,
0070                u8 data_len)
0071 {
0072     eir[eir_len++] = sizeof(u8) + sizeof(uuid) + data_len;
0073     eir[eir_len++] = EIR_SERVICE_DATA;
0074     put_unaligned_le16(uuid, &eir[eir_len]);
0075     eir_len += sizeof(uuid);
0076     memcpy(&eir[eir_len], data, data_len);
0077     eir_len += data_len;
0078 
0079     return eir_len;
0080 }
0081 
0082 static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
0083 {
0084     u8 *ptr = data, *uuids_start = NULL;
0085     struct bt_uuid *uuid;
0086 
0087     if (len < 4)
0088         return ptr;
0089 
0090     list_for_each_entry(uuid, &hdev->uuids, list) {
0091         u16 uuid16;
0092 
0093         if (uuid->size != 16)
0094             continue;
0095 
0096         uuid16 = get_unaligned_le16(&uuid->uuid[12]);
0097         if (uuid16 < 0x1100)
0098             continue;
0099 
0100         if (uuid16 == PNP_INFO_SVCLASS_ID)
0101             continue;
0102 
0103         if (!uuids_start) {
0104             uuids_start = ptr;
0105             uuids_start[0] = 1;
0106             uuids_start[1] = EIR_UUID16_ALL;
0107             ptr += 2;
0108         }
0109 
0110         /* Stop if not enough space to put next UUID */
0111         if ((ptr - data) + sizeof(u16) > len) {
0112             uuids_start[1] = EIR_UUID16_SOME;
0113             break;
0114         }
0115 
0116         *ptr++ = (uuid16 & 0x00ff);
0117         *ptr++ = (uuid16 & 0xff00) >> 8;
0118         uuids_start[0] += sizeof(uuid16);
0119     }
0120 
0121     return ptr;
0122 }
0123 
0124 static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
0125 {
0126     u8 *ptr = data, *uuids_start = NULL;
0127     struct bt_uuid *uuid;
0128 
0129     if (len < 6)
0130         return ptr;
0131 
0132     list_for_each_entry(uuid, &hdev->uuids, list) {
0133         if (uuid->size != 32)
0134             continue;
0135 
0136         if (!uuids_start) {
0137             uuids_start = ptr;
0138             uuids_start[0] = 1;
0139             uuids_start[1] = EIR_UUID32_ALL;
0140             ptr += 2;
0141         }
0142 
0143         /* Stop if not enough space to put next UUID */
0144         if ((ptr - data) + sizeof(u32) > len) {
0145             uuids_start[1] = EIR_UUID32_SOME;
0146             break;
0147         }
0148 
0149         memcpy(ptr, &uuid->uuid[12], sizeof(u32));
0150         ptr += sizeof(u32);
0151         uuids_start[0] += sizeof(u32);
0152     }
0153 
0154     return ptr;
0155 }
0156 
0157 static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
0158 {
0159     u8 *ptr = data, *uuids_start = NULL;
0160     struct bt_uuid *uuid;
0161 
0162     if (len < 18)
0163         return ptr;
0164 
0165     list_for_each_entry(uuid, &hdev->uuids, list) {
0166         if (uuid->size != 128)
0167             continue;
0168 
0169         if (!uuids_start) {
0170             uuids_start = ptr;
0171             uuids_start[0] = 1;
0172             uuids_start[1] = EIR_UUID128_ALL;
0173             ptr += 2;
0174         }
0175 
0176         /* Stop if not enough space to put next UUID */
0177         if ((ptr - data) + 16 > len) {
0178             uuids_start[1] = EIR_UUID128_SOME;
0179             break;
0180         }
0181 
0182         memcpy(ptr, uuid->uuid, 16);
0183         ptr += 16;
0184         uuids_start[0] += 16;
0185     }
0186 
0187     return ptr;
0188 }
0189 
0190 void eir_create(struct hci_dev *hdev, u8 *data)
0191 {
0192     u8 *ptr = data;
0193     size_t name_len;
0194 
0195     name_len = strnlen(hdev->dev_name, sizeof(hdev->dev_name));
0196 
0197     if (name_len > 0) {
0198         /* EIR Data type */
0199         if (name_len > 48) {
0200             name_len = 48;
0201             ptr[1] = EIR_NAME_SHORT;
0202         } else {
0203             ptr[1] = EIR_NAME_COMPLETE;
0204         }
0205 
0206         /* EIR Data length */
0207         ptr[0] = name_len + 1;
0208 
0209         memcpy(ptr + 2, hdev->dev_name, name_len);
0210 
0211         ptr += (name_len + 2);
0212     }
0213 
0214     if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
0215         ptr[0] = 2;
0216         ptr[1] = EIR_TX_POWER;
0217         ptr[2] = (u8)hdev->inq_tx_power;
0218 
0219         ptr += 3;
0220     }
0221 
0222     if (hdev->devid_source > 0) {
0223         ptr[0] = 9;
0224         ptr[1] = EIR_DEVICE_ID;
0225 
0226         put_unaligned_le16(hdev->devid_source, ptr + 2);
0227         put_unaligned_le16(hdev->devid_vendor, ptr + 4);
0228         put_unaligned_le16(hdev->devid_product, ptr + 6);
0229         put_unaligned_le16(hdev->devid_version, ptr + 8);
0230 
0231         ptr += 10;
0232     }
0233 
0234     ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
0235     ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
0236     ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
0237 }
0238 
0239 u8 eir_create_per_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
0240 {
0241     struct adv_info *adv = NULL;
0242     u8 ad_len = 0;
0243 
0244     /* Return 0 when the current instance identifier is invalid. */
0245     if (instance) {
0246         adv = hci_find_adv_instance(hdev, instance);
0247         if (!adv)
0248             return 0;
0249     }
0250 
0251     if (adv) {
0252         memcpy(ptr, adv->per_adv_data, adv->per_adv_data_len);
0253         ad_len += adv->per_adv_data_len;
0254         ptr += adv->per_adv_data_len;
0255     }
0256 
0257     return ad_len;
0258 }
0259 
0260 u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
0261 {
0262     struct adv_info *adv = NULL;
0263     u8 ad_len = 0, flags = 0;
0264     u32 instance_flags;
0265 
0266     /* Return 0 when the current instance identifier is invalid. */
0267     if (instance) {
0268         adv = hci_find_adv_instance(hdev, instance);
0269         if (!adv)
0270             return 0;
0271     }
0272 
0273     instance_flags = hci_adv_instance_flags(hdev, instance);
0274 
0275     /* If instance already has the flags set skip adding it once
0276      * again.
0277      */
0278     if (adv && eir_get_data(adv->adv_data, adv->adv_data_len, EIR_FLAGS,
0279                 NULL))
0280         goto skip_flags;
0281 
0282     /* The Add Advertising command allows userspace to set both the general
0283      * and limited discoverable flags.
0284      */
0285     if (instance_flags & MGMT_ADV_FLAG_DISCOV)
0286         flags |= LE_AD_GENERAL;
0287 
0288     if (instance_flags & MGMT_ADV_FLAG_LIMITED_DISCOV)
0289         flags |= LE_AD_LIMITED;
0290 
0291     if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
0292         flags |= LE_AD_NO_BREDR;
0293 
0294     if (flags || (instance_flags & MGMT_ADV_FLAG_MANAGED_FLAGS)) {
0295         /* If a discovery flag wasn't provided, simply use the global
0296          * settings.
0297          */
0298         if (!flags)
0299             flags |= mgmt_get_adv_discov_flags(hdev);
0300 
0301         /* If flags would still be empty, then there is no need to
0302          * include the "Flags" AD field".
0303          */
0304         if (flags) {
0305             ptr[0] = 0x02;
0306             ptr[1] = EIR_FLAGS;
0307             ptr[2] = flags;
0308 
0309             ad_len += 3;
0310             ptr += 3;
0311         }
0312     }
0313 
0314 skip_flags:
0315     if (adv) {
0316         memcpy(ptr, adv->adv_data, adv->adv_data_len);
0317         ad_len += adv->adv_data_len;
0318         ptr += adv->adv_data_len;
0319     }
0320 
0321     if (instance_flags & MGMT_ADV_FLAG_TX_POWER) {
0322         s8 adv_tx_power;
0323 
0324         if (ext_adv_capable(hdev)) {
0325             if (adv)
0326                 adv_tx_power = adv->tx_power;
0327             else
0328                 adv_tx_power = hdev->adv_tx_power;
0329         } else {
0330             adv_tx_power = hdev->adv_tx_power;
0331         }
0332 
0333         /* Provide Tx Power only if we can provide a valid value for it */
0334         if (adv_tx_power != HCI_TX_POWER_INVALID) {
0335             ptr[0] = 0x02;
0336             ptr[1] = EIR_TX_POWER;
0337             ptr[2] = (u8)adv_tx_power;
0338 
0339             ad_len += 3;
0340             ptr += 3;
0341         }
0342     }
0343 
0344     return ad_len;
0345 }
0346 
0347 static u8 create_default_scan_rsp(struct hci_dev *hdev, u8 *ptr)
0348 {
0349     u8 scan_rsp_len = 0;
0350 
0351     if (hdev->appearance)
0352         scan_rsp_len = eir_append_appearance(hdev, ptr, scan_rsp_len);
0353 
0354     return eir_append_local_name(hdev, ptr, scan_rsp_len);
0355 }
0356 
0357 u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr)
0358 {
0359     struct adv_info *adv;
0360     u8 scan_rsp_len = 0;
0361 
0362     if (!instance)
0363         return create_default_scan_rsp(hdev, ptr);
0364 
0365     adv = hci_find_adv_instance(hdev, instance);
0366     if (!adv)
0367         return 0;
0368 
0369     if ((adv->flags & MGMT_ADV_FLAG_APPEARANCE) && hdev->appearance)
0370         scan_rsp_len = eir_append_appearance(hdev, ptr, scan_rsp_len);
0371 
0372     memcpy(&ptr[scan_rsp_len], adv->scan_rsp_data, adv->scan_rsp_len);
0373 
0374     scan_rsp_len += adv->scan_rsp_len;
0375 
0376     if (adv->flags & MGMT_ADV_FLAG_LOCAL_NAME)
0377         scan_rsp_len = eir_append_local_name(hdev, ptr, scan_rsp_len);
0378 
0379     return scan_rsp_len;
0380 }
0381 
0382 void *eir_get_service_data(u8 *eir, size_t eir_len, u16 uuid, size_t *len)
0383 {
0384     while ((eir = eir_get_data(eir, eir_len, EIR_SERVICE_DATA, len))) {
0385         u16 value = get_unaligned_le16(eir);
0386 
0387         if (uuid == value) {
0388             if (len)
0389                 *len -= 2;
0390             return &eir[2];
0391         }
0392 
0393         eir += *len;
0394         eir_len -= *len;
0395     }
0396 
0397     return NULL;
0398 }