From c362709a1e2b0252cffbf1633f7cce41fea4d769 Mon Sep 17 00:00:00 2001
From: Dean Camera <dean@fourwalledcubicle.com>
Date: Wed, 2 Jun 2010 07:05:34 +0000
Subject: [PATCH] The SDP UUID lists should be searched and ALL UUIDs matched
 for a record to be retrieved, not partial matches. Change the SDP code so
 that the entire list must be matched against a service attribute table's
 contents before it is returned.

Change matching algorithm so that it recursively searches through the entire attribute table, and not just pre-specified sequence attributes.

Add browse lists and proper descriptions to the Serial Port service.
---
 .../BluetoothHost/Lib/SDPServices.c           | 205 +++---------------
 .../BluetoothHost/Lib/SDPServices.h           |  23 +-
 .../Lib/ServiceDiscoveryProtocol.c            | 170 +++++++++------
 .../Lib/ServiceDiscoveryProtocol.h            |  12 +-
 LUFA/Common/Common.h                          |   2 +-
 5 files changed, 159 insertions(+), 253 deletions(-)

diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.c b/Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.c
index 96401c010..511e0b074 100644
--- a/Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.c
+++ b/Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.c
@@ -30,86 +30,6 @@
 
 #include "SDPServices.h"
 
-/* ------------------------------ SDP SERVICE ATTRIBUTES  ------------------------------ */
-
-const struct
-{
-	uint8_t  Header;
-	uint32_t Data;
-} PROGMEM SDP_Attribute_ServiceHandle =
-	{
-		(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_32Bit),
-		SWAPENDIAN_32(0x00010000),
-	};
-
-const struct
-{
-	uint8_t    Header;
-	uint16_t   Size;
-	ItemUUID_t UUIDList[];
-} PROGMEM SDP_Attribute_ServiceClassIDs =
-	{
-		(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable16Bit),
-		SWAPENDIAN_16(sizeof(ItemUUID_t) * 1),
-		{
-			{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), SDP_CLASS_UUID}
-		}
-	};
-
-const struct
-{
-	uint8_t     Header;
-	uint8_t     Size;
-	Item16Bit_t VersionList[];
-} PROGMEM SDP_Attribute_Version =
-	{
-		(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
-		(sizeof(Item16Bit_t) * 1),
-		{
-			{(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit), SWAPENDIAN_16(0x0100)}
-		}
-	};
-
-const struct
-{
-	uint8_t Header;
-	uint8_t Size;
-	char    Text[];
-} PROGMEM SDP_Attribute_ServiceName =
-	{
-		(SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),
-		(sizeof("SDP") - 1),
-		"SDP",
-	};
-
-const struct
-{
-	uint8_t Header;
-	uint8_t Size;
-	char    Text[];
-} PROGMEM SDP_Attribute_ServiceDescription =
-	{
-		(SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),
-		(sizeof("Service Discovery Protocol Server") - 1),
-		"Service Discovery Protocol Server",
-	};
-
-/** Service Discovery Protocol attribute table, listing all supported attributes of the service. */
-const ServiceAttributeTable_t SDP_Attribute_Table[] PROGMEM =
-	{
-		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE,    .Data = &SDP_Attribute_ServiceHandle      },
-		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICECLASSIDS,        .Data = &SDP_Attribute_ServiceClassIDs    },
-		{.AttributeID = SDP_ATTRIBUTE_ID_VERSION,                .Data = &SDP_Attribute_Version            },
-		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICENAME,            .Data = &SDP_Attribute_ServiceName        },
-		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION,     .Data = &SDP_Attribute_ServiceDescription },
-
-		SERVICE_ATTRIBUTE_TABLE_TERMINATOR
-	};
-
-
-/* ------------------------------ RFCOMM SERVICE ATTRIBUTES  ------------------------------ */
-
-
 const struct
 {
 	uint8_t  Header;
@@ -147,123 +67,64 @@ const struct
 		{
 			{
 				(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
-				sizeof(UUID_t),
+				sizeof(ItemUUID_t),
 				{
 					{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), L2CAP_UUID},
 				}
 			},
 			{
 				(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
-				sizeof(UUID_t),
+				sizeof(ItemUUID_t),
 				{
 					{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), RFCOMM_UUID},
 				}
-			}
+			},
 		}
 	};
 
-const struct
-{
-	uint8_t Header;
-	uint8_t Size;
-	char    Text[];
-} PROGMEM RFCOMM_Attribute_ServiceName =
-	{
-		(SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),
-		sizeof("Serial Port") - 1,
-		"Serial Port",
-	};
-
-const struct
-{
-	uint8_t Header;
-	uint8_t Size;
-	char    Text[];
-} PROGMEM RFCOMM_Attribute_ServiceDescription =
-	{
-		(SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),
-		sizeof("Wireless Serial Port Service") - 1,
-		"Wireless Serial Port Service",
-	};
-
-const ServiceAttributeTable_t RFCOMM_Attribute_Table[] PROGMEM =
-	{
-		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE,    .Data = &RFCOMM_Attribute_ServiceHandle      },
-		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICECLASSIDS,        .Data = &RFCOMM_Attribute_ServiceClassIDs    },
-		{.AttributeID = SDP_ATTRIBUTE_ID_PROTOCOLDESCRIPTORLIST, .Data = &RFCOMM_Attribute_ProtocolDescriptor },
-		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICENAME,            .Data = &RFCOMM_Attribute_ServiceName        },
-		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION,     .Data = &RFCOMM_Attribute_ServiceDescription },
-
-		SERVICE_ATTRIBUTE_TABLE_TERMINATOR
-	};
-
-
-/* ------------------------------ L2CAP SERVICE ATTRIBUTES  ------------------------------ */
-
-
-const struct
-{
-	uint8_t  Header;
-	uint32_t Data;
-} PROGMEM L2CAP_Attribute_ServiceHandle =
-	{
-		(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_32Bit),
-		SWAPENDIAN_32(0x00010002),
-	};
-
 const struct
 {
 	uint8_t    Header;
 	uint16_t   Size;
 	ItemUUID_t UUIDList[];
-} PROGMEM L2CAP_Attribute_ServiceClassIDs =
+} PROGMEM RFCOMM_Attribute_BrowseGroupList =
 	{
 		(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable16Bit),
-		SWAPENDIAN_16(sizeof(ItemUUID_t) * 2),
+		SWAPENDIAN_16(sizeof(ItemUUID_t) * 1),
 		{
-			{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), SDP_CLASS_UUID },
-			{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), SP_CLASS_UUID  },
+			{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), PUBLICBROWSEGROUP_CLASS_UUID}
 		}
 	};
-
+	
 const struct
 {
-	uint8_t        Header;
-	uint16_t       Size;
-
-	ItemProtocol_t ProtocolList[];
-} PROGMEM L2CAP_Attribute_ProtocolDescriptor =
-	{
-		(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable16Bit),
-		SWAPENDIAN_16(sizeof(ItemProtocol_t) * 2),
-		{
+	uint8_t      Header;
+	uint8_t      Size;
+	ItemLangID_t OffsetList[];
+} PROGMEM RFCOMM_Attribute_LanguageBaseIDOffset =
+	{
+		.Header = (SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
+		.Size   = (sizeof(ItemLangID_t) * 1),
+		.OffsetList =
 			{
-				(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
-				sizeof(UUID_t),
 				{
-					{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), L2CAP_UUID},
-				}
-			},
-			{
-				(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
-				sizeof(UUID_t),
-				{
-					{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), RFCOMM_UUID},
+					{(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit), SWAPENDIAN_16(0x454E)},
+					{(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit), SWAPENDIAN_16(0x006A)},
+					{(SDP_DATATYPE_UnsignedInt | SDP_DATASIZE_16Bit), SWAPENDIAN_16(0x0100)},
 				}
 			}
-		}
-	};
+	};	
 	
 const struct
 {
 	uint8_t Header;
 	uint8_t Size;
 	char    Text[];
-} PROGMEM L2CAP_Attribute_ServiceName =
+} PROGMEM RFCOMM_Attribute_ServiceName =
 	{
 		(SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),
-		sizeof("L2CAP") - 1,
-		"L2CAP",
+		sizeof("Serial Port") - 1,
+		"Serial Port",
 	};
 
 const struct
@@ -271,20 +132,22 @@ const struct
 	uint8_t Header;
 	uint8_t Size;
 	char    Text[];
-} PROGMEM L2CAP_Attribute_ServiceDescription =
+} PROGMEM RFCOMM_Attribute_ServiceDescription =
 	{
 		(SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),
-		sizeof("Logical Link Layer") - 1,
-		"Logical Link Layer",
+		sizeof("Wireless Serial Port Service") - 1,
+		"Wireless Serial Port Service",
 	};
 
-const ServiceAttributeTable_t L2CAP_Attribute_Table[] PROGMEM =
+const ServiceAttributeTable_t PROGMEM RFCOMM_Attribute_Table[] =
 	{
-		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE,    .Data = &L2CAP_Attribute_ServiceHandle      },
-		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICECLASSIDS,        .Data = &L2CAP_Attribute_ServiceClassIDs    },
-		{.AttributeID = SDP_ATTRIBUTE_ID_PROTOCOLDESCRIPTORLIST, .Data = &L2CAP_Attribute_ProtocolDescriptor },
-		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICENAME,            .Data = &L2CAP_Attribute_ServiceName        },
-		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION,     .Data = &L2CAP_Attribute_ServiceDescription },
-		
+		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE,    .Data = &RFCOMM_Attribute_ServiceHandle       },
+		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICECLASSIDS,        .Data = &RFCOMM_Attribute_ServiceClassIDs     },
+		{.AttributeID = SDP_ATTRIBUTE_ID_PROTOCOLDESCRIPTORLIST, .Data = &RFCOMM_Attribute_ProtocolDescriptor  },
+		{.AttributeID = SDP_ATTRIBUTE_ID_BROWSEGROUPLIST,        .Data = &RFCOMM_Attribute_BrowseGroupList     },
+		{.AttributeID = SDP_ATTRIBUTE_ID_LANGUAGEBASEATTROFFSET, .Data = &RFCOMM_Attribute_LanguageBaseIDOffset},
+		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICENAME,            .Data = &RFCOMM_Attribute_ServiceName         },
+		{.AttributeID = SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION,     .Data = &RFCOMM_Attribute_ServiceDescription  },
+
 		SERVICE_ATTRIBUTE_TABLE_TERMINATOR
 	};
diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.h b/Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.h
index a11850dcb..654ed94e0 100644
--- a/Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.h
+++ b/Demos/Host/Incomplete/BluetoothHost/Lib/SDPServices.h
@@ -49,14 +49,15 @@
 		#define SDP_UUID                                {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}
 		#define RFCOMM_UUID                             {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}}
 		#define L2CAP_UUID                              {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x01, 0x00}}
-		#define UPNP_UUID                               {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x00, 0x10}}
 		#define SDP_CLASS_UUID                          {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x10, 0x00}}
 		#define SP_CLASS_UUID                           {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x11, 0x01}}
-		#define UPNP_CLASS_UUID                         {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x12, 0x00}}
+		#define PUBLICBROWSEGROUP_CLASS_UUID            {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x10, 0x02}}
 		
 		#define SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE    0x0000
 		#define SDP_ATTRIBUTE_ID_SERVICECLASSIDS        0x0001
 		#define SDP_ATTRIBUTE_ID_PROTOCOLDESCRIPTORLIST 0x0004
+		#define SDP_ATTRIBUTE_ID_BROWSEGROUPLIST        0x0005
+		#define SDP_ATTRIBUTE_ID_LANGUAGEBASEATTROFFSET 0x0006
 		#define SDP_ATTRIBUTE_ID_VERSION                0x0200
 		#define SDP_ATTRIBUTE_ID_SERVICENAME            0x0100
 		#define SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION     0x0101
@@ -87,15 +88,6 @@
 			const void* Data; /**< Pointer to the attribute data, located in PROGMEM memory space */
 		} ServiceAttributeTable_t;
 
-		/** Structure for the association of service UUID values to attribute tables stored in FLASH. A table of these
-		 *  structures can then be built up for each supported UUID service within the device.
-		 */
-		typedef struct
-		{
-			UUID_t      UUID; /**< UUID of a service supported by the device */
-			const void* AttributeTable; /**< Pointer to the UUID's attribute table, located in PROGMEM memory space */
-		} ServiceTable_t;
-
 		/** Structure for a list of Data Elements containing 8-bit integers, for service attributes requiring such lists. */
 		typedef struct
 		{
@@ -138,9 +130,14 @@
 			} Protocol;
 		} ItemProtocol_t;
 		
+		typedef struct
+		{
+			Item16Bit_t LanguageID;
+			Item16Bit_t EncodingID;
+			Item16Bit_t OffsetID;
+		} ItemLangID_t;
+		
 	/* External Variables: */
-		extern const ServiceAttributeTable_t SDP_Attribute_Table[];
 		extern const ServiceAttributeTable_t RFCOMM_Attribute_Table[];
-		extern const ServiceAttributeTable_t L2CAP_Attribute_Table[];
 		
 #endif
diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.c b/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.c
index c6b394819..ffe2be0b7 100644
--- a/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.c
+++ b/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.c
@@ -31,14 +31,10 @@
 #define  INCLUDE_FROM_SERVICEDISCOVERYPROTOCOL_C
 #include "ServiceDiscoveryProtocol.h"
 
-/** Master service table, listing all supported services (and their attribute tables) of the device, including
- *  each service's UUID.
- */
-const ServiceTable_t SDP_Services_Table[] PROGMEM =
+/** Service attribute table list, containing a pointer to each service attribute table the device contains */
+const ServiceAttributeTable_t* SDP_Services_Table[] PROGMEM =
 	{
-		{ .UUID  = SDP_UUID   , .AttributeTable = SDP_Attribute_Table     },
-		{ .UUID  = RFCOMM_UUID, .AttributeTable = RFCOMM_Attribute_Table  },
-		{ .UUID  = L2CAP_UUID , .AttributeTable = L2CAP_Attribute_Table   },
+		RFCOMM_Attribute_Table,
 	};
 
 /** Base UUID value common to all standardized Bluetooth services */
@@ -101,25 +97,25 @@ static void SDP_ProcessServiceSearch(const SDP_PDUHeader_t* const SDPHeader, Blu
 		uint16_t        CurrentServiceRecordCount;
 		uint8_t         ResponseData[100];
 	} ResponsePacket;
+	
+	uint8_t AddedServiceHandles = 0;
 
 	/* Create a pointer to the buffer to indicate the current location for response data to be added */
 	void* CurrResponsePos = ResponsePacket.ResponseData;
-	
-	uint8_t AddedServiceHandles = 0;
 
-	/* Search through the list of UUIDs one at a time looking for matching search Attributes */
-	for (uint8_t CurrUUIDItem = 0; CurrUUIDItem < TotalUUIDs; CurrUUIDItem++)
+	/* Search through the global service list an item at a time */
+	for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(void*)); CurrTableItem++)
 	{
-		ServiceAttributeTable_t* AttributeTable;
+		/* Read in a pointer to the current UUID table entry's Attribute table */
+		ServiceAttributeTable_t* CurrAttributeTable = pgm_read_ptr(&SDP_Services_Table[CurrTableItem]);
 
-		/* Retrieve the attribute table of the current search UUID from the global UUID table if it exists */
-		if ((AttributeTable = SDP_GetAttributeTable(UUIDList[CurrUUIDItem])) == NULL)
+		if (!(SDP_SearchServiceTable(UUIDList, TotalUUIDs, CurrAttributeTable)))
 		  continue;
-		  
-		BT_SDP_DEBUG(2, " -- Found UUID %d in table", CurrUUIDItem);
+
+		BT_SDP_DEBUG(2, " -- Found search match in table");
 
 		/* Retrieve a PROGMEM pointer to the value of the service's record handle */
-		const void* AttributeValue = SDP_GetAttributeValue(AttributeTable, SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE);
+		const void* AttributeValue = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE);
 
 		/* Copy over the service record handle to the response list */
 		uint8_t AttrHeaderSize;
@@ -197,10 +193,10 @@ static void SDP_ProcessServiceAttribute(const SDP_PDUHeader_t* const SDPHeader,
 	uint16_t TotalResponseSize = 0;
 
 	/* Search through the global UUID list an item at a time */
-	for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(ServiceTable_t)); CurrTableItem++)
+	for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(void*)); CurrTableItem++)
 	{
 		/* Read in a pointer to the current UUID table entry's Attribute table */
-		ServiceAttributeTable_t* CurrAttributeTable = (ServiceAttributeTable_t*)pgm_read_word(&SDP_Services_Table[CurrTableItem].AttributeTable);
+		ServiceAttributeTable_t* CurrAttributeTable = pgm_read_ptr(&SDP_Services_Table[CurrTableItem]);
 		
 		/* Retrieve a PROGMEM pointer to the value of the Service Record Handle */
 		const void* ServiceRecord = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE);
@@ -288,19 +284,19 @@ static void SDP_ProcessServiceSearchAttribute(const SDP_PDUHeader_t* const SDPHe
 	/* Add the outer Data Element Sequence header for all of the retrieved Attributes */
 	uint16_t* TotalResponseSize = SDP_AddSequence16(&CurrResponsePos);
 	
-	/* Search through the list of UUIDs one at a time looking for matching search Attributes */
-	for (uint8_t CurrUUIDItem = 0; CurrUUIDItem < TotalUUIDs; CurrUUIDItem++)
+	/* Search through the global service list an item at a time */
+	for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(void*)); CurrTableItem++)
 	{
-		ServiceAttributeTable_t* AttributeTable;
+		/* Read in a pointer to the current UUID table entry's Attribute table */
+		ServiceAttributeTable_t* CurrAttributeTable = pgm_read_ptr(&SDP_Services_Table[CurrTableItem]);
 
-		/* Retrieve the attribute table of the current search UUID from the global UUID table if it exists */
-		if ((AttributeTable = SDP_GetAttributeTable(UUIDList[CurrUUIDItem])) == NULL)
+		if (!(SDP_SearchServiceTable(UUIDList, TotalUUIDs, CurrAttributeTable)))
 		  continue;
 		  
-		BT_SDP_DEBUG(2, " -- Found UUID %d in table", CurrUUIDItem);
+		BT_SDP_DEBUG(2, " -- Found search match in table");
 
 		/* Add the listed attributes for the found UUID to the response */
-		*TotalResponseSize += SDP_AddListedAttributesToResponse(AttributeTable, AttributeList, TotalAttributes, 
+		*TotalResponseSize += SDP_AddListedAttributesToResponse(CurrAttributeTable, AttributeList, TotalAttributes, 
 		                                                        &CurrResponsePos);
 	}
 	
@@ -355,7 +351,7 @@ static uint16_t SDP_AddListedAttributesToResponse(const ServiceAttributeTable_t*
 		void*     AttributeValue;
 		
 		/* Look through the current service's attribute list, examining all the attributes */
-		while ((AttributeValue = (void*)pgm_read_word(&AttributeTable->Data)) != NULL)
+		while ((AttributeValue = pgm_read_ptr(&AttributeTable->Data)) != NULL)
 		{
 			/* Get the current Attribute's ID from the current attribute table entry */
 			uint16_t CurrAttributeID = pgm_read_word(&AttributeTable->AttributeID);
@@ -421,7 +417,7 @@ static void* SDP_GetAttributeValue(const ServiceAttributeTable_t* AttributeTable
 	void* CurrTableItemData;
 	
 	/* Search through the current Attribute table, abort when the terminator item has been reached */
-	while ((CurrTableItemData = (void*)pgm_read_word(&AttributeTable->Data)) != NULL)
+	while ((CurrTableItemData = pgm_read_ptr(&AttributeTable->Data)) != NULL)
 	{
 		/* Check if the current Attribute ID matches the search ID - if so return a pointer to it */
 		if (pgm_read_word(&AttributeTable->AttributeID) == AttributeID)
@@ -433,49 +429,91 @@ static void* SDP_GetAttributeValue(const ServiceAttributeTable_t* AttributeTable
 	return NULL;
 }
 
-/** Retrieves the Attribute table for the given UUID if it exists.
+/** Retrieves the Attribute table for the given UUID list if it exists.
  *
- *  \param[in] UUID  UUID to search for
+ *  \param[in] UUIDList            List of UUIDs which must be matched within the service attribute table
+ *  \param[in] TotalUUIDs          Total number of UUIDs stored in the UUID list
+ *  \param[in] CurrAttributeTable  Pointer to the service attribute table to search through
  *
- *  \return Pointer to the UUID's associated Attribute table if found in the global UUID table, NULL otherwise
+ *  \return True if all the UUIDs given in the UUID list appear in the given attribute table, false otherwise
  */
-static ServiceAttributeTable_t* SDP_GetAttributeTable(const uint8_t* const UUID)
+static bool SDP_SearchServiceTable(uint8_t UUIDList[][UUID_SIZE_BYTES], const uint8_t TotalUUIDs,
+			                       const ServiceAttributeTable_t* CurrAttributeTable)
 {
-	/* Search through the global UUID list an item at a time */
-	for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(ServiceTable_t)); CurrTableItem++)
+	bool UUIDMatch[TotalUUIDs];	
+	
+	/* Set all the match flags to false (not matched) before starting the search */
+	memset(UUIDMatch, false, sizeof(UUIDMatch));
+
+	const void* CurrAttribute;
+	
+	/* Search through the current attribute table, checking each attribute value for UUID matches */
+	while ((CurrAttribute = pgm_read_ptr(&CurrAttributeTable->Data)) != NULL)
 	{
-		/* Read in a pointer to the current UUID table entry's Attribute table */
-		ServiceAttributeTable_t* CurrAttributeTable = (ServiceAttributeTable_t*)pgm_read_word(&SDP_Services_Table[CurrTableItem].AttributeTable);
+		SDP_CheckUUIDMatch(UUIDList, TotalUUIDs, UUIDMatch, CurrAttribute);
+		CurrAttributeTable++;
+	}
+
+	/* Determine how many UUID matches in the list we have found */
+	uint8_t UUIDMatches = 0;
+	for (uint8_t i = 0; i < TotalUUIDs; i++)
+	{
+		if (UUIDMatch[i])
+		  UUIDMatches++;
+	}
 	
-		/* If the current table item's UUID matches the search UUID, return a pointer the table item's Attribute table */
-		if (!(memcmp_P(UUID, &SDP_Services_Table[CurrTableItem].UUID, UUID_SIZE_BYTES)))
-		  return CurrAttributeTable;
-		
-		/* Retrieve the list of the service's Class UUIDs from its Attribute table */
-		void* ClassUUIDs = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICECLASSIDS);
+	/* If all UUIDs have been matched to the current service, return true */
+	return (UUIDMatches == TotalUUIDs);
+}
+
+/** Recursively upwraps the given locally stored attribute (in PROGMEM space), searching for UUIDs to match against
+ *  the given UUID list. As matches are found, they are indicated in the UUIDMatch flag list.
+ *
+ *  \param[in]      UUIDList       List of UUIDs which must be matched within the service attribute table
+ *  \param[in]      TotalUUIDs     Total number of UUIDs stored in the UUID list
+ *  \param[in, out] UUIDMatch      Array of flags indicating which UUIDs in the list have already been matched
+ *  \param[in]      CurrAttribute  Pointer to the current attribute to search through
+ *
+ *  \return True if all the UUIDs given in the UUID list appear in the given attribute table, false otherwise
+ */
+static void SDP_CheckUUIDMatch(uint8_t UUIDList[][UUID_SIZE_BYTES], const uint8_t TotalUUIDs, bool UUIDMatch[],
+                               const void* CurrAttribute)
+{
+	uint8_t CurrAttributeType = (pgm_read_byte(CurrAttribute) & ~0x07);
+
+	/* Check the data type of the current attribute value - if UUID, compare, if Sequence, unwrap and recurse */
+	if (CurrAttributeType == SDP_DATATYPE_UUID)
+	{
+		/* Look for matches in the UUID list against the current attribute UUID value */
+		for (uint8_t i = 0; i < TotalUUIDs; i++)
+		{
+			if (!(UUIDMatch[i]) && !(memcmp_P(UUIDList[i], (CurrAttribute + 1), UUID_SIZE_BYTES)))
+			{
+				/* Indicate match found for the current attribute UUID and early-abort */
+				UUIDMatch[i] = true;
+				break;
+			}
+		}
+	}
+	else if (CurrAttributeType == SDP_DATATYPE_Sequence)
+	{
+		uint8_t  SequenceHeaderSize;
+		uint16_t SequenceSize = SDP_GetLocalAttributeContainerSize(CurrAttribute, &SequenceHeaderSize);
 		
-		/* Go to the next UUID in the table if the current item does not have a list of Class UUIDs */
-		if (ClassUUIDs == NULL)
-		  continue;
-		  
-		/* Retrieve the size of the Class UUID list and skip past the header to the first Class UUID in the list */ 
-		uint8_t  ClassUUIDListHeaderSize;
-		uint16_t ClassUUIDListSize = SDP_GetLocalAttributeContainerSize(ClassUUIDs, &ClassUUIDListHeaderSize);
-		ClassUUIDs += ClassUUIDListHeaderSize;
+		CurrAttribute += SequenceHeaderSize;
 		
-		/* Check each class UUID in turn for a match */
-		while (ClassUUIDListSize)
+		/* Recursively unwrap the sequence container, and re-search its contents for UUIDs */
+		while (SequenceSize)
 		{
-			/* Current Service UUID's Class UUID list has a matching entry, return the Attribute table */
-			if (!(memcmp_P(UUID, &((ItemUUID_t*)ClassUUIDs)->UUID, UUID_SIZE_BYTES)))
-			  return CurrAttributeTable;
-		
-			ClassUUIDListSize -= sizeof(ItemUUID_t);
-			ClassUUIDs        += sizeof(ItemUUID_t);
-		}	
-	}
-	
-	return NULL;
+			uint8_t  InnerHeaderSize;
+			uint16_t InnerSize = SDP_GetLocalAttributeContainerSize(CurrAttribute, &InnerHeaderSize);
+			
+			SDP_CheckUUIDMatch(UUIDList, TotalUUIDs, UUIDMatch, CurrAttribute);
+						
+			SequenceSize  -= InnerHeaderSize + InnerSize;
+			CurrAttribute += InnerHeaderSize + InnerSize;
+		}
+	}	
 }
 
 /** Reads in the collection of Attribute ranges from the input buffer's Data Element Sequence container, into the given 
@@ -620,20 +658,20 @@ static uint32_t SDP_GetDataElementSize(const void** const DataElementHeader, uin
 	switch (SizeIndex)
 	{
 		case SDP_DATASIZE_Variable8Bit:
-			ElementValueSize    = SDP_ReadData8(DataElementHeader);
 			*ElementHeaderSize  = (1 + sizeof(uint8_t));
+			ElementValueSize    = SDP_ReadData8(DataElementHeader);
 			break;
 		case SDP_DATASIZE_Variable16Bit:
-			ElementValueSize    = SDP_ReadData16(DataElementHeader);
 			*ElementHeaderSize  = (1 + sizeof(uint16_t));
+			ElementValueSize    = SDP_ReadData16(DataElementHeader);
 			break;
 		case SDP_DATASIZE_Variable32Bit:
-			ElementValueSize    = SDP_ReadData32(DataElementHeader);
 			*ElementHeaderSize  = (1 + sizeof(uint32_t));
+			ElementValueSize    = SDP_ReadData32(DataElementHeader);
 			break;
 		default:
-			ElementValueSize    = (1 << SizeIndex);
 			*ElementHeaderSize  = 1;
+			ElementValueSize    = (1 << SizeIndex);
 			break;
 	}
 	
diff --git a/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.h b/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.h
index ec55b2fb1..50f436642 100644
--- a/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.h
+++ b/Demos/Host/Incomplete/BluetoothHost/Lib/ServiceDiscoveryProtocol.h
@@ -50,7 +50,7 @@
 		
 	/* Macros: */
 		#define BT_SDP_DEBUG(l, s, ...)                 do { if (SDP_DEBUG_LEVEL >= l) printf_P(PSTR("(SDP) " s "\r\n"), ##__VA_ARGS__); } while (0)
-		#define SDP_DEBUG_LEVEL                         2
+		#define SDP_DEBUG_LEVEL                         1
 		
 		#define SDP_PDU_ERRORRESPONSE                   0x01
 		#define SDP_PDU_SERVICESEARCHREQUEST            0x02
@@ -59,6 +59,8 @@
 		#define SDP_PDU_SERVICEATTRIBUTERESPONSE        0x05
 		#define SDP_PDU_SERVICESEARCHATTRIBUTEREQUEST   0x06
 		#define SDP_PDU_SERVICESEARCHATTRIBUTERESPONSE  0x07
+		
+		#define pgm_read_ptr(x)                         (void*)pgm_read_word(x)
 
 	/* Enums: */
 		/** Data sizes for SDP Data Element headers, to indicate the size of the data contained in the element. When creating
@@ -213,9 +215,15 @@
 			                                                  const uint8_t TotalAttributes, void** const BufferPos);
 			static uint16_t SDP_AddAttributeToResponse(const uint16_t AttributeID, const void* AttributeValue, void** ResponseBuffer);
 			static void*    SDP_GetAttributeValue(const ServiceAttributeTable_t* AttributeTable, const uint16_t AttributeID);
-			static ServiceAttributeTable_t* SDP_GetAttributeTable(const uint8_t* const UUID);
+
+			static bool     SDP_SearchServiceTable(uint8_t UUIDList[][UUID_SIZE_BYTES], const uint8_t TotalUUIDs,
+			                                       const ServiceAttributeTable_t* CurrAttributeTable);
+			static void     SDP_CheckUUIDMatch(uint8_t UUIDList[][UUID_SIZE_BYTES], const uint8_t TotalUUIDs, bool UUIDMatch[],
+			                                   const void* CurrAttribute);
+
 			static uint8_t  SDP_GetAttributeList(uint16_t AttributeList[][2], const void** const CurrentParameter);
 			static uint8_t  SDP_GetUUIDList(uint8_t UUIDList[][UUID_SIZE_BYTES], const void** const CurrentParameter);
+
 			static uint32_t SDP_GetLocalAttributeContainerSize(const void* const AttributeData, uint8_t* const HeaderSize);
 			static uint32_t SDP_GetDataElementSize(const void** const AttributeHeader, uint8_t* const ElementHeaderSize);
 		#endif
diff --git a/LUFA/Common/Common.h b/LUFA/Common/Common.h
index 76307d7e9..14473cddc 100644
--- a/LUFA/Common/Common.h
+++ b/LUFA/Common/Common.h
@@ -111,7 +111,7 @@
 																"Assertion \"%s\" failed.\r\n"),     \
 																__FILE__, __func__, __LINE__, #x); } \
 			                                }MACROE
-
+											
 		/* Inline Functions: */
 			/** Function to reverse the individual bits in a byte - i.e. bit 7 is moved to bit 0, bit 6 to bit 1,
 			 *  etc.
-- 
GitLab