📄 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-2004 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.7 2004/07/22 18:08:49 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 <sys/un.h>#include <sys/socket.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 <bluetooth/sdp_internal.h>#define BASE_UUID "00000000-0000-1000-8000-00805F9B34FB"static uint128_t *bluetooth_base_uuid = NULL;/* Message structure. */struct tupla { int index; char *str;};static struct tupla Protocol[] = { { SDP_UUID, "SDP" }, { RFCOMM_UUID, "RFCOMM" }, { TCS_BIN_UUID, "TCS-BIN" }, { L2CAP_UUID, "L2CAP" }, { IP_UUID, "IP" }, { UDP_UUID, "UDP" }, { TCP_UUID, "TCP" }, { TCS_AT_UUID, "TCS-AT" }, { OBEX_UUID, "OBEX" }, { FTP_UUID, "FTP" }, { HTTP_UUID, "HTTP" }, { WSP_UUID, "WSP" }, { BNEP_UUID, "BNEP" }, { HIDP_UUID, "HIDP" }, { CMTP_UUID, "CMTP" }, { 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, "IrMCSync" }, { OBEX_OBJPUSH_SVCLASS_ID, "OBEX Object Push" }, { OBEX_FILETRANS_SVCLASS_ID, "OBEX File Transfer" }, { IRMC_SYNC_CMD_SVCLASS_ID, "IrMCSync Command" }, { HEADSET_SVCLASS_ID, "Headset" }, { CORDLESS_TELEPHONY_SVCLASS_ID,"Cordless Telephony" }, { INTERCOM_SVCLASS_ID, "Intercom" }, { FAX_SVCLASS_ID, "Fax" }, { HEADSET_AGW_SVCLASS_ID, "Headset Audio Gateway" }, { 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" }, { PANU_SVCLASS_ID, "PAN user" }, { NAP_SVCLASS_ID, "Network access point" }, { GN_SVCLASS_ID, "PAN group network" }, { HID_SVCLASS_ID, "Human Interface Device" }, { CIP_SVCLASS_ID, "Common ISDN Access" }, { 0 }};static struct tupla Profile[] = { { SERIAL_PORT_PROFILE_ID, "Serial Port" }, { LAN_ACCESS_PROFILE_ID, "LAN Access Using PPP" }, { DIALUP_NET_PROFILE_ID, "Dialup Networking" }, { IRMC_SYNC_PROFILE_ID, "IrMCSync" }, { OBEX_OBJPUSH_PROFILE_ID, "OBEX Object Push" }, { OBEX_FILETRANS_PROFILE_ID, "OBEX File Transfer" }, { IRMC_SYNC_CMD_PROFILE_ID, "IrMCSync Command" }, { HEADSET_PROFILE_ID, "Headset" }, { CORDLESS_TELEPHONY_PROFILE_ID, "Cordless Telephony" }, { INTERCOM_PROFILE_ID, "Intercom" }, { FAX_PROFILE_ID, "Fax" }, { HEADSET_AGW_PROFILE_ID, "Headset Audio Gateway" }, { PANU_PROFILE_ID, "PAN user" }, { NAP_PROFILE_ID, "PAN access point" }, { GN_PROFILE_ID, "PAN group network" }, { HID_SVCLASS_ID, "Human Interface Device" }, { CIP_SVCLASS_ID, "Common ISDN Access" }, { 0 }};static 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: snprintf(str, n, "Error: This is uuid32"); return -3; case SDP_UUID128: snprintf(str, n, "Error: This is uuid128"); 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 = sdp_get_unaligned((uint16_t *)value); d->unitSize += sizeof(uint16_t); break; case SDP_INT16: d->val.int16 = sdp_get_unaligned((int16_t *)value); d->unitSize += sizeof(int16_t); break; case SDP_UINT32: d->val.uint32 = sdp_get_unaligned((uint32_t *)value); d->unitSize += sizeof(uint32_t); break; case SDP_INT32: d->val.int32 = sdp_get_unaligned((int32_t *)value); d->unitSize += sizeof(int32_t); break; case SDP_INT64: d->val.int64 = sdp_get_unaligned((int64_t *)value); d->unitSize += sizeof(int64_t); break; case SDP_UINT64: d->val.uint64 = sdp_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, sdp_get_unaligned((uint16_t *)value)); d->unitSize += sizeof(uint16_t); break; case SDP_UUID32: sdp_uuid32_create(&d->val.uuid, sdp_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){ sdp_data_t *d = sdp_data_get(rec, attr); if (d) rec->attrlist = sdp_list_remove(rec->attrlist, d);}void sdp_set_seq_len(char *ptr, int length){ uint8_t dtd = *(uint8_t *)ptr++; switch (dtd) { case SDP_SEQ8: case SDP_ALT8: case SDP_TEXT_STR8: case SDP_URL_STR8: *(uint8_t *)ptr = (uint8_t)length; break; case SDP_SEQ16: case SDP_ALT16: case SDP_TEXT_STR16: case SDP_URL_STR16: sdp_put_unaligned(htons(length), (uint16_t *)ptr); break; case SDP_SEQ32: case SDP_ALT32: case SDP_TEXT_STR32: case SDP_URL_STR32: sdp_put_unaligned(htons(length), (uint32_t *)ptr); break; }}int sdp_set_data_type(sdp_buf_t *buf, uint8_t dtd){ int orig = buf->data_size; uint8_t *p = buf->data + buf->data_size; *p++ = dtd; buf->data_size += sizeof(uint8_t); switch (dtd) { case SDP_SEQ8: case SDP_TEXT_STR8: case SDP_URL_STR8: case SDP_ALT8: buf->data_size += sizeof(uint8_t); break; case SDP_SEQ16: case SDP_TEXT_STR16: case SDP_URL_STR16: case SDP_ALT16: buf->data_size += sizeof(uint16_t); break; case SDP_SEQ32: case SDP_TEXT_STR32: case SDP_URL_STR32: case SDP_ALT32: buf->data_size += sizeof(uint32_t); break; } return buf->data_size - orig;}void sdp_set_attrid(sdp_buf_t *buf, uint16_t attr){ uint8_t *p = buf->data; // data type for attr *p++ = SDP_UINT16; buf->data_size = sizeof(uint8_t); sdp_put_unaligned(htons(attr), (uint16_t *)p); p += sizeof(uint16_t); buf->data_size += sizeof(uint16_t);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -