?? sdp.c
字號:
/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2001-2002 Nokia Corporation * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> * Copyright (C) 2002-2005 Marcel Holtmann <marcel@holtmann.org> * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com> * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY * CLAIM, OR 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. * * ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, * COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS * SOFTWARE IS DISCLAIMED. * * * $Id: sdp.c,v 1.21 2005/05/08 17:18:21 holtmann Exp $ */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <malloc.h>#include <syslog.h>#include <sys/un.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/types.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <bluetooth/l2cap.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include <netinet/in.h>#define SDPINF(fmt, arg...) syslog(LOG_INFO, fmt "\n", ## arg)#define SDPERR(fmt, arg...) syslog(LOG_ERR, "%s: " fmt "\n", __func__ , ## arg)#ifdef SDP_DEBUG#define SDPDBG(fmt, arg...) syslog(LOG_DEBUG, "%s: " fmt "\n", __func__ , ## arg)#else#define SDPDBG(fmt...)#endif#if __BYTE_ORDER == __BIG_ENDIAN#define ntoh64(x) (x)static inline void ntoh128(uint128_t *src, uint128_t *dst){ int i; for (i = 0; i < 16; i++) dst->data[i] = src->data[i];}#elsestatic inline uint64_t ntoh64(uint64_t n){ uint64_t h; uint64_t tmp = ntohl(n & 0x00000000ffffffff); h = ntohl(n >> 32); h |= tmp << 32; return h;}static inline void ntoh128(uint128_t *src, uint128_t *dst){ int i; for (i = 0; i < 16; i++) dst->data[15 - i] = src->data[i];}#endif#define hton64(x) ntoh64(x)#define hton128(x, y) ntoh128(x, y)#define BASE_UUID "00000000-0000-1000-8000-00805F9B34FB"static uint128_t *bluetooth_base_uuid = NULL;#define SDP_BASIC_ATTR_PDUFORM_SIZE 32#define SDP_SEQ_PDUFORM_SIZE 128#define SDP_UUID_SEQ_SIZE 256#define SDP_MAX_ATTR_LEN 65535/* Message structure. */struct tupla { int index; char *str;};static struct tupla Protocol[] = { { SDP_UUID, "SDP" }, { UDP_UUID, "UDP" }, { RFCOMM_UUID, "RFCOMM" }, { TCP_UUID, "TCP" }, { TCS_BIN_UUID, "TCS-BIN" }, { TCS_AT_UUID, "TCS-AT" }, { OBEX_UUID, "OBEX" }, { IP_UUID, "IP" }, { FTP_UUID, "FTP" }, { HTTP_UUID, "HTTP" }, { WSP_UUID, "WSP" }, { BNEP_UUID, "BNEP" }, { UPNP_UUID, "UPNP" }, { HIDP_UUID, "HIDP" }, { HCRP_CTRL_UUID, "HCRP-Ctrl" }, { HCRP_DATA_UUID, "HCRP-Data" }, { HCRP_NOTE_UUID, "HCRP-Notify" }, { AVCTP_UUID, "AVCTP" }, { AVDTP_UUID, "AVDTP" }, { CMTP_UUID, "CMTP" }, { UDI_UUID, "UDI" }, { L2CAP_UUID, "L2CAP" }, { 0 }};static struct tupla ServiceClass[] = { { SDP_SERVER_SVCLASS_ID, "SDP Server" }, { BROWSE_GRP_DESC_SVCLASS_ID, "Browse Group Descriptor" }, { PUBLIC_BROWSE_GROUP, "Public Browse Group" }, { SERIAL_PORT_SVCLASS_ID, "Serial Port" }, { LAN_ACCESS_SVCLASS_ID, "LAN Access Using PPP" }, { DIALUP_NET_SVCLASS_ID, "Dialup Networking" }, { IRMC_SYNC_SVCLASS_ID, "IrMC Sync" }, { OBEX_OBJPUSH_SVCLASS_ID, "OBEX Object Push" }, { OBEX_FILETRANS_SVCLASS_ID, "OBEX File Transfer" }, { IRMC_SYNC_CMD_SVCLASS_ID, "IrMC Sync Command" }, { HEADSET_SVCLASS_ID, "Headset" }, { CORDLESS_TELEPHONY_SVCLASS_ID, "Cordless Telephony" }, { AUDIO_SOURCE_SVCLASS_ID, "Audio Source" }, { AUDIO_SINK_SVCLASS_ID, "Audio Sink" }, { AV_REMOTE_TARGET_SVCLASS_ID, "AV Remote Target" }, { ADVANCED_AUDIO_SVCLASS_ID, "Advanced Audio" }, { AV_REMOTE_SVCLASS_ID, "AV Remote" }, { VIDEO_CONF_SVCLASS_ID, "Video Conferencing" }, { INTERCOM_SVCLASS_ID, "Intercom" }, { FAX_SVCLASS_ID, "Fax" }, { HEADSET_AGW_SVCLASS_ID, "Headset Audio Gateway" }, { WAP_SVCLASS_ID, "WAP" }, { WAP_CLIENT_SVCLASS_ID, "WAP Client" }, { PANU_SVCLASS_ID, "PAN User" }, { NAP_SVCLASS_ID, "Network Access Point" }, { GN_SVCLASS_ID, "PAN Group Network" }, { DIRECT_PRINTING_SVCLASS_ID, "Direct Printing" }, { REFERENCE_PRINTING_SVCLASS_ID, "Reference Printing" }, { IMAGING_SVCLASS_ID, "Imaging" }, { IMAGING_RESPONDER_SVCLASS_ID, "Imaging Responder" }, { IMAGING_ARCHIVE_SVCLASS_ID, "Imaging Automatic Archive" }, { IMAGING_REFOBJS_SVCLASS_ID, "Imaging Referenced Objects" }, { HANDSFREE_SVCLASS_ID, "Handsfree" }, { HANDSFREE_AGW_SVCLASS_ID, "Handfree Audio Gateway" }, { DIRECT_PRT_REFOBJS_SVCLASS_ID, "Direct Printing Ref. Objects" }, { REFLECTED_UI_SVCLASS_ID, "Reflected UI" }, { BASIC_PRINTING_SVCLASS_ID, "Basic Printing" }, { PRINTING_STATUS_SVCLASS_ID, "Printing Status" }, { HID_SVCLASS_ID, "Human Interface Device" }, { HCR_SVCLASS_ID, "Hardcopy Cable Replacement" }, { HCR_PRINT_SVCLASS_ID, "HCR Print" }, { HCR_SCAN_SVCLASS_ID, "HCR Scan" }, { CIP_SVCLASS_ID, "Common ISDN Access" }, { VIDEO_CONF_GW_SVCLASS_ID, "Video Conferencing Gateway" }, { UDI_MT_SVCLASS_ID, "UDI MT" }, { UDI_TA_SVCLASS_ID, "UDI TA" }, { AV_SVCLASS_ID, "Audio/Video" }, { SAP_SVCLASS_ID, "SIM Access" }, { PNP_INFO_SVCLASS_ID, "PnP Information" }, { GENERIC_NETWORKING_SVCLASS_ID, "Generic Networking" }, { GENERIC_FILETRANS_SVCLASS_ID, "Generic File Transfer" }, { GENERIC_AUDIO_SVCLASS_ID, "Generic Audio" }, { GENERIC_TELEPHONY_SVCLASS_ID, "Generic Telephony" }, { UPNP_SVCLASS_ID, "UPnP" }, { UPNP_IP_SVCLASS_ID, "UPnP IP" }, { UPNP_PAN_SVCLASS_ID, "UPnP PAN" }, { UPNP_LAP_SVCLASS_ID, "UPnP LAP" }, { UPNP_L2CAP_SVCLASS_ID, "UPnP L2CAP" }, { VIDEO_SOURCE_SVCLASS_ID, "Video Source" }, { VIDEO_SINK_SVCLASS_ID, "Video Sink" }, { 0 }};#define Profile ServiceClassstatic char *string_lookup(struct tupla *pt0, int index){ struct tupla *pt; for (pt = pt0; pt->index; pt++) if (pt->index == index) return pt->str; return "";}/* * Prints into a string the Protocol UUID * coping a maximum of n characters. */static int uuid2str(struct tupla *message, const uuid_t *uuid, char *str, size_t n) { char *str2; if (!uuid) { snprintf(str, n, "NULL"); return -2; } switch (uuid->type) { case SDP_UUID16: str2 = string_lookup(message, uuid->value.uuid16); snprintf(str, n, str2); break; case SDP_UUID32: str2 = string_lookup(message, uuid->value.uuid32); snprintf(str, n, str2); break; case SDP_UUID128: snprintf(str, n, "Error: This is UUID-128"); return -4; default: snprintf(str, n, "Type of UUID (%x) unknown.", uuid->type); return -1; } return 0;}int sdp_proto_uuid2strn(const uuid_t *uuid, char *str, size_t n){ return uuid2str(Protocol, uuid, str, n);}int sdp_svclass_uuid2strn(const uuid_t *uuid, char *str, size_t n){ return uuid2str(ServiceClass, uuid, str, n);}int sdp_profile_uuid2strn(const uuid_t *uuid, char *str, size_t n){ return uuid2str(Profile, uuid, str, n);}/* * convert the UUID to string, copying a maximum of n characters. */int sdp_uuid2strn(const uuid_t *uuid, char *str, size_t n){ if (!uuid) { snprintf(str, n, "NULL"); return -2; } switch (uuid->type) { case SDP_UUID16: snprintf(str, n, "%.4x", uuid->value.uuid16); break; case SDP_UUID32: snprintf(str, n, "%.8x", uuid->value.uuid32); break; case 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); snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x", ntohl(data0), ntohs(data1), ntohs(data2), ntohs(data3), ntohl(data4), ntohs(data5)); } break; default: snprintf(str, n, "Type of UUID (%x) unknown.", uuid->type); return -1; // Enum type of UUID not set } return 0;}#ifdef SDP_DEBUG/* * Function prints the UUID in hex as per defined syntax - * * 4bytes-2bytes-2bytes-2bytes-6bytes * * There is some ugly code, including hardcoding, but * that is just the way it is converting 16 and 32 bit * UUIDs to 128 bit as defined in the SDP doc */void sdp_uuid_print(const uuid_t *uuid){ if (uuid == NULL) { SDPERR("Null passed to print UUID\n"); return; } if (uuid->type == SDP_UUID16) { SDPDBG(" uint16_t : 0x%.4x\n", uuid->value.uuid16); } else if (uuid->type == SDP_UUID32) { SDPDBG(" uint32_t : 0x%.8x\n", 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); SDPDBG(" uint128_t : 0x%.8x-", ntohl(data0)); SDPDBG("%.4x-", ntohs(data1)); SDPDBG("%.4x-", ntohs(data2)); SDPDBG("%.4x-", ntohs(data3)); SDPDBG("%.8x", ntohl(data4)); SDPDBG("%.4x\n", ntohs(data5)); } else SDPERR("Enum type of UUID not set\n");}#endifsdp_data_t *sdp_data_alloc(uint8_t dtd, const void *value){ sdp_data_t *seq; int len = 0; sdp_data_t *d = (sdp_data_t *) malloc(sizeof(sdp_data_t)); if (!d) return NULL; memset(d, 0, sizeof(sdp_data_t)); d->dtd = dtd; d->unitSize = sizeof(uint8_t); switch (dtd) { case SDP_DATA_NIL: break; case SDP_UINT8: d->val.uint8 = *(uint8_t *) value; d->unitSize += sizeof(uint8_t); break; case SDP_INT8: case SDP_BOOL: d->val.int8 = *(int8_t *) value; d->unitSize += sizeof(int8_t); break; case SDP_UINT16: d->val.uint16 = bt_get_unaligned((uint16_t *) value); d->unitSize += sizeof(uint16_t); break; case SDP_INT16: d->val.int16 = bt_get_unaligned((int16_t *) value); d->unitSize += sizeof(int16_t); break; case SDP_UINT32: d->val.uint32 = bt_get_unaligned((uint32_t *) value); d->unitSize += sizeof(uint32_t); break; case SDP_INT32: d->val.int32 = bt_get_unaligned((int32_t *) value); d->unitSize += sizeof(int32_t); break; case SDP_INT64: d->val.int64 = bt_get_unaligned((int64_t *) value); d->unitSize += sizeof(int64_t); break; case SDP_UINT64: d->val.uint64 = bt_get_unaligned((uint64_t *) value); d->unitSize += sizeof(uint64_t); break; case SDP_UINT128: memcpy(&d->val.uint128.data, value, sizeof(uint128_t)); d->unitSize += sizeof(uint128_t); break; case SDP_INT128: memcpy(&d->val.int128.data, value, sizeof(uint128_t)); d->unitSize += sizeof(uint128_t); break; case SDP_UUID16: sdp_uuid16_create(&d->val.uuid, bt_get_unaligned((uint16_t *) value)); d->unitSize += sizeof(uint16_t); break; case SDP_UUID32: sdp_uuid32_create(&d->val.uuid, bt_get_unaligned((uint32_t *) value)); d->unitSize += sizeof(uint32_t); break; case SDP_UUID128: sdp_uuid128_create(&d->val.uuid, value); d->unitSize += sizeof(uint128_t); break; case SDP_URL_STR8: case SDP_TEXT_STR8: case SDP_URL_STR16: case SDP_TEXT_STR16: if (!value) goto out_error; len = strlen(value); d->unitSize += len; if (len <= USHRT_MAX) { d->val.str = (char *) malloc(len + 1); if (!d->val.str) goto out_error; strcpy(d->val.str, value); if (len <= UCHAR_MAX) { d->unitSize += sizeof(uint8_t); if (dtd != SDP_URL_STR8 && dtd != SDP_TEXT_STR8) { if (dtd == SDP_URL_STR16) dtd = SDP_URL_STR8; else dtd = SDP_TEXT_STR8; } } else { d->unitSize += sizeof(uint16_t); if (dtd == SDP_TEXT_STR8) dtd = SDP_TEXT_STR16; else dtd = SDP_URL_STR16; } } else { SDPERR("Strings of size > USHRT_MAX not supported\n"); goto out_error; } break; case SDP_URL_STR32: case SDP_TEXT_STR32: SDPERR("Strings of size > USHRT_MAX not supported\n"); break; case SDP_ALT8: case SDP_ALT16: case SDP_ALT32: case SDP_SEQ8: case SDP_SEQ16: case SDP_SEQ32: if (dtd == SDP_ALT8 || dtd == SDP_SEQ8) d->unitSize += sizeof(uint8_t); else if (dtd == SDP_ALT16 || dtd == SDP_SEQ16) d->unitSize += sizeof(uint16_t); else if (dtd == SDP_ALT32 || dtd == SDP_SEQ32) d->unitSize += sizeof(uint32_t); seq = (sdp_data_t *)value; d->val.dataseq = seq; for (; seq; seq = seq->next) d->unitSize += seq->unitSize; break; default: goto out_error; } return d;out_error: free(d); return NULL;}sdp_data_t *sdp_seq_append(sdp_data_t *seq, sdp_data_t *d){ if (seq) { sdp_data_t *p; for (p = seq; p->next; p = p->next); p->next = d; } else seq = d; d->next = NULL; return seq;}sdp_data_t *sdp_seq_alloc(void **dtds, void **values, int len){ sdp_data_t *curr = NULL, *seq = NULL; int i; for (i = 0; i < len; i++) { sdp_data_t *data; uint8_t dtd = *(uint8_t *)dtds[i]; if (dtd >= SDP_SEQ8 && dtd <= SDP_ALT32) data = (sdp_data_t *)values[i]; else data = sdp_data_alloc(dtd, values[i]); if (!data) return NULL; if (curr) curr->next = data; else seq = data; curr = data; } return sdp_data_alloc(SDP_SEQ8, seq);}int sdp_attr_add(sdp_record_t *rec, uint16_t attr, sdp_data_t *d){ sdp_data_t *p = sdp_data_get(rec, attr); if (p) return -1; d->attrId = attr; rec->attrlist = sdp_list_insert_sorted(rec->attrlist, d, sdp_attrid_comp_func); return 0;}void sdp_attr_remove(sdp_record_t *rec, uint16_t attr){
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -