1

我希望能够自定义 HCI LE 广告报告,这样我就可以在不连接到 IOS 应用程序 (iPhone) 的情况下收集其他服务 UUID。

BLUEZ hcitool(通过 lescan 选项)为每个设备返回 HCI LE 广告报告,如下所示:

Num_Reports,
Event_Type[i],
Address_Type[i],
Address[i],
Length[i],
Data[i],
RSSI[i]

我检索此 HCI LE 广告报告的代码基于hcitool.c cmd_lescan函数,如下所示:

static void print_eir(const uint8_t *eir, uint8_t eir_len, bool le)
{
    info("print_eir");
    uint16_t len = 0;

    if (eir_len == 0)
        return;

    while (len < eir_len - 1) {
        uint8_t field_len = eir[0];
        const uint8_t *data = &eir[2];
        uint8_t data_len;
        char name[239], label[100];
        uint8_t flags, mask;
        int i;

        /* Check for the end of EIR */
        if (field_len == 0)
            break;

        len += field_len + 1;

        /* Do not continue EIR Data parsing if got incorrect length */
        if (len > eir_len) {
            len -= field_len + 1;
            break;
        }

        data_len = field_len - 1;

        switch (eir[1]) {
        case BT_EIR_FLAGS:
            info("BT_EIR_FLAGS");
            flags = *data;
            mask = flags;

            info("Flags: 0x%2.2x", flags);

            for (i = 0; eir_flags_table[i].str; i++) {
                if (flags & (1 << eir_flags_table[i].bit)) {
                    info("  %s",
                            eir_flags_table[i].str);
                    mask &= ~(1 << eir_flags_table[i].bit);
                }
            }
            break;

        case BT_EIR_UUID16_SOME:
            info("BT_EIR_UUID16_SOME\n");
            if (data_len < sizeof(uint16_t))
                break;
            print_uuid16_list("16-bit Service UUIDs (partial)",
                            data, data_len);
            break;

        case BT_EIR_UUID16_ALL:
            info("BT_EIR_UUID16_ALL\n");
            if (data_len < sizeof(uint16_t))
                break;
            print_uuid16_list("16-bit Service UUIDs (complete)",
                            data, data_len);
            break;

        case BT_EIR_UUID32_SOME:
            info("BT_EIR_UUID32_SOME\n");
            if (data_len < sizeof(uint32_t))
                break;
            print_uuid32_list("32-bit Service UUIDs (partial)",
                            data, data_len);
            break;

        case BT_EIR_UUID32_ALL:
            info("BT_EIR_UUID32_ALL\n");
            if (data_len < sizeof(uint32_t))
                break;
            print_uuid32_list("32-bit Service UUIDs (complete)",
                            data, data_len);
            break;

        case BT_EIR_UUID128_SOME:
            info("BT_EIR_UUID128_SOME\n");
            if (data_len < 16)
                break;
            print_uuid128_list("128-bit Service UUIDs (partial)",
                                data, data_len);
            break;

        case BT_EIR_UUID128_ALL:
            info("BT_EIR_UUID128_ALL\n");
            if (data_len < 16)
                break;
            print_uuid128_list("128-bit Service UUIDs (complete)",
                                data, data_len);
            break;

        case BT_EIR_NAME_SHORT:
            info("BT_EIR_NAME_SHORT");
            memset(name, 0, sizeof(name));
            memcpy(name, data, data_len);
            info("Name (short): %s", name);
            break;

        case BT_EIR_NAME_COMPLETE:
            info("BT_EIR_NAME_COMPLETE");
            memset(name, 0, sizeof(name));
            memcpy(name, data, data_len);
            info("Name (complete): %s", name);
            break;

        case BT_EIR_SERVICE_UUID128:
            info("BT_EIR_SERVICE_UUID128\n");
            if (data_len < 16)
                break;
            print_uuid128_list("128-bit Service UUIDs",
                            data, data_len);
            break;

        case BT_EIR_SERVICE_DATA:
            info("BT_EIR_SERVICE_DATA\n");
            if (data_len < 2)
                break;
            sprintf(label, "Service Data (UUID 0x%4.4x)",
                            get_le16(&data[0]));
            print_hex_field(label, &data[2], data_len - 2);
            break;

        case BT_EIR_RANDOM_ADDRESS:
            info("BT_EIR_RANDOM_ADDRESS\n");
            if (data_len < 6)
                break;
            print_addr("Random Address", data, 0x01);
            break;

        case BT_EIR_PUBLIC_ADDRESS:
            info("BT_EIR_PUBLIC_ADDRESS\n");
            if (data_len < 6)
                break;
            print_addr("Public Address", data, 0x00);
            break;

        case BT_EIR_TX_POWER:
            info("BT_EIR_TX_POWER");
            if (data_len < 1)
                break;
            info("TX power: %d dBm", (int8_t) *data);
            break;

        case BT_EIR_SMP_OOB_FLAGS:
            info("BT_EIR_SMP_OOB_FLAGS");
            info("SMP OOB Flags: 0x%2.2x", *data);
            break;

        default:
            sprintf(label, "Unknown EIR field 0x%2.2x", eir[1]);
            print_hex_field(label, data, data_len);
            break;
        }

        eir += field_len + 1;
    }

    if (len < eir_len && eir[0] != 0)
        packet_hexdump(eir, eir_len - len);
}

static int print_advertising_devices(int dd, uint8_t filter_type)
{
    unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr;
    struct hci_filter nf, of;
    struct sigaction sa;
    socklen_t olen;
    int len;

    info("print_advertising_devices");

    olen = sizeof(of);
    if (getsockopt(dd, SOL_HCI, HCI_FILTER, &of, &olen) < 0) {
        error("Could not get socket options");
        return -1;
    }

    hci_filter_clear(&nf);
    hci_filter_set_ptype(HCI_EVENT_PKT, &nf);
    hci_filter_set_event(EVT_LE_META_EVENT, &nf);

    if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) {
        error("Could not set socket options");
        return -1;
    }

    memset(&sa, 0, sizeof(sa));
    sa.sa_flags = SA_NOCLDSTOP;
    sa.sa_handler = sigint_handler;
    sigaction(SIGINT, &sa, NULL);

    while (1) {
        evt_le_meta_event *meta;
        le_advertising_info *leinfo;
        char btAddress[18];

        while ((len = read(dd, buf, sizeof(buf))) < 0) {
            if (errno == EINTR && signal_received == SIGINT) {
                len = 0;
                goto done;
            }

            if (errno == EAGAIN || errno == EINTR)
                continue;
            goto done;
        }

        ptr = buf + (1 + HCI_EVENT_HDR_SIZE);
        len -= (1 + HCI_EVENT_HDR_SIZE);

        meta = (void *) ptr;

        if (meta->subevent != 0x02) // must be report type
            goto done;

        // Overlay report structure
        leinfo = (le_advertising_info *) (meta->data + 1);

        // Get report count
        info("************** BLE Buffer **************");
        uint8_t reports_count = meta->data[0];
        info("report-count: %d", reports_count);

        int i; // Dump LE report data
        for (i = 0; i < leinfo->length; i++) {
              printf("%02x", leinfo->data[i]);
        }
        printf("\n");

        // Get BT address & type
        ba2str(&leinfo->bdaddr, btAddress);
        info("BT Address: %s, Type: %s,", btAddress, (leinfo->bdaddr_type == LE_PUBLIC_ADDRESS) ? "public" : "random");

        // Get BT Service name
        char name[30];
        memset(name, 0, sizeof(name));
        eir_parse_name(leinfo->data, leinfo->length, name, sizeof(name) - 1);
        info("Service name: %s", name);

        // Determine Range(RSSI)
        int8_t rssi;
        rssi = leinfo->data[leinfo->length];
        if ((uint8_t) rssi == 0x99 || rssi == 127)
            error("RSSI: invalid (0x%2.2x)", (uint8_t) rssi);
        else
            info("RSSI: %d dBm (0x%2.2x)", rssi, (uint8_t) rssi);

        print_eir(leinfo->data, leinfo->length, true);
        info("****************************************");
    }

done:
    setsockopt(dd, SOL_HCI, HCI_FILTER, &of, sizeof(of));

    if (len < 0)
        return -1;

    return 0;
}

static void cmd_lescan(int dev_id)
{
    int err, dd;
    uint8_t own_type = 0x01;    // Random
    uint8_t scan_type = 0x00;   // passive scan - not sending scan responses
    uint8_t filter_type = 0;
    uint8_t filter_policy = 0x00;
    uint16_t interval = htobs(0x0010);
    uint16_t window = htobs(0x0010);
    uint8_t filter_dup = 0;     // not filtering duplicates

    info("cmd_lescan");

    if (dev_id < 0)
        dev_id = hci_get_route(NULL);

    dd = hci_open_dev(dev_id);
    if (dd < 0) {
        perror("Could not open device");
        exit(1);
    }

    err = hci_le_set_scan_parameters(dd, scan_type, interval, window,
                        own_type, filter_policy, 10000);
    if (err < 0) {
        perror("Set scan parameters failed");
        exit(1);
    }

    err = hci_le_set_scan_enable(dd, 0x01, filter_dup, 10000);
    if (err < 0) {
        perror("Enable scan failed");
        exit(1);
    }

    info("LE Scan ...");

    err = print_advertising_devices(dd, filter_type);
    if (err < 0) {
        perror("Could not receive advertising events");
        exit(1);
    }

    err = hci_le_set_scan_enable(dd, 0x00, filter_dup, 10000);
    if (err < 0) {
        perror("Disable scan failed");
        exit(1);
    }

    hci_close_dev(dd);
}

int main(int argc, char** argv)
{
    info("main");

    // flush stdout immediately
    setvbuf(stdout, NULL, _IONBF, 0);

    cmd_lescan(-1);

    return 0;
}

我能够转储 IOS 应用程序的 HCI LE EVENT 报告结果,如下所示:

RAW Dump: 02011a1106111111111111111111111111111111110909434253616d706c65    
************** BLE Buffer **************
    report-count: 1
    BT Address: 5E:96:DC:70:18:11
    Type: random,
    ENTER: eir_parse_name
    Service name: CBSample
    RSSI: -45 dBm (0xd3)
    ENTER: print_eir
        BT_EIR_FLAGS
            Flags: 0x1a
            LE General Discoverable Mode
            Simultaneous LE and BR/EDR (Controller)
            Simultaneous LE and BR/EDR (Host)
        BT_EIR_UUID128_SOME
             ENTER: print_uuid128_list
            128-bit Service UUIDs (partial): 1 entry
            11111111-1111-1111-1111-111111111111
        BT_EIR_NAME_COMPLETE
            Name (complete): CBSample
    ****************************************

不幸的是,HCI LE 广告报告仅允许单个 128 位 BLE 服务 UUID。有没有办法自定义报告以允许在不连接到 iPhone(IOS) 等设备的情况下收集更多信息?

4

0 回答 0