mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-11-15 16:24:28 +08:00
97531e944c
The strings passed to bt_uuid_strcmp may not be valid UUIDs so the return of bt_string_to_uuid needs to be checked otherwise bt_uuid_cmp may attempt to access unitialized values: Conditional jump or move depends on uninitialised value(s) at 0x4C1D4D: bt_uuid_to_uuid128 (uuid.c:78) by 0x4C1F22: bt_uuid_cmp (uuid.c:131) by 0x4C24A8: bt_uuid_strcmp (uuid.c:286) by 0x40F8A8: reconnect_match (policy.c:514) by 0x40F8A8: service_cb (policy.c:655) by 0x499331: change_state (service.c:109) by 0x499BBB: btd_service_connecting_complete (service.c:361) by 0x4178C1: stream_state_changed (source.c:163) by 0x422C78: avdtp_sep_set_state (avdtp.c:1013) by 0x42372A: handle_transport_connect (avdtp.c:844) by 0x423D8B: avdtp_connect_cb (avdtp.c:2326) by 0x465BBB: connect_cb (btio.c:232) by 0x50CA702: g_main_context_dispatch (in /usr/lib64/libglib-2.0.so.0.4800.1) Uninitialised value was created by a stack allocation at 0x4C2460: bt_uuid_strcmp (uuid.c:280)
313 lines
6.7 KiB
C
313 lines
6.7 KiB
C
/*
|
|
*
|
|
* BlueZ - Bluetooth protocol stack for Linux
|
|
*
|
|
* Copyright (C) 2011 Nokia Corporation
|
|
* Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
|
|
#include "lib/bluetooth.h"
|
|
#include "uuid.h"
|
|
|
|
static uint128_t bluetooth_base_uuid = {
|
|
.data = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
|
|
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }
|
|
};
|
|
|
|
#define BASE_UUID16_OFFSET 2
|
|
#define BASE_UUID32_OFFSET 0
|
|
|
|
static void bt_uuid16_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
|
|
{
|
|
uint16_t be16;
|
|
|
|
dst->value.u128 = bluetooth_base_uuid;
|
|
dst->type = BT_UUID128;
|
|
|
|
/*
|
|
* No matter the system: 128-bit UUIDs should be stored
|
|
* as big-endian. 16-bit UUIDs are stored on host order.
|
|
*/
|
|
|
|
be16 = htons(src->value.u16);
|
|
memcpy(&dst->value.u128.data[BASE_UUID16_OFFSET], &be16, sizeof(be16));
|
|
}
|
|
|
|
static void bt_uuid32_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
|
|
{
|
|
uint32_t be32;
|
|
|
|
dst->value.u128 = bluetooth_base_uuid;
|
|
dst->type = BT_UUID128;
|
|
|
|
/*
|
|
* No matter the system: 128-bit UUIDs should be stored
|
|
* as big-endian. 32-bit UUIDs are stored on host order.
|
|
*/
|
|
|
|
be32 = htonl(src->value.u32);
|
|
memcpy(&dst->value.u128.data[BASE_UUID32_OFFSET], &be32, sizeof(be32));
|
|
}
|
|
|
|
void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
|
|
{
|
|
switch (src->type) {
|
|
case BT_UUID128:
|
|
*dst = *src;
|
|
break;
|
|
case BT_UUID32:
|
|
bt_uuid32_to_uuid128(src, dst);
|
|
break;
|
|
case BT_UUID16:
|
|
bt_uuid16_to_uuid128(src, dst);
|
|
break;
|
|
case BT_UUID_UNSPEC:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int bt_uuid128_cmp(const bt_uuid_t *u1, const bt_uuid_t *u2)
|
|
{
|
|
return memcmp(&u1->value.u128, &u2->value.u128, sizeof(uint128_t));
|
|
}
|
|
|
|
int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value)
|
|
{
|
|
memset(btuuid, 0, sizeof(bt_uuid_t));
|
|
btuuid->type = BT_UUID16;
|
|
btuuid->value.u16 = value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value)
|
|
{
|
|
memset(btuuid, 0, sizeof(bt_uuid_t));
|
|
btuuid->type = BT_UUID32;
|
|
btuuid->value.u32 = value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value)
|
|
{
|
|
memset(btuuid, 0, sizeof(bt_uuid_t));
|
|
btuuid->type = BT_UUID128;
|
|
btuuid->value.u128 = value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2)
|
|
{
|
|
bt_uuid_t u1, u2;
|
|
|
|
bt_uuid_to_uuid128(uuid1, &u1);
|
|
bt_uuid_to_uuid128(uuid2, &u2);
|
|
|
|
return bt_uuid128_cmp(&u1, &u2);
|
|
}
|
|
|
|
/*
|
|
* convert the UUID to string, copying a maximum of n characters.
|
|
*/
|
|
int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n)
|
|
{
|
|
bt_uuid_t tmp;
|
|
unsigned int data0;
|
|
unsigned short data1;
|
|
unsigned short data2;
|
|
unsigned short data3;
|
|
unsigned int data4;
|
|
unsigned short data5;
|
|
const uint8_t *data;
|
|
|
|
if (!uuid || uuid->type == BT_UUID_UNSPEC) {
|
|
snprintf(str, n, "NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Convert to 128 Bit format */
|
|
bt_uuid_to_uuid128(uuid, &tmp);
|
|
data = (uint8_t *) &tmp.value.u128;
|
|
|
|
memcpy(&data0, &data[0], 4);
|
|
memcpy(&data1, &data[4], 2);
|
|
memcpy(&data2, &data[6], 2);
|
|
memcpy(&data3, &data[8], 2);
|
|
memcpy(&data4, &data[10], 4);
|
|
memcpy(&data5, &data[14], 2);
|
|
|
|
snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
|
|
ntohl(data0), ntohs(data1),
|
|
ntohs(data2), ntohs(data3),
|
|
ntohl(data4), ntohs(data5));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int is_uuid128(const char *string)
|
|
{
|
|
return (strlen(string) == 36 &&
|
|
string[8] == '-' &&
|
|
string[13] == '-' &&
|
|
string[18] == '-' &&
|
|
string[23] == '-');
|
|
}
|
|
|
|
static inline int is_base_uuid128(const char *string)
|
|
{
|
|
uint16_t uuid;
|
|
char dummy[2];
|
|
|
|
if (!is_uuid128(string))
|
|
return 0;
|
|
|
|
return sscanf(string,
|
|
"0000%04hx-0000-1000-8000-00805%1[fF]9%1[bB]34%1[fF]%1[bB]",
|
|
&uuid, dummy, dummy, dummy, dummy) == 5;
|
|
}
|
|
|
|
static inline int is_uuid32(const char *string)
|
|
{
|
|
return (strlen(string) == 8 || strlen(string) == 10);
|
|
}
|
|
|
|
static inline int is_uuid16(const char *string)
|
|
{
|
|
return (strlen(string) == 4 || strlen(string) == 6);
|
|
}
|
|
|
|
static int bt_string_to_uuid16(bt_uuid_t *uuid, const char *string)
|
|
{
|
|
uint16_t u16;
|
|
char *endptr = NULL;
|
|
|
|
u16 = strtol(string, &endptr, 16);
|
|
if (endptr && (*endptr == '\0' || *endptr == '-')) {
|
|
bt_uuid16_create(uuid, u16);
|
|
return 0;
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int bt_string_to_uuid32(bt_uuid_t *uuid, const char *string)
|
|
{
|
|
uint32_t u32;
|
|
char *endptr = NULL;
|
|
|
|
u32 = strtol(string, &endptr, 16);
|
|
if (endptr && *endptr == '\0') {
|
|
bt_uuid32_create(uuid, u32);
|
|
return 0;
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int bt_string_to_uuid128(bt_uuid_t *uuid, const char *string)
|
|
{
|
|
uint32_t data0, data4;
|
|
uint16_t data1, data2, data3, data5;
|
|
uint128_t u128;
|
|
uint8_t *val = (uint8_t *) &u128;
|
|
|
|
if (sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
|
|
&data0, &data1, &data2,
|
|
&data3, &data4, &data5) != 6)
|
|
return -EINVAL;
|
|
|
|
data0 = htonl(data0);
|
|
data1 = htons(data1);
|
|
data2 = htons(data2);
|
|
data3 = htons(data3);
|
|
data4 = htonl(data4);
|
|
data5 = htons(data5);
|
|
|
|
memcpy(&val[0], &data0, 4);
|
|
memcpy(&val[4], &data1, 2);
|
|
memcpy(&val[6], &data2, 2);
|
|
memcpy(&val[8], &data3, 2);
|
|
memcpy(&val[10], &data4, 4);
|
|
memcpy(&val[14], &data5, 2);
|
|
|
|
bt_uuid128_create(uuid, u128);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bt_string_to_uuid(bt_uuid_t *uuid, const char *string)
|
|
{
|
|
if (is_base_uuid128(string))
|
|
return bt_string_to_uuid16(uuid, string + 4);
|
|
else if (is_uuid128(string))
|
|
return bt_string_to_uuid128(uuid, string);
|
|
else if (is_uuid32(string))
|
|
return bt_string_to_uuid32(uuid, string);
|
|
else if (is_uuid16(string))
|
|
return bt_string_to_uuid16(uuid, string);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
int bt_uuid_strcmp(const void *a, const void *b)
|
|
{
|
|
bt_uuid_t u1, u2;
|
|
|
|
if (bt_string_to_uuid(&u1, a) < 0)
|
|
return -EINVAL;
|
|
|
|
if (bt_string_to_uuid(&u2, b) < 0)
|
|
return -EINVAL;
|
|
|
|
return bt_uuid_cmp(&u1, &u2);
|
|
}
|
|
|
|
int bt_uuid_to_le(const bt_uuid_t *src, void *dst)
|
|
{
|
|
bt_uuid_t uuid;
|
|
|
|
switch (src->type) {
|
|
case BT_UUID16:
|
|
bt_put_le16(src->value.u16, dst);
|
|
return 0;
|
|
case BT_UUID32:
|
|
bt_uuid32_to_uuid128(src, &uuid);
|
|
src = &uuid;
|
|
/* Fallthrough */
|
|
case BT_UUID128:
|
|
/* Convert from 128-bit BE to LE */
|
|
bswap_128(&src->value.u128, dst);
|
|
return 0;
|
|
case BT_UUID_UNSPEC:
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
}
|