|
Packit |
34410b |
/*
|
|
Packit |
34410b |
*
|
|
Packit |
34410b |
* BlueZ - Bluetooth protocol stack for Linux
|
|
Packit |
34410b |
*
|
|
Packit |
34410b |
* Copyright (C) 2011 Nokia Corporation
|
|
Packit |
34410b |
* Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
|
|
Packit |
34410b |
*
|
|
Packit |
34410b |
*
|
|
Packit |
34410b |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
34410b |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
34410b |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
34410b |
* (at your option) any later version.
|
|
Packit |
34410b |
*
|
|
Packit |
34410b |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
34410b |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
34410b |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
34410b |
* GNU General Public License for more details.
|
|
Packit |
34410b |
*
|
|
Packit |
34410b |
* You should have received a copy of the GNU General Public License
|
|
Packit |
34410b |
* along with this program; if not, write to the Free Software
|
|
Packit |
34410b |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
34410b |
*
|
|
Packit |
34410b |
*/
|
|
Packit |
34410b |
|
|
Packit |
34410b |
#ifdef HAVE_CONFIG_H
|
|
Packit |
34410b |
#include <config.h>
|
|
Packit |
34410b |
#endif
|
|
Packit |
34410b |
|
|
Packit |
34410b |
#define _GNU_SOURCE
|
|
Packit |
34410b |
#include <errno.h>
|
|
Packit |
34410b |
#include <ctype.h>
|
|
Packit |
34410b |
#include <stdlib.h>
|
|
Packit |
34410b |
#include <stdint.h>
|
|
Packit |
34410b |
#include <stdbool.h>
|
|
Packit |
34410b |
#include <glib.h>
|
|
Packit |
34410b |
|
|
Packit |
34410b |
#include "lib/bluetooth.h"
|
|
Packit |
34410b |
#include "lib/hci.h"
|
|
Packit |
34410b |
#include "lib/sdp.h"
|
|
Packit |
34410b |
|
|
Packit |
34410b |
#include "src/shared/util.h"
|
|
Packit |
34410b |
#include "uuid-helper.h"
|
|
Packit |
34410b |
#include "eir.h"
|
|
Packit |
34410b |
|
|
Packit |
34410b |
#define EIR_OOB_MIN (2 + 6)
|
|
Packit |
34410b |
|
|
Packit |
34410b |
static void sd_free(void *data)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
struct eir_sd *sd = data;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
free(sd->uuid);
|
|
Packit |
34410b |
g_free(sd);
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
static void data_free(void *data)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
struct eir_ad *ad = data;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
g_free(ad->data);
|
|
Packit |
34410b |
g_free(ad);
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
void eir_data_free(struct eir_data *eir)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
g_slist_free_full(eir->services, free);
|
|
Packit |
34410b |
eir->services = NULL;
|
|
Packit |
34410b |
g_free(eir->name);
|
|
Packit |
34410b |
eir->name = NULL;
|
|
Packit |
34410b |
g_free(eir->hash);
|
|
Packit |
34410b |
eir->hash = NULL;
|
|
Packit |
34410b |
g_free(eir->randomizer);
|
|
Packit |
34410b |
eir->randomizer = NULL;
|
|
Packit |
34410b |
g_slist_free_full(eir->msd_list, g_free);
|
|
Packit |
34410b |
eir->msd_list = NULL;
|
|
Packit |
34410b |
g_slist_free_full(eir->sd_list, sd_free);
|
|
Packit |
34410b |
eir->sd_list = NULL;
|
|
Packit |
34410b |
g_slist_free_full(eir->data_list, data_free);
|
|
Packit |
34410b |
eir->data_list = NULL;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
static void eir_parse_uuid16(struct eir_data *eir, const void *data,
|
|
Packit |
34410b |
uint8_t len)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
const uint16_t *uuid16 = data;
|
|
Packit |
34410b |
uuid_t service;
|
|
Packit |
34410b |
char *uuid_str;
|
|
Packit |
34410b |
unsigned int i;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
service.type = SDP_UUID16;
|
|
Packit |
34410b |
for (i = 0; i < len / 2; i++, uuid16++) {
|
|
Packit |
34410b |
service.value.uuid16 = get_le16(uuid16);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
uuid_str = bt_uuid2string(&service);
|
|
Packit |
34410b |
if (!uuid_str)
|
|
Packit |
34410b |
continue;
|
|
Packit |
34410b |
eir->services = g_slist_append(eir->services, uuid_str);
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
static void eir_parse_uuid32(struct eir_data *eir, const void *data,
|
|
Packit |
34410b |
uint8_t len)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
const uint32_t *uuid32 = data;
|
|
Packit |
34410b |
uuid_t service;
|
|
Packit |
34410b |
char *uuid_str;
|
|
Packit |
34410b |
unsigned int i;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
service.type = SDP_UUID32;
|
|
Packit |
34410b |
for (i = 0; i < len / 4; i++, uuid32++) {
|
|
Packit |
34410b |
service.value.uuid32 = get_le32(uuid32);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
uuid_str = bt_uuid2string(&service);
|
|
Packit |
34410b |
if (!uuid_str)
|
|
Packit |
34410b |
continue;
|
|
Packit |
34410b |
eir->services = g_slist_append(eir->services, uuid_str);
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
static void eir_parse_uuid128(struct eir_data *eir, const uint8_t *data,
|
|
Packit |
34410b |
uint8_t len)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
const uint8_t *uuid_ptr = data;
|
|
Packit |
34410b |
uuid_t service;
|
|
Packit |
34410b |
char *uuid_str;
|
|
Packit |
34410b |
unsigned int i;
|
|
Packit |
34410b |
int k;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
service.type = SDP_UUID128;
|
|
Packit |
34410b |
for (i = 0; i < len / 16; i++) {
|
|
Packit |
34410b |
for (k = 0; k < 16; k++)
|
|
Packit |
34410b |
service.value.uuid128.data[k] = uuid_ptr[16 - k - 1];
|
|
Packit |
34410b |
uuid_str = bt_uuid2string(&service);
|
|
Packit |
34410b |
if (!uuid_str)
|
|
Packit |
34410b |
continue;
|
|
Packit |
34410b |
eir->services = g_slist_append(eir->services, uuid_str);
|
|
Packit |
34410b |
uuid_ptr += 16;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
static char *name2utf8(const uint8_t *name, uint8_t len)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
char utf8_name[HCI_MAX_NAME_LENGTH + 2];
|
|
Packit |
34410b |
int i;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (g_utf8_validate((const char *) name, len, NULL))
|
|
Packit |
34410b |
return g_strndup((char *) name, len);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
memset(utf8_name, 0, sizeof(utf8_name));
|
|
Packit |
34410b |
strncpy(utf8_name, (char *) name, len);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* Assume ASCII, and replace all non-ASCII with spaces */
|
|
Packit |
34410b |
for (i = 0; utf8_name[i] != '\0'; i++) {
|
|
Packit |
34410b |
if (!isascii(utf8_name[i]))
|
|
Packit |
34410b |
utf8_name[i] = ' ';
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* Remove leading and trailing whitespace characters */
|
|
Packit |
34410b |
g_strstrip(utf8_name);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
return g_strdup(utf8_name);
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
static void eir_parse_msd(struct eir_data *eir, const uint8_t *data,
|
|
Packit |
34410b |
uint8_t len)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
struct eir_msd *msd;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (len < 2 || len > 2 + sizeof(msd->data))
|
|
Packit |
34410b |
return;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
msd = g_malloc(sizeof(*msd));
|
|
Packit |
34410b |
msd->company = get_le16(data);
|
|
Packit |
34410b |
msd->data_len = len - 2;
|
|
Packit |
34410b |
memcpy(&msd->data, data + 2, msd->data_len);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir->msd_list = g_slist_append(eir->msd_list, msd);
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
static void eir_parse_sd(struct eir_data *eir, uuid_t *service,
|
|
Packit |
34410b |
const uint8_t *data, uint8_t len)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
struct eir_sd *sd;
|
|
Packit |
34410b |
char *uuid;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
uuid = bt_uuid2string(service);
|
|
Packit |
34410b |
if (!uuid)
|
|
Packit |
34410b |
return;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
sd = g_malloc(sizeof(*sd));
|
|
Packit |
34410b |
sd->uuid = uuid;
|
|
Packit |
34410b |
sd->data_len = len;
|
|
Packit |
34410b |
memcpy(&sd->data, data, sd->data_len);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir->sd_list = g_slist_append(eir->sd_list, sd);
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
static void eir_parse_uuid16_data(struct eir_data *eir, const uint8_t *data,
|
|
Packit |
34410b |
uint8_t len)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
uuid_t service;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (len < 2 || len > EIR_SD_MAX_LEN)
|
|
Packit |
34410b |
return;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
service.type = SDP_UUID16;
|
|
Packit |
34410b |
service.value.uuid16 = get_le16(data);
|
|
Packit |
34410b |
eir_parse_sd(eir, &service, data + 2, len - 2);
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
static void eir_parse_uuid32_data(struct eir_data *eir, const uint8_t *data,
|
|
Packit |
34410b |
uint8_t len)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
uuid_t service;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (len < 4 || len > EIR_SD_MAX_LEN)
|
|
Packit |
34410b |
return;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
service.type = SDP_UUID32;
|
|
Packit |
34410b |
service.value.uuid32 = get_le32(data);
|
|
Packit |
34410b |
eir_parse_sd(eir, &service, data + 4, len - 4);
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
static void eir_parse_uuid128_data(struct eir_data *eir, const uint8_t *data,
|
|
Packit |
34410b |
uint8_t len)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
uuid_t service;
|
|
Packit |
34410b |
int k;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (len < 16 || len > EIR_SD_MAX_LEN)
|
|
Packit |
34410b |
return;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
service.type = SDP_UUID128;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
for (k = 0; k < 16; k++)
|
|
Packit |
34410b |
service.value.uuid128.data[k] = data[16 - k - 1];
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir_parse_sd(eir, &service, data + 16, len - 16);
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
static void eir_parse_data(struct eir_data *eir, uint8_t type,
|
|
Packit |
34410b |
const uint8_t *data, uint8_t len)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
struct eir_ad *ad;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
ad = g_malloc(sizeof(*ad));
|
|
Packit |
34410b |
ad->type = type;
|
|
Packit |
34410b |
ad->len = len;
|
|
Packit |
34410b |
ad->data = g_malloc(len);
|
|
Packit |
34410b |
memcpy(ad->data, data, len);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir->data_list = g_slist_append(eir->data_list, ad);
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
void eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
uint16_t len = 0;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir->flags = 0;
|
|
Packit |
34410b |
eir->tx_power = 127;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* No EIR data to parse */
|
|
Packit |
34410b |
if (eir_data == NULL)
|
|
Packit |
34410b |
return;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
while (len < eir_len - 1) {
|
|
Packit |
34410b |
uint8_t field_len = eir_data[0];
|
|
Packit |
34410b |
const uint8_t *data;
|
|
Packit |
34410b |
uint8_t data_len;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* Check for the end of EIR */
|
|
Packit |
34410b |
if (field_len == 0)
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
len += field_len + 1;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* Do not continue EIR Data parsing if got incorrect length */
|
|
Packit |
34410b |
if (len > eir_len)
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
data = &eir_data[2];
|
|
Packit |
34410b |
data_len = field_len - 1;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
switch (eir_data[1]) {
|
|
Packit |
34410b |
case EIR_UUID16_SOME:
|
|
Packit |
34410b |
case EIR_UUID16_ALL:
|
|
Packit |
34410b |
eir_parse_uuid16(eir, data, data_len);
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_UUID32_SOME:
|
|
Packit |
34410b |
case EIR_UUID32_ALL:
|
|
Packit |
34410b |
eir_parse_uuid32(eir, data, data_len);
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_UUID128_SOME:
|
|
Packit |
34410b |
case EIR_UUID128_ALL:
|
|
Packit |
34410b |
eir_parse_uuid128(eir, data, data_len);
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_FLAGS:
|
|
Packit |
34410b |
if (data_len > 0)
|
|
Packit |
34410b |
eir->flags = *data;
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_NAME_SHORT:
|
|
Packit |
34410b |
case EIR_NAME_COMPLETE:
|
|
Packit |
34410b |
/* Some vendors put a NUL byte terminator into
|
|
Packit |
34410b |
* the name */
|
|
Packit |
34410b |
while (data_len > 0 && data[data_len - 1] == '\0')
|
|
Packit |
34410b |
data_len--;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
g_free(eir->name);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir->name = name2utf8(data, data_len);
|
|
Packit |
34410b |
eir->name_complete = eir_data[1] == EIR_NAME_COMPLETE;
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_TX_POWER:
|
|
Packit |
34410b |
if (data_len < 1)
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
eir->tx_power = (int8_t) data[0];
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_CLASS_OF_DEV:
|
|
Packit |
34410b |
if (data_len < 3)
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
eir->class = data[0] | (data[1] << 8) |
|
|
Packit |
34410b |
(data[2] << 16);
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_GAP_APPEARANCE:
|
|
Packit |
34410b |
if (data_len < 2)
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
eir->appearance = get_le16(data);
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_SSP_HASH:
|
|
Packit |
34410b |
if (data_len < 16)
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
eir->hash = g_memdup(data, 16);
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_SSP_RANDOMIZER:
|
|
Packit |
34410b |
if (data_len < 16)
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
eir->randomizer = g_memdup(data, 16);
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_DEVICE_ID:
|
|
Packit |
34410b |
if (data_len < 8)
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir->did_source = data[0] | (data[1] << 8);
|
|
Packit |
34410b |
eir->did_vendor = data[2] | (data[3] << 8);
|
|
Packit |
34410b |
eir->did_product = data[4] | (data[5] << 8);
|
|
Packit |
34410b |
eir->did_version = data[6] | (data[7] << 8);
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_SVC_DATA16:
|
|
Packit |
34410b |
eir_parse_uuid16_data(eir, data, data_len);
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_SVC_DATA32:
|
|
Packit |
34410b |
eir_parse_uuid32_data(eir, data, data_len);
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_SVC_DATA128:
|
|
Packit |
34410b |
eir_parse_uuid128_data(eir, data, data_len);
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
case EIR_MANUFACTURER_DATA:
|
|
Packit |
34410b |
eir_parse_msd(eir, data, data_len);
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
default:
|
|
Packit |
34410b |
eir_parse_data(eir, eir_data[1], data, data_len);
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir_data += field_len + 1;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
int eir_parse_oob(struct eir_data *eir, uint8_t *eir_data, uint16_t eir_len)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (eir_len < EIR_OOB_MIN)
|
|
Packit |
34410b |
return -1;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (eir_len != get_le16(eir_data))
|
|
Packit |
34410b |
return -1;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir_data += sizeof(uint16_t);
|
|
Packit |
34410b |
eir_len -= sizeof(uint16_t);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
memcpy(&eir->addr, eir_data, sizeof(bdaddr_t));
|
|
Packit |
34410b |
eir_data += sizeof(bdaddr_t);
|
|
Packit |
34410b |
eir_len -= sizeof(bdaddr_t);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* optional OOB EIR data */
|
|
Packit |
34410b |
if (eir_len > 0)
|
|
Packit |
34410b |
eir_parse(eir, eir_data, eir_len);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
return 0;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
#define SIZEOF_UUID128 16
|
|
Packit |
34410b |
|
|
Packit |
34410b |
static void eir_generate_uuid128(sdp_list_t *list, uint8_t *ptr,
|
|
Packit |
34410b |
uint16_t *eir_len)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
int i, k, uuid_count = 0;
|
|
Packit |
34410b |
uint16_t len = *eir_len;
|
|
Packit |
34410b |
uint8_t *uuid128;
|
|
Packit |
34410b |
bool truncated = false;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* Store UUIDs in place, skip 2 bytes to write type and length later */
|
|
Packit |
34410b |
uuid128 = ptr + 2;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
for (; list; list = list->next) {
|
|
Packit |
34410b |
sdp_record_t *rec = list->data;
|
|
Packit |
34410b |
uuid_t *uuid = &rec->svclass;
|
|
Packit |
34410b |
uint8_t *uuid128_data = uuid->value.uuid128.data;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (uuid->type != SDP_UUID128)
|
|
Packit |
34410b |
continue;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* Stop if not enough space to put next UUID128 */
|
|
Packit |
34410b |
if ((len + 2 + SIZEOF_UUID128) > HCI_MAX_EIR_LENGTH) {
|
|
Packit |
34410b |
truncated = true;
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* Check for duplicates, EIR data is Little Endian */
|
|
Packit |
34410b |
for (i = 0; i < uuid_count; i++) {
|
|
Packit |
34410b |
for (k = 0; k < SIZEOF_UUID128; k++) {
|
|
Packit |
34410b |
if (uuid128[i * SIZEOF_UUID128 + k] !=
|
|
Packit |
34410b |
uuid128_data[SIZEOF_UUID128 - 1 - k])
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
if (k == SIZEOF_UUID128)
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (i < uuid_count)
|
|
Packit |
34410b |
continue;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* EIR data is Little Endian */
|
|
Packit |
34410b |
for (k = 0; k < SIZEOF_UUID128; k++)
|
|
Packit |
34410b |
uuid128[uuid_count * SIZEOF_UUID128 + k] =
|
|
Packit |
34410b |
uuid128_data[SIZEOF_UUID128 - 1 - k];
|
|
Packit |
34410b |
|
|
Packit |
34410b |
len += SIZEOF_UUID128;
|
|
Packit |
34410b |
uuid_count++;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (uuid_count > 0 || truncated) {
|
|
Packit |
34410b |
/* EIR Data length */
|
|
Packit |
34410b |
ptr[0] = (uuid_count * SIZEOF_UUID128) + 1;
|
|
Packit |
34410b |
/* EIR Data type */
|
|
Packit |
34410b |
ptr[1] = truncated ? EIR_UUID128_SOME : EIR_UUID128_ALL;
|
|
Packit |
34410b |
len += 2;
|
|
Packit |
34410b |
*eir_len = len;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
int eir_create_oob(const bdaddr_t *addr, const char *name, uint32_t cod,
|
|
Packit |
34410b |
const uint8_t *hash, const uint8_t *randomizer,
|
|
Packit |
34410b |
uint16_t did_vendor, uint16_t did_product,
|
|
Packit |
34410b |
uint16_t did_version, uint16_t did_source,
|
|
Packit |
34410b |
sdp_list_t *uuids, uint8_t *data)
|
|
Packit |
34410b |
{
|
|
Packit |
34410b |
sdp_list_t *l;
|
|
Packit |
34410b |
uint8_t *ptr = data;
|
|
Packit |
34410b |
uint16_t eir_optional_len = 0;
|
|
Packit |
34410b |
uint16_t eir_total_len;
|
|
Packit |
34410b |
uint16_t uuid16[HCI_MAX_EIR_LENGTH / 2];
|
|
Packit |
34410b |
int i, uuid_count = 0;
|
|
Packit |
34410b |
bool truncated = false;
|
|
Packit |
34410b |
size_t name_len;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir_total_len = sizeof(uint16_t) + sizeof(bdaddr_t);
|
|
Packit |
34410b |
ptr += sizeof(uint16_t);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
memcpy(ptr, addr, sizeof(bdaddr_t));
|
|
Packit |
34410b |
ptr += sizeof(bdaddr_t);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (cod > 0) {
|
|
Packit |
34410b |
uint8_t class[3];
|
|
Packit |
34410b |
|
|
Packit |
34410b |
class[0] = (uint8_t) cod;
|
|
Packit |
34410b |
class[1] = (uint8_t) (cod >> 8);
|
|
Packit |
34410b |
class[2] = (uint8_t) (cod >> 16);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
*ptr++ = 4;
|
|
Packit |
34410b |
*ptr++ = EIR_CLASS_OF_DEV;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
memcpy(ptr, class, sizeof(class));
|
|
Packit |
34410b |
ptr += sizeof(class);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir_optional_len += sizeof(class) + 2;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (hash) {
|
|
Packit |
34410b |
*ptr++ = 17;
|
|
Packit |
34410b |
*ptr++ = EIR_SSP_HASH;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
memcpy(ptr, hash, 16);
|
|
Packit |
34410b |
ptr += 16;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir_optional_len += 16 + 2;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (randomizer) {
|
|
Packit |
34410b |
*ptr++ = 17;
|
|
Packit |
34410b |
*ptr++ = EIR_SSP_RANDOMIZER;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
memcpy(ptr, randomizer, 16);
|
|
Packit |
34410b |
ptr += 16;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir_optional_len += 16 + 2;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
name_len = strlen(name);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (name_len > 0) {
|
|
Packit |
34410b |
/* EIR Data type */
|
|
Packit |
34410b |
if (name_len > 48) {
|
|
Packit |
34410b |
name_len = 48;
|
|
Packit |
34410b |
ptr[1] = EIR_NAME_SHORT;
|
|
Packit |
34410b |
} else
|
|
Packit |
34410b |
ptr[1] = EIR_NAME_COMPLETE;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* EIR Data length */
|
|
Packit |
34410b |
ptr[0] = name_len + 1;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
memcpy(ptr + 2, name, name_len);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir_optional_len += (name_len + 2);
|
|
Packit |
34410b |
ptr += (name_len + 2);
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (did_vendor != 0x0000) {
|
|
Packit |
34410b |
*ptr++ = 9;
|
|
Packit |
34410b |
*ptr++ = EIR_DEVICE_ID;
|
|
Packit |
34410b |
*ptr++ = (did_source & 0x00ff);
|
|
Packit |
34410b |
*ptr++ = (did_source & 0xff00) >> 8;
|
|
Packit |
34410b |
*ptr++ = (did_vendor & 0x00ff);
|
|
Packit |
34410b |
*ptr++ = (did_vendor & 0xff00) >> 8;
|
|
Packit |
34410b |
*ptr++ = (did_product & 0x00ff);
|
|
Packit |
34410b |
*ptr++ = (did_product & 0xff00) >> 8;
|
|
Packit |
34410b |
*ptr++ = (did_version & 0x00ff);
|
|
Packit |
34410b |
*ptr++ = (did_version & 0xff00) >> 8;
|
|
Packit |
34410b |
eir_optional_len += 10;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* Group all UUID16 types */
|
|
Packit |
34410b |
for (l = uuids; l != NULL; l = l->next) {
|
|
Packit |
34410b |
sdp_record_t *rec = l->data;
|
|
Packit |
34410b |
uuid_t *uuid = &rec->svclass;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (uuid->type != SDP_UUID16)
|
|
Packit |
34410b |
continue;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (uuid->value.uuid16 < 0x1100)
|
|
Packit |
34410b |
continue;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (uuid->value.uuid16 == PNP_INFO_SVCLASS_ID)
|
|
Packit |
34410b |
continue;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* Stop if not enough space to put next UUID16 */
|
|
Packit |
34410b |
if ((eir_optional_len + 2 + sizeof(uint16_t)) >
|
|
Packit |
34410b |
HCI_MAX_EIR_LENGTH) {
|
|
Packit |
34410b |
truncated = true;
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* Check for duplicates */
|
|
Packit |
34410b |
for (i = 0; i < uuid_count; i++)
|
|
Packit |
34410b |
if (uuid16[i] == uuid->value.uuid16)
|
|
Packit |
34410b |
break;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (i < uuid_count)
|
|
Packit |
34410b |
continue;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
uuid16[uuid_count++] = uuid->value.uuid16;
|
|
Packit |
34410b |
eir_optional_len += sizeof(uint16_t);
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
if (uuid_count > 0) {
|
|
Packit |
34410b |
/* EIR Data length */
|
|
Packit |
34410b |
ptr[0] = (uuid_count * sizeof(uint16_t)) + 1;
|
|
Packit |
34410b |
/* EIR Data type */
|
|
Packit |
34410b |
ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
ptr += 2;
|
|
Packit |
34410b |
eir_optional_len += 2;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
for (i = 0; i < uuid_count; i++) {
|
|
Packit |
34410b |
*ptr++ = (uuid16[i] & 0x00ff);
|
|
Packit |
34410b |
*ptr++ = (uuid16[i] & 0xff00) >> 8;
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
}
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* Group all UUID128 types */
|
|
Packit |
34410b |
if (eir_optional_len <= HCI_MAX_EIR_LENGTH - 2)
|
|
Packit |
34410b |
eir_generate_uuid128(uuids, ptr, &eir_optional_len);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
eir_total_len += eir_optional_len;
|
|
Packit |
34410b |
|
|
Packit |
34410b |
/* store total length */
|
|
Packit |
34410b |
put_le16(eir_total_len, data);
|
|
Packit |
34410b |
|
|
Packit |
34410b |
return eir_total_len;
|
|
Packit |
34410b |
}
|