⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 listattr.c

📁 蓝牙的各种编程接口和各种按理介绍,还有一些例子和说明
💻 C
字号:
/* * Here should go the usual boiler plate. * The stuff I've added if Copyright Jean Tourrilhes 2002. * As most of it is cut'n'paste from part of the SDP library, this code * is of course GPL... * Jean II *//************************** DOCUMENTATION **************************//* * This code use a "brute force" approach to parsing SDP records. * Instead of a top down approach in sdptool, which pick only known * attributes/members, we use a bottom up approach, printing every * single bit of the record and trying to associate its defintion * to it. * The advantage is that, of course, every attribute is displayed, * even unknow one. Also, the display is lower level, so much closer * to the raw data, so more useful for SDP debugging. * On the other hand, the display is much less user friendly... * * Why is this code here, and not in the libs, especially that we include * sdp_internal.h ? Well, I don't want to bother every single sdp app * (including sdpd) with lists of attribute. That seems unnecessary * overhead for a feature that is used only for debugging. * * Jean II *//***************************** INCLUDES *****************************/#include <stdio.h>#include "sdp.h"#include "sdp_lib.h"/* We need to access the low level structure of the attributes */#include "sdp_internal.h"/****************************** TYPES ******************************//* Definition of attribute members */struct member_def {  char *name;};/* Definition of an attribute */struct attrib_def {  int			num;		/* Numeric ID - 16 bits */  char *		name;		/* User readable name */  struct member_def *	members;	/* Definition of attribute args */  int			member_max;	/* Max of attribute arg definitions */};/* Definition of a service or protocol */struct uuid_def {  int			num;		/* Numeric ID - 16 bits */  char *		name;		/* User readable name */  struct attrib_def *	attribs;	/* Specific attribute definitions */  int			attrib_max;	/* Max of attribute definitions */};/* Context information about current attribute */struct attrib_context {  struct uuid_def *	service;	/* Service UUID, if known */  struct attrib_def *	attrib;		/* Description of the attribute */  int			member_index;	/* Index of current attribute member */};/* Context information about the whole service */struct service_context {  struct uuid_def *	service;	/* Service UUID, if known */};/**************************** CONSTANTS ****************************//* Allow us to do nice formatting of the lists */static char *indent_spaces = "                                         ";/* ID of the service attribute. * Most attributes after 0x200 are defined based on the service, so * we need to find what is the service (which is messy) - Jean II */#define SERVICE_ATTR	0x1/* Definition of the optional arguments in protocol list */static struct member_def protocol_members[] = {  { "Protocol" },  { "Channel/Port" },  { "Version" },};/* Definition of the optional arguments in profile list */static struct member_def profile_members[] = {  { "Profile" },  { "Version" },};/* Definition of the optional arguments in Language list */static struct member_def language_members[] = {  { "Code ISO639" },  { "Encoding" },  { "Base Offset" },};/* Name of the various common attributes. See BT assigned numbers */static struct attrib_def attrib_names[] = {  { 0x0, "ServiceRecordHandle", NULL, 0 },  { 0x1, "ServiceClassIDList", NULL, 0 },  { 0x2, "ServiceRecordState", NULL, 0 },  { 0x3, "ServiceID", NULL, 0 },  { 0x4, "ProtocolDescriptorList",    protocol_members, sizeof(protocol_members)/sizeof(struct member_def) },  { 0x5, "BrowseGroupList", NULL, 0 },  { 0x6, "LanguageBaseAttributeIDList",    language_members, sizeof(language_members)/sizeof(struct member_def) },  { 0x7, "ServiceInfoTimeToLive", NULL, 0 },  { 0x8, "ServiceAvailability", NULL, 0 },  { 0x9, "BluetoothProfileDescriptorList",    profile_members, sizeof(profile_members)/sizeof(struct member_def) },  { 0xA, "DocumentationURL", NULL, 0 },  { 0xB, "ClientExecutableURL", NULL, 0 },  { 0xC, "IconURL", NULL, 0 },  { 0xD, "AdditionalProtocolDescriptorLists", NULL, 0 },  /* Definitions after that are tricky (per profile or offset) */};const int attrib_max = sizeof(attrib_names)/sizeof(struct attrib_def);/* Name of the various SPD attributes. See BT assigned numbers */static struct attrib_def sdp_attrib_names[] = {  { 0x200, "VersionNumberList", NULL, 0 },  { 0x201, "ServiceDatabaseState", NULL, 0 },};/* Name of the various SPD attributes. See BT assigned numbers */static struct attrib_def browse_attrib_names[] = {  { 0x200, "GroupID", NULL, 0 },};/* Name of the various PAN attributes. See BT assigned numbers *//* Note : those need to be double checked - Jean II */static struct attrib_def pan_attrib_names[] = {  { 0x200, "IpSubnet", NULL, 0 },		/* Obsolete ??? */  { 0x30A, "SecurityDescription", NULL, 0 },  { 0x30B, "NetAccessType", NULL, 0 },  { 0x30C, "MaxNetAccessrate", NULL, 0 },  { 0x30D, "IPv4Subnet", NULL, 0 },  { 0x30E, "IPv6Subnet", NULL, 0 },};/* Name of the various Generic-Audio attributes. See BT assigned numbers *//* Note : totally untested - Jean II */static struct attrib_def audio_attrib_names[] = {  { 0x302, "Remote audio volume control", NULL, 0 },};/* Same for the UUIDs. See BT assigned numbers */static struct uuid_def uuid16_names[] = {  /* -- Protocols -- */  { 0x1, "SDP (Service Discovery Protocol)", NULL, 0 },  { 0x2, "UDP", NULL, 0 },  { 0x3, "RFCOMM", NULL, 0 },  { 0x4, "TCP", NULL, 0 },  { 0x5, "TCS-BIN", NULL, 0 },  { 0x6, "TCS-AT", NULL, 0 },  { 0x8, "OBEX", NULL, 0 },  { 0x9, "IP", NULL, 0 },  { 0xA, "FTP", NULL, 0 },  { 0xC, "HTTP", NULL, 0 },  { 0xE, "WSP", NULL, 0 },  { 0xF, "BNEP (PAN/BNEP)", NULL, 0 },  { 0x10, "UPnP/ESDP", NULL, 0 },  { 0x11, "HIDP", NULL, 0 },  { 0x12, "HardcopyControlChannel", NULL, 0 },  { 0x14, "HardcopyDataChannel", NULL, 0 },  { 0x16, "HardcopyNotification", NULL, 0 },  { 0x17, "AVCTP", NULL, 0 },  { 0x19, "AVDTP", NULL, 0 },  { 0x1B, "CMTP", NULL, 0 },  { 0x1D, "UDI_C-Plane", NULL, 0 },  { 0x100, "L2CAP", NULL, 0 },  /* -- Services -- */  { 0x1000, "ServiceDiscoveryServerServiceClassID (SDP)",    sdp_attrib_names, sizeof(sdp_attrib_names)/sizeof(struct attrib_def) },  { 0x1001, "BrowseGroupDescriptorServiceClassID (SDP)",    browse_attrib_names,    sizeof(browse_attrib_names)/sizeof(struct attrib_def) },  { 0x1002, "PublicBrowseGroup (SDP)", NULL, 0 },  { 0x1101, "SerialPort", NULL, 0 },  { 0x1102, "LANAccessUsingPPP", NULL, 0 },  { 0x1103, "DialupNetworking (DUN)", NULL, 0 },  { 0x1104, "IrMCSync", NULL, 0 },  { 0x1105, "OBEXObjectPush", NULL, 0 },  { 0x1106, "OBEXFileTransfer", NULL, 0 },  { 0x1107, "IrMCSyncCommand", NULL, 0 },  { 0x1108, "Headset",    audio_attrib_names, sizeof(audio_attrib_names)/sizeof(struct attrib_def) },  { 0x1109, "CordlessTelephony", NULL, 0 },  /* ... */  { 0x110F, "VideoConferencing", NULL, 0 },  { 0x1110, "Intercom", NULL, 0 },  { 0x1111, "Fax", NULL, 0 },  { 0x1112, "HeadsetAudioGateway", NULL, 0 },  { 0x1113, "WAP", NULL, 0 },  { 0x1114, "WAP_CLIENT", NULL, 0 },  { 0x1115, "PANU (PAN/BNEP)",    pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },  { 0x1116, "NAP (PAN/BNEP)",    pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },  { 0x1117, "GN (PAN/BNEP)",    pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },  { 0x1118, "DirectPrinting (BPP)", NULL, 0 },  { 0x1119, "ReferencePrinting (BPP)", NULL, 0 },  /* ... */  { 0x1120, "DirectPrintingReferenceObjectsService (BPP)", NULL, 0 },  { 0x1121, "ReflectedUI (BPP)", NULL, 0 },  { 0x1122, "BasicPrinting (BPP)", NULL, 0 },  { 0x1123, "PrintingStatus (BPP)", NULL, 0 },  { 0x1124, "HumanInterfaceDeviceService (HID)", NULL, 0 },  { 0x1125, "HardcopyCableReplacement (HCR)", NULL, 0 },  { 0x1126, "HCR_Print (HCR)", NULL, 0 },  { 0x1127, "HCR_Scan (HCR)", NULL, 0 },  { 0x1128, "Common ISDN Access (CIP)", NULL, 0 },  { 0x1129, "VideoConferencingGW (VCP)", NULL, 0 },  /* ... */  { 0x1200, "PnPInformation", NULL, 0 },  { 0x1201, "GenericNetworking", NULL, 0 },  { 0x1202, "GenericFileTransfer", NULL, 0 },  { 0x1203, "GenericAudio",    audio_attrib_names, sizeof(audio_attrib_names)/sizeof(struct attrib_def) },  { 0x1204, "GenericTelephony", NULL, 0 },};const int uuid16_max = sizeof(uuid16_names)/sizeof(struct uuid_def);/**************************** PROTOTYPES ****************************/void sdp_data_printf(sdp_data_t *, struct attrib_context *, int);/******************************* CODE *******************************//* ------------------------------------------------------------------- *//* * Parse a UUID. * The BT assigned numbers only list UUID16, so I'm not sure the * other types will ever get used... */void sdp_uuid_printf(uuid_t *uuid, struct attrib_context *context, int indent){	if (uuid) {		if (uuid->type == SDP_UUID16) {			uint16_t uuidNum = uuid->value.uuid16;			struct uuid_def *uuidDef = NULL;			int i;			for(i = 0; i < uuid16_max; i++)				if(uuid16_names[i].num == uuidNum) {					uuidDef = &uuid16_names[i];					break;				}			/* Check if it's the service attribute */			if (context->attrib && context->attrib->num == SERVICE_ATTR) {				/* We got the service ID !!! */				context->service = uuidDef;			}			if(uuidDef)				printf("%.*sUUID16 : 0x%.4x - %s\n",				       indent, indent_spaces,				       uuidNum, uuidDef->name);			else				printf("%.*sUUID16 : 0x%.4x\n",				       indent, indent_spaces, uuidNum);		} else if (uuid->type == SDP_UUID32) {			printf("%.*sUUID32 : 0x%.8x\n",			       indent, indent_spaces, uuid->value.uuid32);		} else if (uuid->type == SDP_UUID128) {			unsigned int data0;			unsigned short data1;			unsigned short data2;			unsigned short data3;			unsigned int data4;			unsigned short data5;			memcpy(&data0, &uuid->value.uuid128.data[0], 4);			memcpy(&data1, &uuid->value.uuid128.data[4], 2);			memcpy(&data2, &uuid->value.uuid128.data[6], 2);			memcpy(&data3, &uuid->value.uuid128.data[8], 2);			memcpy(&data4, &uuid->value.uuid128.data[10], 4);			memcpy(&data5, &uuid->value.uuid128.data[14], 2);			printf("%.*sUUID128 : 0x%.8x-%.4x-%.4x-%.4x-%.8x-%.4x\n",			       indent, indent_spaces,			       ntohl(data0), ntohs(data1), ntohs(data2),			       ntohs(data3), ntohl(data4), ntohs(data5));		} else			printf("%.*sEnum type of UUID not set\n",			       indent, indent_spaces);	} else		printf("%.*sNull passed to print UUID\n",		       indent, indent_spaces);}/* ------------------------------------------------------------------- *//* * Parse a sequence of data elements (i.e. a list) */static void printf_dataseq(sdp_data_t * pData,			       struct attrib_context *context,			       int indent){	sdp_data_t *sdpdata = NULL;	sdpdata = pData;	if (sdpdata) {		context->member_index = 0;		do {			sdp_data_printf(sdpdata, context, indent + 2);			sdpdata = sdpdata->next;			context->member_index++;		} while (sdpdata);	} else {		printf("%.*sBroken dataseq link\n", indent, indent_spaces);	}}/* ------------------------------------------------------------------- *//* * Parse a single data element (either in the attribute or in a data * sequence). */void sdp_data_printf(sdp_data_t *sdpdata,		     struct attrib_context *context,		     int indent){	char *member_name = NULL;	/* Find member name. Almost black magic ;-) */	if (context->attrib && context->attrib->members &&	   context->member_index < context->attrib->member_max) {	  member_name = context->attrib->members[context->member_index].name;	}	switch (sdpdata->dtd) {	case SDP_DATA_NIL:		printf("%.*sNil\n", indent, indent_spaces);		break;	case SDP_BOOL:	case SDP_UINT8:	case SDP_UINT16:	case SDP_UINT32:	case SDP_UINT64:	case SDP_UINT128:	case SDP_INT8:	case SDP_INT16:	case SDP_INT32:	case SDP_INT64:	case SDP_INT128:		if (member_name) {			printf("%.*s%s (Integer) : 0x%x\n",			       indent, indent_spaces,			       member_name, sdpdata->val.uint32);		} else {			printf("%.*sInteger : 0x%x\n", indent, indent_spaces,			       sdpdata->val.uint32);		}		break;	case SDP_UUID16:	case SDP_UUID32:	case SDP_UUID128:		//printf("%.*sUUID\n", indent, indent_spaces);		sdp_uuid_printf(&sdpdata->val.uuid, context, indent);		break;	case SDP_TEXT_STR8:	case SDP_TEXT_STR16:	case SDP_TEXT_STR32:		printf("%.*sText : \"%s\"\n", indent, indent_spaces,		       sdpdata->val.str);		break;	case SDP_URL_STR8:	case SDP_URL_STR16:	case SDP_URL_STR32:		printf("%.*sURL : %s\n", indent, indent_spaces,		       sdpdata->val.str);		break;	case SDP_SEQ8:	case SDP_SEQ16:	case SDP_SEQ32:		printf("%.*sData Sequence\n", indent, indent_spaces);		printf_dataseq(sdpdata->val.dataseq, context, indent);		break;	case SDP_ALT8:	case SDP_ALT16:	case SDP_ALT32:		printf("%.*sData Sequence Alternates\n", indent, indent_spaces);		printf_dataseq(sdpdata->val.dataseq, context, indent);		break;	}}/* ------------------------------------------------------------------- *//* * Parse a single attribute. */void sdp_attr_printf_func(void *value, void *userData){	sdp_data_t *sdpdata = NULL;	uint16_t attrId;	struct service_context *service = (struct service_context *) userData;	struct attrib_context context;	struct attrib_def *attrDef = NULL;	int i;	sdpdata = (sdp_data_t *)value;	attrId = sdpdata->attrId;	/* Search amongst the generic attributes */	for (i = 0; i < attrib_max; i++)		if (attrib_names[i].num == attrId) {			attrDef = &attrib_names[i];			break;		}	/* Search amongst the specific attributes of this service */	if ((attrDef == NULL) &&	   (service->service != NULL) &&	   (service->service->attribs != NULL)) {		struct attrib_def *svc_attribs = service->service->attribs;		int		svc_attrib_max = service->service->attrib_max;		for (i = 0; i < svc_attrib_max; i++)			if (svc_attribs[i].num == attrId) {				attrDef = &svc_attribs[i];				break;			}	}	if (attrDef)		printf("Attribute Identifier : 0x%x - %s\n",		       attrId, attrDef->name);	else		printf("Attribute Identifier : 0x%x\n", attrId);	/* Build context */	context.service = service->service;	context.attrib = attrDef;	context.member_index = 0;	/* Parse attribute members */	if (sdpdata)		sdp_data_printf(sdpdata, &context, 2);	else		printf("  NULL value\n");	/* Update service */	service->service = context.service;}/* ------------------------------------------------------------------- *//* * Main entry point of this library. Parse a SDP record. * We assume the record has already been read, parsed and cached * locally. Jean II */void sdp_printf_service_attr(sdp_record_t *rec){	if (rec && rec->attrlist) {		struct service_context service = { NULL };		sdp_list_foreach(rec->attrlist, sdp_attr_printf_func, &service);	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -