Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/bluetoothapis/sdp.c
5965 views
1
/*
2
* SDP APIs
3
*
4
* Copyright 2024 Vibhav Pant
5
*
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
*
20
*/
21
22
#include <stdarg.h>
23
#include <windef.h>
24
#include <winbase.h>
25
#include <winternl.h>
26
27
#include "wine/debug.h"
28
#include "bthsdpdef.h"
29
#include "bluetoothapis.h"
30
31
WINE_DEFAULT_DEBUG_CHANNEL( bluetoothapis );
32
33
#define BTH_READ_UINT16( s ) RtlUshortByteSwap( *(USHORT *)(s) )
34
#define BTH_READ_UINT32( s ) RtlUlongByteSwap( *(ULONG *)(s) )
35
#define BTH_READ_UINT64( s ) RtlUlonglongByteSwap( *(ULONGLONG *)(s) )
36
37
#define SDP_SIZE_DESC_1_BYTE 0
38
#define SDP_SIZE_DESC_2_BYTES 1
39
#define SDP_SIZE_DESC_4_BYTES 2
40
#define SDP_SIZE_DESC_8_BYTES 3
41
#define SDP_SIZE_DESC_16_BYTES 4
42
#define SDP_SIZE_DESC_NEXT_UINT8 5
43
#define SDP_SIZE_DESC_NEXT_UINT16 6
44
#define SDP_SIZE_DESC_NEXT_UINT32 7
45
46
static void bth_read_uint128( BYTE *s, SDP_ULARGE_INTEGER_16 *v )
47
{
48
v->HighPart = BTH_READ_UINT64( s );
49
v->LowPart = BTH_READ_UINT64( s + 8 );
50
}
51
52
static BYTE data_elem_type( BYTE elem ) { return (elem & 0xf8) >> 3; }
53
static BYTE data_elem_size_desc( BYTE elem ) { return elem & 0x7; }
54
55
#define SDP_ELEMENT_IS_UINT16( d ) ( (d)->type == SDP_TYPE_UINT && (d)->specificType == SDP_ST_UINT16 )
56
#define SDP_ELEMENT_IS_ATTRID( d ) SDP_ELEMENT_IS_UINT16((d))
57
58
/* Read the data element's size/length as described by the size descriptor, starting from stream. Only
59
* valid for SDP_SIZE_DESC_NEXT_* types. */
60
static BOOL sdp_elem_read_var_size( BYTE *stream, ULONG stream_size, SIZE_T *read, BYTE size_desc,
61
UINT32 *size )
62
{
63
switch (size_desc)
64
{
65
case SDP_SIZE_DESC_NEXT_UINT8:
66
if (stream_size < sizeof( UINT8 )) return FALSE;
67
*size = *stream;
68
*read += sizeof( UINT8 );
69
return TRUE;
70
case SDP_SIZE_DESC_NEXT_UINT16:
71
if (stream_size < sizeof( UINT16 )) return FALSE;
72
*size = BTH_READ_UINT16( stream );
73
*read += sizeof( UINT16 );
74
return TRUE;
75
case SDP_SIZE_DESC_NEXT_UINT32:
76
if (stream_size < sizeof( UINT32 )) return FALSE;
77
*size = BTH_READ_UINT32( stream );
78
*read += sizeof( UINT32 );
79
return TRUE;
80
default:
81
return FALSE;
82
}
83
}
84
85
const static SDP_SPECIFICTYPE SDP_BASIC_TYPES[4][5] = {
86
[SDP_TYPE_UINT] =
87
{
88
[SDP_SIZE_DESC_1_BYTE] = SDP_ST_UINT8,
89
[SDP_SIZE_DESC_2_BYTES] = SDP_ST_UINT16,
90
[SDP_SIZE_DESC_4_BYTES] = SDP_ST_UINT32,
91
[SDP_SIZE_DESC_8_BYTES] = SDP_ST_UINT64,
92
[SDP_SIZE_DESC_16_BYTES] = SDP_ST_UINT128,
93
},
94
[SDP_TYPE_INT] =
95
{
96
[SDP_SIZE_DESC_1_BYTE] = SDP_ST_INT8,
97
[SDP_SIZE_DESC_2_BYTES] = SDP_ST_INT16,
98
[SDP_SIZE_DESC_4_BYTES] = SDP_ST_INT32,
99
[SDP_SIZE_DESC_8_BYTES] = SDP_ST_INT64,
100
[SDP_SIZE_DESC_16_BYTES] = SDP_ST_INT128,
101
},
102
[SDP_TYPE_UUID] =
103
{
104
[SDP_SIZE_DESC_2_BYTES] = SDP_ST_UUID16,
105
[SDP_SIZE_DESC_4_BYTES] = SDP_ST_UUID32,
106
[SDP_SIZE_DESC_16_BYTES] = SDP_ST_UUID128,
107
},
108
};
109
110
static BOOL sdp_read_specific_type( BYTE *stream, ULONG stream_size, SDP_SPECIFICTYPE st,
111
SDP_ELEMENT_DATA *data, SIZE_T *read )
112
{
113
switch (st)
114
{
115
case SDP_ST_UINT8:
116
case SDP_ST_INT8:
117
if (stream_size < sizeof( UINT8 )) return FALSE;
118
data->data.uint8 = *stream;
119
*read += sizeof( UINT8 );
120
break;
121
case SDP_ST_UINT16:
122
case SDP_ST_INT16:
123
case SDP_ST_UUID16:
124
if (stream_size < sizeof( UINT16 )) return FALSE;
125
data->data.uint16 = BTH_READ_UINT16( stream );
126
*read += sizeof( UINT16 );
127
break;
128
case SDP_ST_UINT32:
129
case SDP_ST_INT32:
130
if (stream_size < sizeof( UINT32 )) return FALSE;
131
data->data.uint32 = BTH_READ_UINT32( stream );
132
*read += sizeof( UINT32 );
133
break;
134
case SDP_ST_UINT64:
135
case SDP_ST_INT64:
136
if (stream_size < sizeof( UINT64 )) return FALSE;
137
data->data.uint64 = BTH_READ_UINT64( stream );
138
*read += sizeof( UINT64 );
139
break;
140
case SDP_ST_UINT128:
141
case SDP_ST_INT128:
142
case SDP_ST_UUID128:
143
if (stream_size < sizeof( SDP_ULARGE_INTEGER_16 )) return FALSE;
144
bth_read_uint128( stream, &data->data.uint128 );
145
*read += sizeof( SDP_ULARGE_INTEGER_16 );
146
break;
147
default:
148
return FALSE;
149
}
150
151
return TRUE;
152
}
153
154
static DWORD sdp_read_element_data( BYTE *stream, ULONG stream_size, SDP_ELEMENT_DATA *data,
155
SIZE_T *read )
156
{
157
BYTE type, size_desc, elem;
158
SDP_SPECIFICTYPE st;
159
160
if (stream_size < sizeof( BYTE )) return ERROR_INVALID_PARAMETER;
161
162
elem = *stream;
163
type = data_elem_type( elem );
164
size_desc = data_elem_size_desc( elem );
165
166
stream += sizeof( BYTE );
167
*read += sizeof( BYTE );
168
stream_size -= sizeof( BYTE );
169
170
memset( data, 0, sizeof( *data ) );
171
switch (type)
172
{
173
case SDP_TYPE_NIL:
174
if (size_desc != 0) return ERROR_INVALID_PARAMETER;
175
176
data->type = type;
177
data->specificType = SDP_ST_NONE;
178
break;
179
case SDP_TYPE_UINT:
180
case SDP_TYPE_INT:
181
case SDP_TYPE_UUID:
182
if (size_desc > SDP_SIZE_DESC_16_BYTES) return ERROR_INVALID_PARAMETER;
183
184
st = SDP_BASIC_TYPES[type][size_desc];
185
if (st == SDP_ST_NONE) return ERROR_INVALID_PARAMETER;
186
187
if (!sdp_read_specific_type( stream, stream_size, st, data, read ))
188
return ERROR_INVALID_PARAMETER;
189
190
data->type = type;
191
data->specificType = st;
192
break;
193
case SDP_TYPE_BOOLEAN:
194
if (size_desc != SDP_SIZE_DESC_1_BYTE) return ERROR_INVALID_PARAMETER;
195
if (stream_size < sizeof( BYTE )) return ERROR_INVALID_PARAMETER;
196
197
data->type = type;
198
data->specificType = SDP_ST_NONE;
199
data->data.booleanVal = *stream;
200
*read += sizeof( BYTE );
201
break;
202
case SDP_TYPE_STRING:
203
case SDP_TYPE_URL:
204
case SDP_TYPE_SEQUENCE:
205
case SDP_TYPE_ALTERNATIVE:
206
{
207
UINT32 elems_size;
208
SIZE_T size_read = 0;
209
210
if (!(size_desc >= SDP_SIZE_DESC_NEXT_UINT8 && size_desc <= SDP_SIZE_DESC_NEXT_UINT32))
211
return ERROR_INVALID_PARAMETER;
212
if (!sdp_elem_read_var_size( stream, stream_size, &size_read, size_desc, &elems_size ))
213
return ERROR_INVALID_PARAMETER;
214
215
stream_size -= size_read;
216
if (type == SDP_TYPE_STRING || type == SDP_TYPE_URL)
217
stream += size_read;
218
219
if (stream_size < elems_size) return ERROR_INVALID_PARAMETER;
220
221
data->type = type;
222
data->specificType = SDP_ST_NONE;
223
if (type == SDP_TYPE_STRING || type == SDP_TYPE_URL)
224
{
225
data->data.string.value = stream;
226
data->data.string.length = elems_size;
227
}
228
else
229
{
230
/* For sequence and alternative containers, the stream should begin at the container
231
* header. */
232
data->data.sequence.value = stream - sizeof( BYTE );
233
data->data.sequence.length = elems_size + *read + size_read;
234
}
235
*read += size_read + elems_size;
236
break;
237
}
238
default:
239
return ERROR_INVALID_PARAMETER;
240
}
241
242
return ERROR_SUCCESS;
243
}
244
245
/*********************************************************************
246
* BluetoothSdpGetElementData
247
*/
248
DWORD WINAPI BluetoothSdpGetElementData( BYTE *stream, ULONG stream_size, SDP_ELEMENT_DATA *data )
249
{
250
SIZE_T read = 0;
251
252
TRACE( "(%p, %lu, %p)\n", stream, stream_size, data );
253
254
if (stream == NULL || stream_size < sizeof( BYTE ) || data == NULL)
255
return ERROR_INVALID_PARAMETER;
256
257
return sdp_read_element_data( stream, stream_size, data, &read );
258
}
259
260
/*********************************************************************
261
* BluetoothSdpGetContainerElementData
262
*/
263
DWORD WINAPI BluetoothSdpGetContainerElementData( BYTE *stream, ULONG stream_size,
264
HBLUETOOTH_CONTAINER_ELEMENT *handle,
265
SDP_ELEMENT_DATA *data )
266
{
267
BYTE *cursor;
268
DWORD result;
269
SIZE_T read = 0;
270
271
TRACE( "(%p, %lu, %p, %p)\n", stream, stream_size, handle, data );
272
273
if (stream == NULL || stream_size < sizeof( BYTE ) || handle == NULL || data == NULL)
274
return ERROR_INVALID_PARAMETER;
275
276
cursor = (BYTE *)(*handle);
277
278
if (cursor == NULL)
279
{
280
BYTE header, type, size_desc;
281
UINT32 elems_size = 0;
282
SIZE_T read = 0;
283
284
header = *stream;
285
type = data_elem_type( header );
286
size_desc = data_elem_size_desc( header );
287
288
if (type != SDP_TYPE_SEQUENCE && type != SDP_TYPE_ALTERNATIVE)
289
return ERROR_INVALID_PARAMETER;
290
if (!(size_desc >= SDP_SIZE_DESC_NEXT_UINT8 && size_desc <= SDP_SIZE_DESC_NEXT_UINT32))
291
return ERROR_INVALID_PARAMETER;
292
293
stream++;
294
if (!sdp_elem_read_var_size( stream, stream_size, &read, size_desc, &elems_size ))
295
return ERROR_INVALID_PARAMETER;
296
297
stream += read;
298
stream_size -= read;
299
}
300
else
301
{
302
if (cursor < stream) return ERROR_INVALID_PARAMETER;
303
if (cursor == (stream + stream_size)) return ERROR_NO_MORE_ITEMS;
304
305
stream = cursor;
306
stream_size = stream_size - (cursor - stream);
307
}
308
result = sdp_read_element_data( stream, stream_size, data, &read );
309
if (result != ERROR_SUCCESS) return result;
310
311
stream += read;
312
TRACE( "handle=%p\n", stream );
313
*handle = stream;
314
return ERROR_SUCCESS;
315
}
316
317
/*********************************************************************
318
* BluetoothSdpEnumAttributes
319
*/
320
BOOL WINAPI BluetoothSdpEnumAttributes( BYTE *stream, ULONG stream_size,
321
PFN_BLUETOOTH_ENUM_ATTRIBUTES_CALLBACK callback, void *param )
322
{
323
SDP_ELEMENT_DATA data = {0};
324
DWORD result;
325
HBLUETOOTH_CONTAINER_ELEMENT cursor = NULL;
326
327
TRACE( "(%p, %ld, %p, %p)\n", stream, stream_size, callback, param );
328
329
if (stream == NULL || callback == NULL) return ERROR_INVALID_PARAMETER;
330
331
result = BluetoothSdpGetElementData( stream, stream_size, &data );
332
if (result != ERROR_SUCCESS)
333
{
334
SetLastError( ERROR_INVALID_DATA );
335
return FALSE;
336
}
337
338
switch (data.type)
339
{
340
case SDP_TYPE_SEQUENCE:
341
case SDP_TYPE_ALTERNATIVE:
342
break;
343
default:
344
SetLastError( ERROR_INVALID_DATA );
345
return FALSE;
346
}
347
348
for (;;)
349
{
350
SDP_ELEMENT_DATA attrid = {0};
351
SDP_ELEMENT_DATA attr = {0};
352
BYTE *raw_attr_stream;
353
354
result = BluetoothSdpGetContainerElementData( data.data.sequence.value,
355
data.data.sequence.length, &cursor, &attrid );
356
if (result == ERROR_NO_MORE_ITEMS) return TRUE;
357
if (result || !SDP_ELEMENT_IS_ATTRID( &attrid ))
358
{
359
SetLastError( ERROR_INVALID_DATA );
360
return FALSE;
361
}
362
363
raw_attr_stream = cursor;
364
result = BluetoothSdpGetContainerElementData( data.data.sequence.value,
365
data.data.sequence.length, &cursor, &attr );
366
if (result != ERROR_SUCCESS)
367
{
368
SetLastError( ERROR_INVALID_DATA );
369
return FALSE;
370
}
371
if (!callback( attrid.data.uint16, raw_attr_stream, ((BYTE *)cursor - raw_attr_stream),
372
param ))
373
return TRUE;
374
}
375
}
376
377
struct get_attr_value_data
378
{
379
USHORT attr_id;
380
BYTE *attr_stream;
381
ULONG stream_size;
382
};
383
384
static BOOL WINAPI get_attr_value_callback( ULONG attr_id, BYTE *stream, ULONG stream_size,
385
void *params )
386
{
387
struct get_attr_value_data *args = params;
388
if (attr_id == args->attr_id)
389
{
390
args->attr_stream = stream;
391
args->stream_size = stream_size;
392
return FALSE;
393
}
394
return TRUE;
395
}
396
397
/*********************************************************************
398
* BluetoothSdpGetAttributeValue
399
*/
400
DWORD WINAPI BluetoothSdpGetAttributeValue( BYTE *stream, ULONG stream_size, USHORT attr_id,
401
SDP_ELEMENT_DATA *data )
402
{
403
struct get_attr_value_data args = {0};
404
405
TRACE( "(%p %lu %u %p)\n", stream, stream_size, attr_id, data );
406
407
if (stream == NULL || data == NULL) return ERROR_INVALID_PARAMETER;
408
409
args.attr_id = attr_id;
410
if (!BluetoothSdpEnumAttributes( stream, stream_size, get_attr_value_callback, &args ))
411
return ERROR_INVALID_PARAMETER;
412
if (!args.attr_stream) return ERROR_FILE_NOT_FOUND;
413
414
return BluetoothSdpGetElementData( args.attr_stream, args.stream_size, data );
415
}
416
417