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.
pull/1469/head
Dean Camera 15 years ago
parent da51c1f974
commit c362709a1e

@ -30,86 +30,6 @@
#include "SDPServices.h" #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 const struct
{ {
uint8_t Header; uint8_t Header;
@ -147,68 +67,19 @@ const struct
{ {
{ {
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit), (SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
sizeof(UUID_t), sizeof(ItemUUID_t),
{ {
{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), L2CAP_UUID}, {(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), L2CAP_UUID},
} }
}, },
{ {
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit), (SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
sizeof(UUID_t), sizeof(ItemUUID_t),
{ {
{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), RFCOMM_UUID}, {(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 const struct
@ -216,40 +87,30 @@ const struct
uint8_t Header; uint8_t Header;
uint16_t Size; uint16_t Size;
ItemUUID_t UUIDList[]; ItemUUID_t UUIDList[];
} PROGMEM L2CAP_Attribute_ServiceClassIDs = } PROGMEM RFCOMM_Attribute_BrowseGroupList =
{ {
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable16Bit), (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), PUBLICBROWSEGROUP_CLASS_UUID}
{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), SP_CLASS_UUID },
} }
}; };
const struct const struct
{ {
uint8_t Header; uint8_t Header;
uint16_t Size; uint8_t Size;
ItemLangID_t OffsetList[];
ItemProtocol_t ProtocolList[]; } PROGMEM RFCOMM_Attribute_LanguageBaseIDOffset =
} PROGMEM L2CAP_Attribute_ProtocolDescriptor =
{
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable16Bit),
SWAPENDIAN_16(sizeof(ItemProtocol_t) * 2),
{ {
.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_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)},
{
(SDP_DATATYPE_Sequence | SDP_DATASIZE_Variable8Bit),
sizeof(UUID_t),
{
{(SDP_DATATYPE_UUID | SDP_DATASIZE_128Bit), RFCOMM_UUID},
}
} }
} }
}; };
@ -259,11 +120,11 @@ const struct
uint8_t Header; uint8_t Header;
uint8_t Size; uint8_t Size;
char Text[]; char Text[];
} PROGMEM L2CAP_Attribute_ServiceName = } PROGMEM RFCOMM_Attribute_ServiceName =
{ {
(SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit), (SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),
sizeof("L2CAP") - 1, sizeof("Serial Port") - 1,
"L2CAP", "Serial Port",
}; };
const struct const struct
@ -271,20 +132,22 @@ const struct
uint8_t Header; uint8_t Header;
uint8_t Size; uint8_t Size;
char Text[]; char Text[];
} PROGMEM L2CAP_Attribute_ServiceDescription = } PROGMEM RFCOMM_Attribute_ServiceDescription =
{ {
(SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit), (SDP_DATATYPE_String | SDP_DATASIZE_Variable8Bit),
sizeof("Logical Link Layer") - 1, sizeof("Wireless Serial Port Service") - 1,
"Logical Link Layer", "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_SERVICERECORDHANDLE, .Data = &RFCOMM_Attribute_ServiceHandle },
{.AttributeID = SDP_ATTRIBUTE_ID_SERVICECLASSIDS, .Data = &L2CAP_Attribute_ServiceClassIDs }, {.AttributeID = SDP_ATTRIBUTE_ID_SERVICECLASSIDS, .Data = &RFCOMM_Attribute_ServiceClassIDs },
{.AttributeID = SDP_ATTRIBUTE_ID_PROTOCOLDESCRIPTORLIST, .Data = &L2CAP_Attribute_ProtocolDescriptor }, {.AttributeID = SDP_ATTRIBUTE_ID_PROTOCOLDESCRIPTORLIST, .Data = &RFCOMM_Attribute_ProtocolDescriptor },
{.AttributeID = SDP_ATTRIBUTE_ID_SERVICENAME, .Data = &L2CAP_Attribute_ServiceName }, {.AttributeID = SDP_ATTRIBUTE_ID_BROWSEGROUPLIST, .Data = &RFCOMM_Attribute_BrowseGroupList },
{.AttributeID = SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION, .Data = &L2CAP_Attribute_ServiceDescription }, {.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 SERVICE_ATTRIBUTE_TABLE_TERMINATOR
}; };

@ -49,14 +49,15 @@
#define SDP_UUID {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}} #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 RFCOMM_UUID {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}}
#define L2CAP_UUID {BASE_80BIT_UUID, {0x00, 0x00, 0x00, 0x00, 0x01, 0x00}} #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 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 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_SERVICERECORDHANDLE 0x0000
#define SDP_ATTRIBUTE_ID_SERVICECLASSIDS 0x0001 #define SDP_ATTRIBUTE_ID_SERVICECLASSIDS 0x0001
#define SDP_ATTRIBUTE_ID_PROTOCOLDESCRIPTORLIST 0x0004 #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_VERSION 0x0200
#define SDP_ATTRIBUTE_ID_SERVICENAME 0x0100 #define SDP_ATTRIBUTE_ID_SERVICENAME 0x0100
#define SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION 0x0101 #define SDP_ATTRIBUTE_ID_SERVICEDESCRIPTION 0x0101
@ -87,15 +88,6 @@
const void* Data; /**< Pointer to the attribute data, located in PROGMEM memory space */ const void* Data; /**< Pointer to the attribute data, located in PROGMEM memory space */
} ServiceAttributeTable_t; } 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. */ /** Structure for a list of Data Elements containing 8-bit integers, for service attributes requiring such lists. */
typedef struct typedef struct
{ {
@ -138,9 +130,14 @@
} Protocol; } Protocol;
} ItemProtocol_t; } ItemProtocol_t;
typedef struct
{
Item16Bit_t LanguageID;
Item16Bit_t EncodingID;
Item16Bit_t OffsetID;
} ItemLangID_t;
/* External Variables: */ /* External Variables: */
extern const ServiceAttributeTable_t SDP_Attribute_Table[];
extern const ServiceAttributeTable_t RFCOMM_Attribute_Table[]; extern const ServiceAttributeTable_t RFCOMM_Attribute_Table[];
extern const ServiceAttributeTable_t L2CAP_Attribute_Table[];
#endif #endif

@ -31,14 +31,10 @@
#define INCLUDE_FROM_SERVICEDISCOVERYPROTOCOL_C #define INCLUDE_FROM_SERVICEDISCOVERYPROTOCOL_C
#include "ServiceDiscoveryProtocol.h" #include "ServiceDiscoveryProtocol.h"
/** Master service table, listing all supported services (and their attribute tables) of the device, including /** Service attribute table list, containing a pointer to each service attribute table the device contains */
* each service's UUID. const ServiceAttributeTable_t* SDP_Services_Table[] PROGMEM =
*/
const ServiceTable_t SDP_Services_Table[] PROGMEM =
{ {
{ .UUID = SDP_UUID , .AttributeTable = SDP_Attribute_Table }, RFCOMM_Attribute_Table,
{ .UUID = RFCOMM_UUID, .AttributeTable = RFCOMM_Attribute_Table },
{ .UUID = L2CAP_UUID , .AttributeTable = L2CAP_Attribute_Table },
}; };
/** Base UUID value common to all standardized Bluetooth services */ /** Base UUID value common to all standardized Bluetooth services */
@ -102,24 +98,24 @@ static void SDP_ProcessServiceSearch(const SDP_PDUHeader_t* const SDPHeader, Blu
uint8_t ResponseData[100]; uint8_t ResponseData[100];
} ResponsePacket; } ResponsePacket;
uint8_t AddedServiceHandles = 0;
/* Create a pointer to the buffer to indicate the current location for response data to be added */ /* Create a pointer to the buffer to indicate the current location for response data to be added */
void* CurrResponsePos = ResponsePacket.ResponseData; void* CurrResponsePos = ResponsePacket.ResponseData;
uint8_t AddedServiceHandles = 0; /* Search through the global service list an item at a time */
for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(void*)); CurrTableItem++)
/* Search through the list of UUIDs one at a time looking for matching search Attributes */
for (uint8_t CurrUUIDItem = 0; CurrUUIDItem < TotalUUIDs; CurrUUIDItem++)
{ {
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 (!(SDP_SearchServiceTable(UUIDList, TotalUUIDs, CurrAttributeTable)))
if ((AttributeTable = SDP_GetAttributeTable(UUIDList[CurrUUIDItem])) == NULL)
continue; 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 */ /* 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 */ /* Copy over the service record handle to the response list */
uint8_t AttrHeaderSize; uint8_t AttrHeaderSize;
@ -197,10 +193,10 @@ static void SDP_ProcessServiceAttribute(const SDP_PDUHeader_t* const SDPHeader,
uint16_t TotalResponseSize = 0; uint16_t TotalResponseSize = 0;
/* Search through the global UUID list an item at a time */ /* 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 */ /* 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 */ /* Retrieve a PROGMEM pointer to the value of the Service Record Handle */
const void* ServiceRecord = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE); 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 */ /* Add the outer Data Element Sequence header for all of the retrieved Attributes */
uint16_t* TotalResponseSize = SDP_AddSequence16(&CurrResponsePos); uint16_t* TotalResponseSize = SDP_AddSequence16(&CurrResponsePos);
/* Search through the list of UUIDs one at a time looking for matching search Attributes */ /* Search through the global service list an item at a time */
for (uint8_t CurrUUIDItem = 0; CurrUUIDItem < TotalUUIDs; CurrUUIDItem++) 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 (!(SDP_SearchServiceTable(UUIDList, TotalUUIDs, CurrAttributeTable)))
if ((AttributeTable = SDP_GetAttributeTable(UUIDList[CurrUUIDItem])) == NULL)
continue; 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 */ /* Add the listed attributes for the found UUID to the response */
*TotalResponseSize += SDP_AddListedAttributesToResponse(AttributeTable, AttributeList, TotalAttributes, *TotalResponseSize += SDP_AddListedAttributesToResponse(CurrAttributeTable, AttributeList, TotalAttributes,
&CurrResponsePos); &CurrResponsePos);
} }
@ -355,7 +351,7 @@ static uint16_t SDP_AddListedAttributesToResponse(const ServiceAttributeTable_t*
void* AttributeValue; void* AttributeValue;
/* Look through the current service's attribute list, examining all the attributes */ /* 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 */ /* Get the current Attribute's ID from the current attribute table entry */
uint16_t CurrAttributeID = pgm_read_word(&AttributeTable->AttributeID); uint16_t CurrAttributeID = pgm_read_word(&AttributeTable->AttributeID);
@ -421,7 +417,7 @@ static void* SDP_GetAttributeValue(const ServiceAttributeTable_t* AttributeTable
void* CurrTableItemData; void* CurrTableItemData;
/* Search through the current Attribute table, abort when the terminator item has been reached */ /* 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 */ /* Check if the current Attribute ID matches the search ID - if so return a pointer to it */
if (pgm_read_word(&AttributeTable->AttributeID) == AttributeID) if (pgm_read_word(&AttributeTable->AttributeID) == AttributeID)
@ -433,49 +429,91 @@ static void* SDP_GetAttributeValue(const ServiceAttributeTable_t* AttributeTable
return NULL; 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++)
{ {
/* Read in a pointer to the current UUID table entry's Attribute table */ bool UUIDMatch[TotalUUIDs];
ServiceAttributeTable_t* CurrAttributeTable = (ServiceAttributeTable_t*)pgm_read_word(&SDP_Services_Table[CurrTableItem].AttributeTable);
/* If the current table item's UUID matches the search UUID, return a pointer the table item's Attribute table */ /* Set all the match flags to false (not matched) before starting the search */
if (!(memcmp_P(UUID, &SDP_Services_Table[CurrTableItem].UUID, UUID_SIZE_BYTES))) memset(UUIDMatch, false, sizeof(UUIDMatch));
return CurrAttributeTable;
/* Retrieve the list of the service's Class UUIDs from its Attribute table */ const void* CurrAttribute;
void* ClassUUIDs = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICECLASSIDS);
/* Go to the next UUID in the table if the current item does not have a list of Class UUIDs */ /* Search through the current attribute table, checking each attribute value for UUID matches */
if (ClassUUIDs == NULL) while ((CurrAttribute = pgm_read_ptr(&CurrAttributeTable->Data)) != NULL)
continue; {
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++;
}
/* Retrieve the size of the Class UUID list and skip past the header to the first Class UUID in the list */ /* If all UUIDs have been matched to the current service, return true */
uint8_t ClassUUIDListHeaderSize; return (UUIDMatches == TotalUUIDs);
uint16_t ClassUUIDListSize = SDP_GetLocalAttributeContainerSize(ClassUUIDs, &ClassUUIDListHeaderSize); }
ClassUUIDs += ClassUUIDListHeaderSize;
/* Check each class UUID in turn for a match */ /** Recursively upwraps the given locally stored attribute (in PROGMEM space), searching for UUIDs to match against
while (ClassUUIDListSize) * 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)
{ {
/* Current Service UUID's Class UUID list has a matching entry, return the Attribute table */ uint8_t CurrAttributeType = (pgm_read_byte(CurrAttribute) & ~0x07);
if (!(memcmp_P(UUID, &((ItemUUID_t*)ClassUUIDs)->UUID, UUID_SIZE_BYTES)))
return CurrAttributeTable;
ClassUUIDListSize -= sizeof(ItemUUID_t); /* Check the data type of the current attribute value - if UUID, compare, if Sequence, unwrap and recurse */
ClassUUIDs += sizeof(ItemUUID_t); 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);
return NULL; CurrAttribute += SequenceHeaderSize;
/* Recursively unwrap the sequence container, and re-search its contents for UUIDs */
while (SequenceSize)
{
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 /** 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) switch (SizeIndex)
{ {
case SDP_DATASIZE_Variable8Bit: case SDP_DATASIZE_Variable8Bit:
ElementValueSize = SDP_ReadData8(DataElementHeader);
*ElementHeaderSize = (1 + sizeof(uint8_t)); *ElementHeaderSize = (1 + sizeof(uint8_t));
ElementValueSize = SDP_ReadData8(DataElementHeader);
break; break;
case SDP_DATASIZE_Variable16Bit: case SDP_DATASIZE_Variable16Bit:
ElementValueSize = SDP_ReadData16(DataElementHeader);
*ElementHeaderSize = (1 + sizeof(uint16_t)); *ElementHeaderSize = (1 + sizeof(uint16_t));
ElementValueSize = SDP_ReadData16(DataElementHeader);
break; break;
case SDP_DATASIZE_Variable32Bit: case SDP_DATASIZE_Variable32Bit:
ElementValueSize = SDP_ReadData32(DataElementHeader);
*ElementHeaderSize = (1 + sizeof(uint32_t)); *ElementHeaderSize = (1 + sizeof(uint32_t));
ElementValueSize = SDP_ReadData32(DataElementHeader);
break; break;
default: default:
ElementValueSize = (1 << SizeIndex);
*ElementHeaderSize = 1; *ElementHeaderSize = 1;
ElementValueSize = (1 << SizeIndex);
break; break;
} }

@ -50,7 +50,7 @@
/* Macros: */ /* 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 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_ERRORRESPONSE 0x01
#define SDP_PDU_SERVICESEARCHREQUEST 0x02 #define SDP_PDU_SERVICESEARCHREQUEST 0x02
@ -60,6 +60,8 @@
#define SDP_PDU_SERVICESEARCHATTRIBUTEREQUEST 0x06 #define SDP_PDU_SERVICESEARCHATTRIBUTEREQUEST 0x06
#define SDP_PDU_SERVICESEARCHATTRIBUTERESPONSE 0x07 #define SDP_PDU_SERVICESEARCHATTRIBUTERESPONSE 0x07
#define pgm_read_ptr(x) (void*)pgm_read_word(x)
/* Enums: */ /* Enums: */
/** Data sizes for SDP Data Element headers, to indicate the size of the data contained in the element. When creating /** Data sizes for SDP Data Element headers, to indicate the size of the data contained in the element. When creating
* a Data Element, a value from this enum should be ORed with a value from the \ref ServiceDiscovery_DataTypes_t enum. * a Data Element, a value from this enum should be ORed with a value from the \ref ServiceDiscovery_DataTypes_t enum.
@ -213,9 +215,15 @@
const uint8_t TotalAttributes, void** const BufferPos); const uint8_t TotalAttributes, void** const BufferPos);
static uint16_t SDP_AddAttributeToResponse(const uint16_t AttributeID, const void* AttributeValue, void** ResponseBuffer); 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 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_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 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_GetLocalAttributeContainerSize(const void* const AttributeData, uint8_t* const HeaderSize);
static uint32_t SDP_GetDataElementSize(const void** const AttributeHeader, uint8_t* const ElementHeaderSize); static uint32_t SDP_GetDataElementSize(const void** const AttributeHeader, uint8_t* const ElementHeaderSize);
#endif #endif

Loading…
Cancel
Save