ServiceDiscoveryProtocol.c 13.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
             LUFA Library
     Copyright (C) Dean Camera, 2010.
              
  dean [at] fourwalledcubicle [dot] com
      www.fourwalledcubicle.com
*/

/*
  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)

  Permission to use, copy, modify, distribute, and sell this 
  software and its documentation for any purpose is hereby granted
  without fee, provided that the above copyright notice appear in 
  all copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting 
  documentation, and that the name of the author not be used in 
  advertising or publicity pertaining to distribution of the 
  software without specific, written prior permission.

  The author disclaim all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

#define  INCLUDE_FROM_SERVICEDISCOVERYPROTOCOL_C
#include "ServiceDiscoveryProtocol.h"

34
/** Service Discovery Protocol attribute, indicationg the service's name. */
35
36
37
38
39
40
41
const struct
{
	uint8_t Header;
	uint8_t Length;
	uint8_t Data[];
} PROGMEM SDP_Attribute_Name = {(SDP_DATATYPE_String | 5), sizeof("SDP"), "SDP"};

42
/** Service Discovery Protocol attribute, indicationg the service's description. */
43
44
45
46
47
48
49
const struct
{
	uint8_t Header;
	uint8_t Length;
	uint8_t Data[];
} PROGMEM SDP_Attribute_Description = {(SDP_DATATYPE_String | 5), sizeof("BT Service Discovery"), "BT Service Discovery"};

50
/** Service Discovery Protocol attribute, indicationg the service's availability. */
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
const struct
{
	uint8_t Header;
	uint8_t Data;
} PROGMEM SDP_Attribute_Availability = {(SDP_DATATYPE_UnsignedInt | 0), 0xFF};

const struct
{
	uint8_t  Header;
	uint16_t Data;
} PROGMEM SDP_Attribute_LanguageOffset = {(SDP_DATATYPE_UnsignedInt | 1), 0x0100};

const struct
{
	uint8_t  Header;
	uint16_t Data;
} PROGMEM SDP_Attribute_ServiceHandle = {(SDP_DATATYPE_UnsignedInt | 1), 0x0001};

const struct
{
	uint8_t     Header;
	uint8_t     Size;
	ClassUUID_t UUIDList[];
} PROGMEM SDP_Attribute_ServiceClassIDs =
75
	{
76
77
78
79
		(SDP_DATATYPE_Sequence | 5), (sizeof(ClassUUID_t) * 1),
		{
			{.Header = (SDP_DATATYPE_UUID | 5), .Size = UUID_SIZE_BYTES, .UUID = {BASE_96BIT_UUID, 0x01, 0x00, 0x00, 0x00}}
		}
80
81
	};

82
83
/** Service Discovery Protocol attribute table, listing all supported attributes of the service. */
const ServiceAttributeTable_t SDP_Attribute_Table[] PROGMEM =
84
	{
85
86
87
88
89
90
		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE,   .Data = &SDP_Attribute_ServiceHandle},
		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICECLASSIDS,       .Data = &SDP_Attribute_ServiceClassIDs},
		{.AttributeID = SDP_ATTRIBUTE_ID_LANGIDOFFSET,          .Data = &SDP_Attribute_LanguageOffset},
		{.AttributeID = SDP_ATTRIBUTE_IDO_PROVIDER    | 0x0100, .Data = &SDP_Attribute_Name},
		{.AttributeID = SDP_ATTRIBUTE_IDO_DESCRIPTION | 0x0100, .Data = &SDP_Attribute_Description},

91
92
		SERVICE_ATTRIBUTE_TABLE_TERMINATOR
	};
93

94
95
96
/** Master service table, listing all supported services (and their attribute tables) of the device, including
 *  each service's UUID.
 */
97
const ServiceTable_t SDP_Services_Table[] PROGMEM =
98
99
100
	{
		{   // 128-bit UUID for the SDP service
			.UUID  = {BASE_96BIT_UUID, 0x01, 0x00, 0x00, 0x00},
101
			.AttributeTable = SDP_Attribute_Table,
102
		},
103
#if 0
104
105
		{   // 128-bit UUID for the RFCOMM service
			.UUID  = {BASE_96BIT_UUID, 0x03, 0x00, 0x00, 0x00},
106
			.AttributeTable = RFCOMM_Attribute_Table,
107
		},
108
#endif
109
110
	};

111
/** Base UUID value common to all standardized Bluetooth services */
112
const uint8_t BaseUUID[] PROGMEM = {BASE_96BIT_UUID, 0x00, 0x00, 0x00, 0x00};
113

114

115
116
117
118
119
120
121
/** Main Service Discovery Protocol packet processing routine. This function processes incomming SDP packets from
 *  a connected Bluetooth device, and sends back appropriate responses to allow other devices to determine the
 *  services the local device exposes.
 *
 *  \param[in]  Data     Incomming packet data containing the SDP request
 *  \param[in]  Channel  Channel the request was issued to by the remote device
 */
122
123
124
125
126
127
128
129
130
131
132
133
void ServiceDiscovery_ProcessPacket(void* Data, Bluetooth_Channel_t* Channel)
{
	SDP_PDUHeader_t* SDPHeader = (SDP_PDUHeader_t*)Data;
	SDPHeader->ParameterLength = SwapEndian_16(SDPHeader->ParameterLength);

	BT_SDP_DEBUG(1, "SDP Packet Received");
	BT_SDP_DEBUG(2, "-- PDU ID: 0x%02X", SDPHeader->PDU);
	BT_SDP_DEBUG(2, "-- Param Length: 0x%04X", SDPHeader->ParameterLength);

	switch (SDPHeader->PDU)
	{
		case SDP_PDU_SERVICESEARCHREQUEST:
134
			ServiceDiscovery_ProcessServiceSearch(SDPHeader, Channel);
135
136
			break;		
		case SDP_PDU_SERVICEATTRIBUTEREQUEST:
137
			ServiceDiscovery_ProcessServiceAttribute(SDPHeader, Channel);
138
139
			break;
		case SDP_PDU_SERVICESEARCHATTRIBUTEREQUEST:
140
			ServiceDiscovery_ProcessServiceSearchAttribute(SDPHeader, Channel);
141
142
143
144
			break;
	}
}

145
static void ServiceDiscovery_ProcessServiceSearch(SDP_PDUHeader_t* SDPHeader, Bluetooth_Channel_t* Channel)
146
147
148
149
{
	BT_SDP_DEBUG(1, "<< Service Search");
}

150
static void ServiceDiscovery_ProcessServiceAttribute(SDP_PDUHeader_t* SDPHeader, Bluetooth_Channel_t* Channel)
151
152
153
154
{
	BT_SDP_DEBUG(1, "<< Service Attribute");
}

155
static void ServiceDiscovery_ProcessServiceSearchAttribute(SDP_PDUHeader_t* SDPHeader, Bluetooth_Channel_t* Channel)
156
{
157
	const void* CurrentParameter = ((void*)SDPHeader + sizeof(SDP_PDUHeader_t));
158
159
160
	
	BT_SDP_DEBUG(1, "<< Service Search Attribute");

161
	uint8_t UUIDList[12][UUID_SIZE_BYTES];
162
163
	uint8_t TotalUUIDs = ServiceDiscovery_GetUUIDList(UUIDList, &CurrentParameter);
	BT_SDP_DEBUG(2, "-- Total UUIDs: %d", TotalUUIDs);
164
165
166
	
	uint16_t MaxAttributeSize = ServiceDiscovery_Read16BitParameter(&CurrentParameter);
	BT_SDP_DEBUG(2, "-- Max Return Attribute Bytes: 0x%04X", MaxAttributeSize);
167
	
168
	uint16_t AttributeList[15][2];
169
170
171
	uint8_t  TotalAttributes = ServiceDiscovery_GetAttributeList(AttributeList, &CurrentParameter);
	BT_SDP_DEBUG(2, "-- Total Attributes: %d", TotalAttributes);
	
172
173
174
	struct
	{
		SDP_PDUHeader_t SDPHeader;
175
		uint16_t        AttributeListByteCount;
176
177
178
		uint8_t         ResponseData[100];
	} ResponsePacket;
	
179
180
	uint8_t* CurrResponsePos = ResponsePacket.ResponseData;

181
182
183
	if (MaxAttributeSize > sizeof(ResponsePacket.ResponseData))
	  MaxAttributeSize = sizeof(ResponsePacket.ResponseData);
	  
184
185
186
187
188
189
190
191
192
193
194
195
196
	uint16_t* TotalResponseSize = ServiceDiscovery_AddDataElementHeader(&CurrResponsePos, SDP_DATATYPE_Sequence);
	for (uint8_t CurrUUIDItem = 0; CurrUUIDItem < TotalUUIDs; CurrUUIDItem++)
	{
		ServiceAttributeTable_t* AttributeTable = ServiceDiscovery_GetAttributeTable(UUIDList[CurrUUIDItem]);
		
		if (AttributeTable == NULL)
		  continue;
		  
		uint16_t* CurrentUUIDResponseSize = ServiceDiscovery_AddDataElementHeader(&CurrResponsePos, SDP_DATATYPE_Sequence);
		for (uint8_t CurrAttribute = 0; CurrAttribute < TotalAttributes; CurrAttribute++)
		{
			uint16_t* AttributeIDRange = AttributeList[CurrAttribute];
		
197
			for (uint32_t CurrAttributeID = AttributeIDRange[0]; CurrAttributeID <= AttributeIDRange[1]; CurrAttributeID++)
198
			{
199
				const void* AttributeValue = ServiceDiscovery_GetAttributeValue(AttributeTable, CurrAttributeID);
200
201
202
203
				
				if (AttributeValue == NULL)
				  continue;

204
205
206
207
208
209
210
211
212
213
214
215
				uint32_t AttributeValueLength = ServiceDiscovery_GetLocalAttributeSize(AttributeValue);
				
				BT_SDP_DEBUG(2, " -- Add Attribute 0x%04X", CurrAttributeID);

				*((uint8_t*)CurrResponsePos) = (1 | SDP_DATATYPE_UnsignedInt);
				CurrResponsePos += sizeof(uint8_t);
				*((uint16_t*)CurrResponsePos) = CurrAttributeID;
				CurrResponsePos += sizeof(uint16_t);				
				memcpy_P(CurrResponsePos, AttributeValue, AttributeValueLength);
				CurrResponsePos += AttributeValueLength;
								
				*CurrentUUIDResponseSize += sizeof(uint8_t) + sizeof(uint16_t) + AttributeValueLength;
216
			}
217
218

			*TotalResponseSize += 3 + *CurrentUUIDResponseSize;
219
220
221
		}
	}

222
	ResponsePacket.AttributeListByteCount    = (*TotalResponseSize + 3);
223
224
225
	ResponsePacket.SDPHeader.PDU             = SDP_PDU_SERVICESEARCHATTRIBUTERESPONSE;
	ResponsePacket.SDPHeader.TransactionID   = SDPHeader->TransactionID;
	ResponsePacket.SDPHeader.ParameterLength = (ResponsePacket.AttributeListByteCount + sizeof(ResponsePacket.AttributeListByteCount));
226

227
228
229
	BT_SDP_DEBUG(1, ">> Service Search Attribute Response");
	BT_SDP_DEBUG(2, "-- Total Parameter Length: 0x%04X", ResponsePacket.SDPHeader.ParameterLength);

230
231
232
233
	Bluetooth_SendPacket(&ResponsePacket, (sizeof(ResponsePacket.SDPHeader) + ResponsePacket.SDPHeader.ParameterLength),
	                     Channel);
}

234
235
static void* ServiceDiscovery_GetAttributeValue(ServiceAttributeTable_t* AttributeTable, uint16_t AttributeID)
{
236
237
	void* CurrTableItemData;
	while ((CurrTableItemData = (void*)pgm_read_word(&AttributeTable->Data)) != NULL)
238
239
	{
		if (pgm_read_word(&AttributeTable->AttributeID) == AttributeID)
240
		  return CurrTableItemData;
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
		
		AttributeTable++;
	}
			
	return NULL;
}

static ServiceAttributeTable_t* ServiceDiscovery_GetAttributeTable(uint8_t* UUID)
{
	for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(ServiceTable_t)); CurrTableItem++)
	{
		if (!(memcmp_P(UUID, SDP_Services_Table[CurrTableItem].UUID, UUID_SIZE_BYTES)))
		  return (ServiceAttributeTable_t*)pgm_read_word(&SDP_Services_Table[CurrTableItem].AttributeTable);
	}
	
	return NULL;
}

static uint8_t ServiceDiscovery_GetAttributeList(uint16_t AttributeList[][2], const void** CurrentParameter)
260
{
261
262
	uint8_t ElementHeaderSize;
	uint8_t TotalAttributes = 0;
263
264

	uint16_t AttributeIDListLength = ServiceDiscovery_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
265
266
267
	BT_SDP_DEBUG(2, "-- Total Attribute Length: 0x%04X", AttributeIDListLength);
	while (AttributeIDListLength)
	{
268
		uint8_t AttributeLength = ServiceDiscovery_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
269
		
270
271
272
273
		memcpy(&AttributeList[TotalAttributes][0], *CurrentParameter, AttributeLength);
		
		if (AttributeLength == 2)
		  memcpy(&AttributeList[TotalAttributes][1], *CurrentParameter, 2);
274

275
276
277
		BT_SDP_DEBUG(2, "-- Attribute: 0x%04X-0x%04X", AttributeList[TotalAttributes][0], AttributeList[TotalAttributes][1]);
		
		TotalAttributes++;
278
		
279
		AttributeIDListLength -= (AttributeLength + ElementHeaderSize);
280
		*CurrentParameter     += AttributeLength;
281
	}
282
	
283
	return TotalAttributes;
284
285
}

286
static uint8_t ServiceDiscovery_GetUUIDList(uint8_t UUIDList[][UUID_SIZE_BYTES], const void** CurrentParameter)
287
288
289
290
291
292
293
294
295
{
	uint8_t ElementHeaderSize;
	uint8_t TotalUUIDs = 0;

	uint16_t ServicePatternLength = ServiceDiscovery_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
	BT_SDP_DEBUG(2, "-- Total UUID Length: 0x%04X", ServicePatternLength);
	while (ServicePatternLength)
	{
		uint8_t* CurrentUUID = UUIDList[TotalUUIDs++];
296
		uint8_t  UUIDLength  = ServiceDiscovery_GetDataElementSize(CurrentParameter, &ElementHeaderSize);
297
		
298
		memcpy_P(CurrentUUID, BaseUUID, sizeof(BaseUUID));
299
		memcpy(&CurrentUUID[(UUIDLength <= 4) ? (UUID_SIZE_BYTES - 4) : 0], *CurrentParameter, UUIDLength);
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
		
		BT_SDP_DEBUG(2, "-- UUID (%d): 0x%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
		                UUIDLength,
		                CurrentUUID[15], CurrentUUID[14], CurrentUUID[13], CurrentUUID[12],
		                CurrentUUID[11], CurrentUUID[10], CurrentUUID[9],  CurrentUUID[8],
		                CurrentUUID[7],  CurrentUUID[6],  CurrentUUID[5],  CurrentUUID[4],
		                CurrentUUID[3],  CurrentUUID[2],  CurrentUUID[1],  CurrentUUID[0]);

		ServicePatternLength -= (UUIDLength + ElementHeaderSize);
		*CurrentParameter    += UUIDLength;
	}
	
	return TotalUUIDs;
}

315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
static uint32_t ServiceDiscovery_GetLocalAttributeSize(const void* AttributeData)
{
	/* Fetch the size of the Data Element structure from the header */
	uint8_t SizeIndex = (pgm_read_byte(AttributeData) & 0x07);
	
	/* Convert the Data Element size index into a size in bytes */
	switch (SizeIndex)
	{
		case 5:
			return (1 + sizeof(uint8_t)) + pgm_read_byte(AttributeData + 1);
		case 6:
			return (1 + sizeof(uint16_t)) + pgm_read_word(AttributeData + 1);
		case 7:
			return (1 + sizeof(uint32_t)) + pgm_read_dword(AttributeData + 1);
		default:
			return (1 + (1 << SizeIndex));
	}

	return 0;
}

336
static uint32_t ServiceDiscovery_GetDataElementSize(const void** DataElementHeader, uint8_t* ElementHeaderSize)
337
{
338
	/* Fetch the size of the Data Element structure from the header, increment the current buffer pos */
339
340
341
342
	uint8_t SizeIndex = (*((uint8_t*)*DataElementHeader) & 0x07);
	*DataElementHeader += sizeof(uint8_t);
	
	uint32_t ElementValue;
343
344

	/* Convert the Data Element size index into a size in bytes */
345
346
347
348
349
350
351
352
353
354
355
356
	switch (SizeIndex)
	{
		case 5:
			ElementValue = *((uint8_t*)*DataElementHeader);
			*DataElementHeader += sizeof(uint8_t);
			*ElementHeaderSize  = (1 + sizeof(uint8_t));
			break;
		case 6:
			ElementValue = *((uint16_t*)*DataElementHeader);
			*DataElementHeader += sizeof(uint16_t);
			*ElementHeaderSize  = (1 + sizeof(uint16_t));
			break;
357
		case 7:
358
359
360
361
			ElementValue = *((uint32_t*)*DataElementHeader);
			*DataElementHeader += sizeof(uint32_t);
			*ElementHeaderSize  = (1 + sizeof(uint32_t));
			break;
362
		default:
363
364
			ElementValue = (1 << SizeIndex);
			*ElementHeaderSize = 1;
365
			break;
366
367
368
369
	}
	
	return ElementValue;
}