Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/next/external/cache/sources/hcitools/lib/sdp.c
Views: 3959
/*1*2* BlueZ - Bluetooth protocol stack for Linux3*4* Copyright (C) 2001-2002 Nokia Corporation5* Copyright (C) 2002-2003 Maxim Krasnyansky <[email protected]>6* Copyright (C) 2002-2010 Marcel Holtmann <[email protected]>7* Copyright (C) 2002-2003 Stephen Crane <[email protected]>8*9*10* This program is free software; you can redistribute it and/or modify11* it under the terms of the GNU General Public License as published by12* the Free Software Foundation; either version 2 of the License, or13* (at your option) any later version.14*15* This program is distributed in the hope that it will be useful,16* but WITHOUT ANY WARRANTY; without even the implied warranty of17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the18* GNU General Public License for more details.19*20* You should have received a copy of the GNU General Public License21* along with this program; if not, write to the Free Software22* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA23*24*/2526#ifdef HAVE_CONFIG_H27#include <config.h>28#endif2930#include <stdio.h>31#include <errno.h>32#include <fcntl.h>33#include <unistd.h>34#include <stdlib.h>35#include <limits.h>36#include <string.h>37#include <syslog.h>38#include <sys/time.h>39#include <sys/types.h>40#include <sys/socket.h>41#include <sys/un.h>42#include <netinet/in.h>4344#include "bluetooth.h"45#include "hci.h"46#include "hci_lib.h"47#include "l2cap.h"48#include "sdp.h"49#include "sdp_lib.h"5051#define SDPINF(fmt, arg...) syslog(LOG_INFO, fmt "\n", ## arg)52#define SDPERR(fmt, arg...) syslog(LOG_ERR, "%s: " fmt "\n", __func__ , ## arg)5354#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))5556#ifdef SDP_DEBUG57#define SDPDBG(fmt, arg...) syslog(LOG_DEBUG, "%s: " fmt "\n", __func__ , ## arg)58#else59#define SDPDBG(fmt...)60#endif6162long int __fdelt_chk (long int __d)63{64return 0;65}6667static uint128_t bluetooth_base_uuid = {68.data = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,690x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }70};7172#define SDP_MAX_ATTR_LEN 655357374static sdp_data_t *sdp_copy_seq(sdp_data_t *data);75static int sdp_attr_add_new_with_length(sdp_record_t *rec,76uint16_t attr, uint8_t dtd, const void *value, uint32_t len);77static int sdp_gen_buffer(sdp_buf_t *buf, sdp_data_t *d);7879/* Message structure. */80struct tupla {81int index;82char *str;83};8485static struct tupla Protocol[] = {86{ SDP_UUID, "SDP" },87{ UDP_UUID, "UDP" },88{ RFCOMM_UUID, "RFCOMM" },89{ TCP_UUID, "TCP" },90{ TCS_BIN_UUID, "TCS-BIN" },91{ TCS_AT_UUID, "TCS-AT" },92{ OBEX_UUID, "OBEX" },93{ IP_UUID, "IP" },94{ FTP_UUID, "FTP" },95{ HTTP_UUID, "HTTP" },96{ WSP_UUID, "WSP" },97{ BNEP_UUID, "BNEP" },98{ UPNP_UUID, "UPNP" },99{ HIDP_UUID, "HIDP" },100{ HCRP_CTRL_UUID, "HCRP-Ctrl" },101{ HCRP_DATA_UUID, "HCRP-Data" },102{ HCRP_NOTE_UUID, "HCRP-Notify" },103{ AVCTP_UUID, "AVCTP" },104{ AVDTP_UUID, "AVDTP" },105{ CMTP_UUID, "CMTP" },106{ UDI_UUID, "UDI" },107{ MCAP_CTRL_UUID, "MCAP-Ctrl" },108{ MCAP_DATA_UUID, "MCAP-Data" },109{ L2CAP_UUID, "L2CAP" },110{ ATT_UUID, "ATT" },111{ 0 }112};113114static struct tupla ServiceClass[] = {115{ SDP_SERVER_SVCLASS_ID, "SDP Server" },116{ BROWSE_GRP_DESC_SVCLASS_ID, "Browse Group Descriptor" },117{ PUBLIC_BROWSE_GROUP, "Public Browse Group" },118{ SERIAL_PORT_SVCLASS_ID, "Serial Port" },119{ LAN_ACCESS_SVCLASS_ID, "LAN Access Using PPP" },120{ DIALUP_NET_SVCLASS_ID, "Dialup Networking" },121{ IRMC_SYNC_SVCLASS_ID, "IrMC Sync" },122{ OBEX_OBJPUSH_SVCLASS_ID, "OBEX Object Push" },123{ OBEX_FILETRANS_SVCLASS_ID, "OBEX File Transfer" },124{ IRMC_SYNC_CMD_SVCLASS_ID, "IrMC Sync Command" },125{ HEADSET_SVCLASS_ID, "Headset" },126{ CORDLESS_TELEPHONY_SVCLASS_ID, "Cordless Telephony" },127{ AUDIO_SOURCE_SVCLASS_ID, "Audio Source" },128{ AUDIO_SINK_SVCLASS_ID, "Audio Sink" },129{ AV_REMOTE_TARGET_SVCLASS_ID, "AV Remote Target" },130{ ADVANCED_AUDIO_SVCLASS_ID, "Advanced Audio" },131{ AV_REMOTE_SVCLASS_ID, "AV Remote" },132{ AV_REMOTE_CONTROLLER_SVCLASS_ID, "AV Remote Controller" },133{ INTERCOM_SVCLASS_ID, "Intercom" },134{ FAX_SVCLASS_ID, "Fax" },135{ HEADSET_AGW_SVCLASS_ID, "Headset Audio Gateway" },136{ WAP_SVCLASS_ID, "WAP" },137{ WAP_CLIENT_SVCLASS_ID, "WAP Client" },138{ PANU_SVCLASS_ID, "PAN User" },139{ NAP_SVCLASS_ID, "Network Access Point" },140{ GN_SVCLASS_ID, "PAN Group Network" },141{ DIRECT_PRINTING_SVCLASS_ID, "Direct Printing" },142{ REFERENCE_PRINTING_SVCLASS_ID, "Reference Printing" },143{ IMAGING_SVCLASS_ID, "Imaging" },144{ IMAGING_RESPONDER_SVCLASS_ID, "Imaging Responder" },145{ IMAGING_ARCHIVE_SVCLASS_ID, "Imaging Automatic Archive" },146{ IMAGING_REFOBJS_SVCLASS_ID, "Imaging Referenced Objects" },147{ HANDSFREE_SVCLASS_ID, "Handsfree" },148{ HANDSFREE_AGW_SVCLASS_ID, "Handsfree Audio Gateway" },149{ DIRECT_PRT_REFOBJS_SVCLASS_ID, "Direct Printing Ref. Objects" },150{ REFLECTED_UI_SVCLASS_ID, "Reflected UI" },151{ BASIC_PRINTING_SVCLASS_ID, "Basic Printing" },152{ PRINTING_STATUS_SVCLASS_ID, "Printing Status" },153{ HID_SVCLASS_ID, "Human Interface Device" },154{ HCR_SVCLASS_ID, "Hardcopy Cable Replacement" },155{ HCR_PRINT_SVCLASS_ID, "HCR Print" },156{ HCR_SCAN_SVCLASS_ID, "HCR Scan" },157{ CIP_SVCLASS_ID, "Common ISDN Access" },158{ VIDEO_CONF_GW_SVCLASS_ID, "Video Conferencing Gateway" },159{ UDI_MT_SVCLASS_ID, "UDI MT" },160{ UDI_TA_SVCLASS_ID, "UDI TA" },161{ AV_SVCLASS_ID, "Audio/Video" },162{ SAP_SVCLASS_ID, "SIM Access" },163{ PBAP_PCE_SVCLASS_ID, "Phonebook Access - PCE" },164{ PBAP_PSE_SVCLASS_ID, "Phonebook Access - PSE" },165{ PBAP_SVCLASS_ID, "Phonebook Access" },166{ MAP_MSE_SVCLASS_ID, "Message Access - MAS" },167{ MAP_MCE_SVCLASS_ID, "Message Access - MNS" },168{ MAP_SVCLASS_ID, "Message Access" },169{ PNP_INFO_SVCLASS_ID, "PnP Information" },170{ GENERIC_NETWORKING_SVCLASS_ID, "Generic Networking" },171{ GENERIC_FILETRANS_SVCLASS_ID, "Generic File Transfer" },172{ GENERIC_AUDIO_SVCLASS_ID, "Generic Audio" },173{ GENERIC_TELEPHONY_SVCLASS_ID, "Generic Telephony" },174{ UPNP_SVCLASS_ID, "UPnP" },175{ UPNP_IP_SVCLASS_ID, "UPnP IP" },176{ UPNP_PAN_SVCLASS_ID, "UPnP PAN" },177{ UPNP_LAP_SVCLASS_ID, "UPnP LAP" },178{ UPNP_L2CAP_SVCLASS_ID, "UPnP L2CAP" },179{ VIDEO_SOURCE_SVCLASS_ID, "Video Source" },180{ VIDEO_SINK_SVCLASS_ID, "Video Sink" },181{ VIDEO_DISTRIBUTION_SVCLASS_ID, "Video Distribution" },182{ HDP_SVCLASS_ID, "HDP" },183{ HDP_SOURCE_SVCLASS_ID, "HDP Source" },184{ HDP_SINK_SVCLASS_ID, "HDP Sink" },185{ APPLE_AGENT_SVCLASS_ID, "Apple Agent" },186{ GENERIC_ATTRIB_SVCLASS_ID, "Generic Attribute" },187{ 0 }188};189190#define Profile ServiceClass191192193194static char *string_lookup(struct tupla *pt0, int index)195{196struct tupla *pt;197198for (pt = pt0; pt->index; pt++)199if (pt->index == index)200return pt->str;201202return "";203}204205static char *string_lookup_uuid(struct tupla *pt0, const uuid_t *uuid)206{207uuid_t tmp_uuid;208209memcpy(&tmp_uuid, uuid, sizeof(tmp_uuid));210211if (sdp_uuid128_to_uuid(&tmp_uuid)) {212switch (tmp_uuid.type) {213case SDP_UUID16:214return string_lookup(pt0, tmp_uuid.value.uuid16);215case SDP_UUID32:216return string_lookup(pt0, tmp_uuid.value.uuid32);217}218}219220return "";221}222223/*224* Prints into a string the Protocol UUID225* coping a maximum of n characters.226*/227static int uuid2str(struct tupla *message, const uuid_t *uuid, char *str, size_t n)228{229char *str2;230231if (!uuid) {232snprintf(str, n, "NULL");233return -2;234}235236switch (uuid->type) {237case SDP_UUID16:238str2 = string_lookup(message, uuid->value.uuid16);239snprintf(str, n, "%s", str2);240break;241case SDP_UUID32:242str2 = string_lookup(message, uuid->value.uuid32);243snprintf(str, n, "%s", str2);244break;245case SDP_UUID128:246str2 = string_lookup_uuid(message, uuid);247snprintf(str, n, "%s", str2);248break;249default:250snprintf(str, n, "Type of UUID (%x) unknown.", uuid->type);251return -1;252}253254return 0;255}256257int sdp_proto_uuid2strn(const uuid_t *uuid, char *str, size_t n)258{259return uuid2str(Protocol, uuid, str, n);260}261262int sdp_svclass_uuid2strn(const uuid_t *uuid, char *str, size_t n)263{264return uuid2str(ServiceClass, uuid, str, n);265}266267int sdp_profile_uuid2strn(const uuid_t *uuid, char *str, size_t n)268{269return uuid2str(Profile, uuid, str, n);270}271272/*273* convert the UUID to string, copying a maximum of n characters.274*/275int sdp_uuid2strn(const uuid_t *uuid, char *str, size_t n)276{277if (!uuid) {278snprintf(str, n, "NULL");279return -2;280}281switch (uuid->type) {282case SDP_UUID16:283snprintf(str, n, "%.4x", uuid->value.uuid16);284break;285case SDP_UUID32:286snprintf(str, n, "%.8x", uuid->value.uuid32);287break;288case SDP_UUID128:{289unsigned int data0;290unsigned short data1;291unsigned short data2;292unsigned short data3;293unsigned int data4;294unsigned short data5;295296memcpy(&data0, &uuid->value.uuid128.data[0], 4);297memcpy(&data1, &uuid->value.uuid128.data[4], 2);298memcpy(&data2, &uuid->value.uuid128.data[6], 2);299memcpy(&data3, &uuid->value.uuid128.data[8], 2);300memcpy(&data4, &uuid->value.uuid128.data[10], 4);301memcpy(&data5, &uuid->value.uuid128.data[14], 2);302303snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",304ntohl(data0), ntohs(data1),305ntohs(data2), ntohs(data3),306ntohl(data4), ntohs(data5));307}308break;309default:310snprintf(str, n, "Type of UUID (%x) unknown.", uuid->type);311return -1; /* Enum type of UUID not set */312}313return 0;314}315316#ifdef SDP_DEBUG317/*318* Function prints the UUID in hex as per defined syntax -319*320* 4bytes-2bytes-2bytes-2bytes-6bytes321*322* There is some ugly code, including hardcoding, but323* that is just the way it is converting 16 and 32 bit324* UUIDs to 128 bit as defined in the SDP doc325*/326void sdp_uuid_print(const uuid_t *uuid)327{328if (uuid == NULL) {329SDPERR("Null passed to print UUID");330return;331}332if (uuid->type == SDP_UUID16) {333SDPDBG(" uint16_t : 0x%.4x", uuid->value.uuid16);334} else if (uuid->type == SDP_UUID32) {335SDPDBG(" uint32_t : 0x%.8x", uuid->value.uuid32);336} else if (uuid->type == SDP_UUID128) {337unsigned int data0;338unsigned short data1;339unsigned short data2;340unsigned short data3;341unsigned int data4;342unsigned short data5;343344memcpy(&data0, &uuid->value.uuid128.data[0], 4);345memcpy(&data1, &uuid->value.uuid128.data[4], 2);346memcpy(&data2, &uuid->value.uuid128.data[6], 2);347memcpy(&data3, &uuid->value.uuid128.data[8], 2);348memcpy(&data4, &uuid->value.uuid128.data[10], 4);349memcpy(&data5, &uuid->value.uuid128.data[14], 2);350351SDPDBG(" uint128_t : 0x%.8x-%.4x-%.4x-%.4x-%.8x%.4x",352ntohl(data0), ntohs(data1), ntohs(data2),353ntohs(data3), ntohl(data4), ntohs(data5));354} else355SDPERR("Enum type of UUID not set");356}357#endif358359sdp_data_t *sdp_data_alloc_with_length(uint8_t dtd, const void *value,360uint32_t length)361{362sdp_data_t *seq;363sdp_data_t *d = malloc(sizeof(sdp_data_t));364365if (!d)366return NULL;367368memset(d, 0, sizeof(sdp_data_t));369d->dtd = dtd;370d->unitSize = sizeof(uint8_t);371372switch (dtd) {373case SDP_DATA_NIL:374break;375case SDP_UINT8:376d->val.uint8 = *(uint8_t *) value;377d->unitSize += sizeof(uint8_t);378break;379case SDP_INT8:380case SDP_BOOL:381d->val.int8 = *(int8_t *) value;382d->unitSize += sizeof(int8_t);383break;384case SDP_UINT16:385d->val.uint16 = bt_get_unaligned((uint16_t *) value);386d->unitSize += sizeof(uint16_t);387break;388case SDP_INT16:389d->val.int16 = bt_get_unaligned((int16_t *) value);390d->unitSize += sizeof(int16_t);391break;392case SDP_UINT32:393d->val.uint32 = bt_get_unaligned((uint32_t *) value);394d->unitSize += sizeof(uint32_t);395break;396case SDP_INT32:397d->val.int32 = bt_get_unaligned((int32_t *) value);398d->unitSize += sizeof(int32_t);399break;400case SDP_INT64:401d->val.int64 = bt_get_unaligned((int64_t *) value);402d->unitSize += sizeof(int64_t);403break;404case SDP_UINT64:405d->val.uint64 = bt_get_unaligned((uint64_t *) value);406d->unitSize += sizeof(uint64_t);407break;408case SDP_UINT128:409memcpy(&d->val.uint128.data, value, sizeof(uint128_t));410d->unitSize += sizeof(uint128_t);411break;412case SDP_INT128:413memcpy(&d->val.int128.data, value, sizeof(uint128_t));414d->unitSize += sizeof(uint128_t);415break;416case SDP_UUID16:417sdp_uuid16_create(&d->val.uuid, bt_get_unaligned((uint16_t *) value));418d->unitSize += sizeof(uint16_t);419break;420case SDP_UUID32:421sdp_uuid32_create(&d->val.uuid, bt_get_unaligned((uint32_t *) value));422d->unitSize += sizeof(uint32_t);423break;424case SDP_UUID128:425sdp_uuid128_create(&d->val.uuid, value);426d->unitSize += sizeof(uint128_t);427break;428case SDP_URL_STR8:429case SDP_URL_STR16:430case SDP_TEXT_STR8:431case SDP_TEXT_STR16:432if (!value) {433free(d);434return NULL;435}436437d->unitSize += length;438if (length <= USHRT_MAX) {439d->val.str = malloc(length);440if (!d->val.str) {441free(d);442return NULL;443}444445memcpy(d->val.str, value, length);446} else {447SDPERR("Strings of size > USHRT_MAX not supported");448free(d);449d = NULL;450}451break;452case SDP_URL_STR32:453case SDP_TEXT_STR32:454SDPERR("Strings of size > USHRT_MAX not supported");455break;456case SDP_ALT8:457case SDP_ALT16:458case SDP_ALT32:459case SDP_SEQ8:460case SDP_SEQ16:461case SDP_SEQ32:462if (dtd == SDP_ALT8 || dtd == SDP_SEQ8)463d->unitSize += sizeof(uint8_t);464else if (dtd == SDP_ALT16 || dtd == SDP_SEQ16)465d->unitSize += sizeof(uint16_t);466else if (dtd == SDP_ALT32 || dtd == SDP_SEQ32)467d->unitSize += sizeof(uint32_t);468seq = (sdp_data_t *)value;469d->val.dataseq = seq;470for (; seq; seq = seq->next)471d->unitSize += seq->unitSize;472break;473default:474free(d);475d = NULL;476}477478return d;479}480481sdp_data_t *sdp_data_alloc(uint8_t dtd, const void *value)482{483uint32_t length;484485switch (dtd) {486case SDP_URL_STR8:487case SDP_URL_STR16:488case SDP_TEXT_STR8:489case SDP_TEXT_STR16:490if (!value)491return NULL;492493length = strlen((char *) value);494break;495default:496length = 0;497break;498}499500return sdp_data_alloc_with_length(dtd, value, length);501}502503sdp_data_t *sdp_seq_append(sdp_data_t *seq, sdp_data_t *d)504{505if (seq) {506sdp_data_t *p;507for (p = seq; p->next; p = p->next);508p->next = d;509} else510seq = d;511d->next = NULL;512return seq;513}514515sdp_data_t *sdp_seq_alloc_with_length(void **dtds, void **values, int *length,516int len)517{518sdp_data_t *curr = NULL, *seq = NULL;519int i;520521for (i = 0; i < len; i++) {522sdp_data_t *data;523int8_t dtd = *(uint8_t *) dtds[i];524525if (dtd >= SDP_SEQ8 && dtd <= SDP_ALT32)526data = (sdp_data_t *) values[i];527else528data = sdp_data_alloc_with_length(dtd, values[i], length[i]);529530if (!data)531return NULL;532533if (curr)534curr->next = data;535else536seq = data;537538curr = data;539}540541return sdp_data_alloc(SDP_SEQ8, seq);542}543544sdp_data_t *sdp_seq_alloc(void **dtds, void **values, int len)545{546sdp_data_t *curr = NULL, *seq = NULL;547int i;548549for (i = 0; i < len; i++) {550sdp_data_t *data;551uint8_t dtd = *(uint8_t *) dtds[i];552553if (dtd >= SDP_SEQ8 && dtd <= SDP_ALT32)554data = (sdp_data_t *) values[i];555else556data = sdp_data_alloc(dtd, values[i]);557558if (!data)559return NULL;560561if (curr)562curr->next = data;563else564seq = data;565566curr = data;567}568569return sdp_data_alloc(SDP_SEQ8, seq);570}571572static void extract_svclass_uuid(sdp_data_t *data, uuid_t *uuid)573{574sdp_data_t *d;575576if (!data || !SDP_IS_SEQ(data->dtd))577return;578579d = data->val.dataseq;580if (!d)581return;582583if (d->dtd < SDP_UUID16 || d->dtd > SDP_UUID128)584return;585586*uuid = d->val.uuid;587}588589int sdp_attr_add(sdp_record_t *rec, uint16_t attr, sdp_data_t *d)590{591sdp_data_t *p = sdp_data_get(rec, attr);592593if (p)594return -1;595596d->attrId = attr;597rec->attrlist = sdp_list_insert_sorted(rec->attrlist, d, sdp_attrid_comp_func);598599if (attr == SDP_ATTR_SVCLASS_ID_LIST)600extract_svclass_uuid(d, &rec->svclass);601602return 0;603}604605void sdp_attr_remove(sdp_record_t *rec, uint16_t attr)606{607sdp_data_t *d = sdp_data_get(rec, attr);608609if (d)610rec->attrlist = sdp_list_remove(rec->attrlist, d);611612if (attr == SDP_ATTR_SVCLASS_ID_LIST)613memset(&rec->svclass, 0, sizeof(rec->svclass));614}615616void sdp_set_seq_len(uint8_t *ptr, uint32_t length)617{618uint8_t dtd = *ptr++;619620switch (dtd) {621case SDP_SEQ8:622case SDP_ALT8:623case SDP_TEXT_STR8:624case SDP_URL_STR8:625*ptr = (uint8_t) length;626break;627case SDP_SEQ16:628case SDP_ALT16:629case SDP_TEXT_STR16:630case SDP_URL_STR16:631bt_put_be16(length, ptr);632break;633case SDP_SEQ32:634case SDP_ALT32:635case SDP_TEXT_STR32:636case SDP_URL_STR32:637bt_put_be32(length, ptr);638break;639}640}641642static int sdp_get_data_type_size(uint8_t dtd)643{644int size = sizeof(uint8_t);645646switch (dtd) {647case SDP_SEQ8:648case SDP_TEXT_STR8:649case SDP_URL_STR8:650case SDP_ALT8:651size += sizeof(uint8_t);652break;653case SDP_SEQ16:654case SDP_TEXT_STR16:655case SDP_URL_STR16:656case SDP_ALT16:657size += sizeof(uint16_t);658break;659case SDP_SEQ32:660case SDP_TEXT_STR32:661case SDP_URL_STR32:662case SDP_ALT32:663size += sizeof(uint32_t);664break;665}666667return size;668}669670void sdp_set_attrid(sdp_buf_t *buf, uint16_t attr)671{672uint8_t *p = buf->data;673674/* data type for attr */675*p++ = SDP_UINT16;676buf->data_size = sizeof(uint8_t);677bt_put_be16(attr, p);678buf->data_size += sizeof(uint16_t);679}680681static int get_data_size(sdp_buf_t *buf, sdp_data_t *sdpdata)682{683sdp_data_t *d;684int n = 0;685686for (d = sdpdata->val.dataseq; d; d = d->next) {687if (buf->data)688n += sdp_gen_pdu(buf, d);689else690n += sdp_gen_buffer(buf, d);691}692693return n;694}695696static int sdp_get_data_size(sdp_buf_t *buf, sdp_data_t *d)697{698uint32_t data_size = 0;699uint8_t dtd = d->dtd;700701switch (dtd) {702case SDP_DATA_NIL:703break;704case SDP_UINT8:705data_size = sizeof(uint8_t);706break;707case SDP_UINT16:708data_size = sizeof(uint16_t);709break;710case SDP_UINT32:711data_size = sizeof(uint32_t);712break;713case SDP_UINT64:714data_size = sizeof(uint64_t);715break;716case SDP_UINT128:717data_size = sizeof(uint128_t);718break;719case SDP_INT8:720case SDP_BOOL:721data_size = sizeof(int8_t);722break;723case SDP_INT16:724data_size = sizeof(int16_t);725break;726case SDP_INT32:727data_size = sizeof(int32_t);728break;729case SDP_INT64:730data_size = sizeof(int64_t);731break;732case SDP_INT128:733data_size = sizeof(uint128_t);734break;735case SDP_TEXT_STR8:736case SDP_TEXT_STR16:737case SDP_TEXT_STR32:738case SDP_URL_STR8:739case SDP_URL_STR16:740case SDP_URL_STR32:741data_size = d->unitSize - sizeof(uint8_t);742break;743case SDP_SEQ8:744case SDP_SEQ16:745case SDP_SEQ32:746data_size = get_data_size(buf, d);747break;748case SDP_ALT8:749case SDP_ALT16:750case SDP_ALT32:751data_size = get_data_size(buf, d);752break;753case SDP_UUID16:754data_size = sizeof(uint16_t);755break;756case SDP_UUID32:757data_size = sizeof(uint32_t);758break;759case SDP_UUID128:760data_size = sizeof(uint128_t);761break;762default:763break;764}765766return data_size;767}768769static int sdp_gen_buffer(sdp_buf_t *buf, sdp_data_t *d)770{771int orig = buf->buf_size;772773if (buf->buf_size == 0 && d->dtd == 0) {774/* create initial sequence */775buf->buf_size += sizeof(uint8_t);776777/* reserve space for sequence size */778buf->buf_size += sizeof(uint8_t);779}780781/* attribute length */782buf->buf_size += sizeof(uint8_t) + sizeof(uint16_t);783784buf->buf_size += sdp_get_data_type_size(d->dtd);785buf->buf_size += sdp_get_data_size(buf, d);786787if (buf->buf_size > UCHAR_MAX && d->dtd == SDP_SEQ8)788buf->buf_size += sizeof(uint8_t);789790return buf->buf_size - orig;791}792793int sdp_gen_pdu(sdp_buf_t *buf, sdp_data_t *d)794{795uint32_t pdu_size, data_size;796unsigned char *src = NULL, is_seq = 0, is_alt = 0;797uint16_t u16;798uint32_t u32;799uint64_t u64;800uint128_t u128;801uint8_t *seqp = buf->data + buf->data_size;802uint32_t orig_data_size = buf->data_size;803804recalculate:805pdu_size = sdp_get_data_type_size(d->dtd);806buf->data_size += pdu_size;807808data_size = sdp_get_data_size(buf, d);809if (data_size > UCHAR_MAX && d->dtd == SDP_SEQ8) {810buf->data_size = orig_data_size;811d->dtd = SDP_SEQ16;812goto recalculate;813}814815*seqp = d->dtd;816817switch (d->dtd) {818case SDP_DATA_NIL:819break;820case SDP_UINT8:821src = &d->val.uint8;822break;823case SDP_UINT16:824u16 = htons(d->val.uint16);825src = (unsigned char *) &u16;826break;827case SDP_UINT32:828u32 = htonl(d->val.uint32);829src = (unsigned char *) &u32;830break;831case SDP_UINT64:832u64 = hton64(d->val.uint64);833src = (unsigned char *) &u64;834break;835case SDP_UINT128:836hton128(&d->val.uint128, &u128);837src = (unsigned char *) &u128;838break;839case SDP_INT8:840case SDP_BOOL:841src = (unsigned char *) &d->val.int8;842break;843case SDP_INT16:844u16 = htons(d->val.int16);845src = (unsigned char *) &u16;846break;847case SDP_INT32:848u32 = htonl(d->val.int32);849src = (unsigned char *) &u32;850break;851case SDP_INT64:852u64 = hton64(d->val.int64);853src = (unsigned char *) &u64;854break;855case SDP_INT128:856hton128(&d->val.int128, &u128);857src = (unsigned char *) &u128;858break;859case SDP_TEXT_STR8:860case SDP_TEXT_STR16:861case SDP_TEXT_STR32:862case SDP_URL_STR8:863case SDP_URL_STR16:864case SDP_URL_STR32:865src = (unsigned char *) d->val.str;866sdp_set_seq_len(seqp, data_size);867break;868case SDP_SEQ8:869case SDP_SEQ16:870case SDP_SEQ32:871is_seq = 1;872sdp_set_seq_len(seqp, data_size);873break;874case SDP_ALT8:875case SDP_ALT16:876case SDP_ALT32:877is_alt = 1;878sdp_set_seq_len(seqp, data_size);879break;880case SDP_UUID16:881u16 = htons(d->val.uuid.value.uuid16);882src = (unsigned char *) &u16;883break;884case SDP_UUID32:885u32 = htonl(d->val.uuid.value.uuid32);886src = (unsigned char *) &u32;887break;888case SDP_UUID128:889src = (unsigned char *) &d->val.uuid.value.uuid128;890break;891default:892break;893}894895if (!is_seq && !is_alt) {896if (src && buf->buf_size >= buf->data_size + data_size) {897memcpy(buf->data + buf->data_size, src, data_size);898buf->data_size += data_size;899} else if (d->dtd != SDP_DATA_NIL) {900SDPDBG("Gen PDU : Can't copy from invalid source or dest");901}902}903904pdu_size += data_size;905906return pdu_size;907}908909static void sdp_attr_pdu(void *value, void *udata)910{911sdp_append_to_pdu((sdp_buf_t *)udata, (sdp_data_t *)value);912}913914static void sdp_attr_size(void *value, void *udata)915{916sdp_gen_buffer((sdp_buf_t *)udata, (sdp_data_t *)value);917}918919int sdp_gen_record_pdu(const sdp_record_t *rec, sdp_buf_t *buf)920{921memset(buf, 0, sizeof(sdp_buf_t));922sdp_list_foreach(rec->attrlist, sdp_attr_size, buf);923924buf->data = malloc(buf->buf_size);925if (!buf->data)926return -ENOMEM;927buf->data_size = 0;928memset(buf->data, 0, buf->buf_size);929930sdp_list_foreach(rec->attrlist, sdp_attr_pdu, buf);931932return 0;933}934935void sdp_attr_replace(sdp_record_t *rec, uint16_t attr, sdp_data_t *d)936{937sdp_data_t *p = sdp_data_get(rec, attr);938939if (p) {940rec->attrlist = sdp_list_remove(rec->attrlist, p);941sdp_data_free(p);942}943944d->attrId = attr;945rec->attrlist = sdp_list_insert_sorted(rec->attrlist, d, sdp_attrid_comp_func);946947if (attr == SDP_ATTR_SVCLASS_ID_LIST)948extract_svclass_uuid(d, &rec->svclass);949}950951int sdp_attrid_comp_func(const void *key1, const void *key2)952{953const sdp_data_t *d1 = (const sdp_data_t *)key1;954const sdp_data_t *d2 = (const sdp_data_t *)key2;955956if (d1 && d2)957return d1->attrId - d2->attrId;958return 0;959}960961static void data_seq_free(sdp_data_t *seq)962{963sdp_data_t *d = seq->val.dataseq;964965while (d) {966sdp_data_t *next = d->next;967sdp_data_free(d);968d = next;969}970}971972void sdp_data_free(sdp_data_t *d)973{974switch (d->dtd) {975case SDP_SEQ8:976case SDP_SEQ16:977case SDP_SEQ32:978data_seq_free(d);979break;980case SDP_URL_STR8:981case SDP_URL_STR16:982case SDP_URL_STR32:983case SDP_TEXT_STR8:984case SDP_TEXT_STR16:985case SDP_TEXT_STR32:986free(d->val.str);987break;988}989free(d);990}991992int sdp_uuid_extract(const uint8_t *p, int bufsize, uuid_t *uuid, int *scanned)993{994uint8_t type;995996if (bufsize < (int) sizeof(uint8_t)) {997SDPERR("Unexpected end of packet");998return -1;999}10001001type = *(const uint8_t *) p;10021003if (!SDP_IS_UUID(type)) {1004SDPERR("Unknown data type : %d expecting a svc UUID", type);1005return -1;1006}1007p += sizeof(uint8_t);1008*scanned += sizeof(uint8_t);1009bufsize -= sizeof(uint8_t);1010if (type == SDP_UUID16) {1011if (bufsize < (int) sizeof(uint16_t)) {1012SDPERR("Not enough room for 16-bit UUID");1013return -1;1014}1015sdp_uuid16_create(uuid, bt_get_be16(p));1016*scanned += sizeof(uint16_t);1017} else if (type == SDP_UUID32) {1018if (bufsize < (int) sizeof(uint32_t)) {1019SDPERR("Not enough room for 32-bit UUID");1020return -1;1021}1022sdp_uuid32_create(uuid, bt_get_be32(p));1023*scanned += sizeof(uint32_t);1024} else {1025if (bufsize < (int) sizeof(uint128_t)) {1026SDPERR("Not enough room for 128-bit UUID");1027return -1;1028}1029sdp_uuid128_create(uuid, p);1030*scanned += sizeof(uint128_t);1031}1032return 0;1033}10341035static sdp_data_t *extract_int(const void *p, int bufsize, int *len)1036{1037sdp_data_t *d;10381039if (bufsize < (int) sizeof(uint8_t)) {1040SDPERR("Unexpected end of packet");1041return NULL;1042}10431044d = malloc(sizeof(sdp_data_t));1045if (!d)1046return NULL;10471048SDPDBG("Extracting integer");1049memset(d, 0, sizeof(sdp_data_t));1050d->dtd = *(uint8_t *) p;1051p += sizeof(uint8_t);1052*len += sizeof(uint8_t);1053bufsize -= sizeof(uint8_t);10541055switch (d->dtd) {1056case SDP_DATA_NIL:1057break;1058case SDP_BOOL:1059case SDP_INT8:1060case SDP_UINT8:1061if (bufsize < (int) sizeof(uint8_t)) {1062SDPERR("Unexpected end of packet");1063free(d);1064return NULL;1065}1066*len += sizeof(uint8_t);1067d->val.uint8 = *(uint8_t *) p;1068break;1069case SDP_INT16:1070case SDP_UINT16:1071if (bufsize < (int) sizeof(uint16_t)) {1072SDPERR("Unexpected end of packet");1073free(d);1074return NULL;1075}1076*len += sizeof(uint16_t);1077d->val.uint16 = bt_get_be16(p);1078break;1079case SDP_INT32:1080case SDP_UINT32:1081if (bufsize < (int) sizeof(uint32_t)) {1082SDPERR("Unexpected end of packet");1083free(d);1084return NULL;1085}1086*len += sizeof(uint32_t);1087d->val.uint32 = bt_get_be32(p);1088break;1089case SDP_INT64:1090case SDP_UINT64:1091if (bufsize < (int) sizeof(uint64_t)) {1092SDPERR("Unexpected end of packet");1093free(d);1094return NULL;1095}1096*len += sizeof(uint64_t);1097d->val.uint64 = bt_get_be64(p);1098break;1099case SDP_INT128:1100case SDP_UINT128:1101if (bufsize < (int) sizeof(uint128_t)) {1102SDPERR("Unexpected end of packet");1103free(d);1104return NULL;1105}1106*len += sizeof(uint128_t);1107ntoh128((uint128_t *) p, &d->val.uint128);1108break;1109default:1110free(d);1111d = NULL;1112}1113return d;1114}11151116static sdp_data_t *extract_uuid(const uint8_t *p, int bufsize, int *len,1117sdp_record_t *rec)1118{1119sdp_data_t *d = malloc(sizeof(sdp_data_t));11201121if (!d)1122return NULL;11231124SDPDBG("Extracting UUID");1125memset(d, 0, sizeof(sdp_data_t));1126if (sdp_uuid_extract(p, bufsize, &d->val.uuid, len) < 0) {1127free(d);1128return NULL;1129}1130d->dtd = *p;1131if (rec)1132sdp_pattern_add_uuid(rec, &d->val.uuid);1133return d;1134}11351136/*1137* Extract strings from the PDU (could be service description and similar info)1138*/1139static sdp_data_t *extract_str(const void *p, int bufsize, int *len)1140{1141char *s;1142int n;1143sdp_data_t *d;11441145if (bufsize < (int) sizeof(uint8_t)) {1146SDPERR("Unexpected end of packet");1147return NULL;1148}11491150d = malloc(sizeof(sdp_data_t));1151if (!d)1152return NULL;11531154memset(d, 0, sizeof(sdp_data_t));1155d->dtd = *(uint8_t *) p;1156p += sizeof(uint8_t);1157*len += sizeof(uint8_t);1158bufsize -= sizeof(uint8_t);11591160switch (d->dtd) {1161case SDP_TEXT_STR8:1162case SDP_URL_STR8:1163if (bufsize < (int) sizeof(uint8_t)) {1164SDPERR("Unexpected end of packet");1165free(d);1166return NULL;1167}1168n = *(uint8_t *) p;1169p += sizeof(uint8_t);1170*len += sizeof(uint8_t);1171bufsize -= sizeof(uint8_t);1172break;1173case SDP_TEXT_STR16:1174case SDP_URL_STR16:1175if (bufsize < (int) sizeof(uint16_t)) {1176SDPERR("Unexpected end of packet");1177free(d);1178return NULL;1179}1180n = bt_get_be16(p);1181p += sizeof(uint16_t);1182*len += sizeof(uint16_t);1183bufsize -= sizeof(uint16_t);1184break;1185default:1186SDPERR("Sizeof text string > UINT16_MAX");1187free(d);1188return NULL;1189}11901191if (bufsize < n) {1192SDPERR("String too long to fit in packet");1193free(d);1194return NULL;1195}11961197s = malloc(n + 1);1198if (!s) {1199SDPERR("Not enough memory for incoming string");1200free(d);1201return NULL;1202}1203memset(s, 0, n + 1);1204memcpy(s, p, n);12051206*len += n;12071208SDPDBG("Len : %d", n);1209SDPDBG("Str : %s", s);12101211d->val.str = s;1212d->unitSize = n + sizeof(uint8_t);1213return d;1214}12151216/*1217* Extract the sequence type and its length, and return offset into buf1218* or 0 on failure.1219*/1220int sdp_extract_seqtype(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *size)1221{1222uint8_t dtd;1223int scanned = sizeof(uint8_t);12241225if (bufsize < (int) sizeof(uint8_t)) {1226SDPERR("Unexpected end of packet");1227return 0;1228}12291230dtd = *(uint8_t *) buf;1231buf += sizeof(uint8_t);1232bufsize -= sizeof(uint8_t);1233*dtdp = dtd;1234switch (dtd) {1235case SDP_SEQ8:1236case SDP_ALT8:1237if (bufsize < (int) sizeof(uint8_t)) {1238SDPERR("Unexpected end of packet");1239return 0;1240}1241*size = *(uint8_t *) buf;1242scanned += sizeof(uint8_t);1243break;1244case SDP_SEQ16:1245case SDP_ALT16:1246if (bufsize < (int) sizeof(uint16_t)) {1247SDPERR("Unexpected end of packet");1248return 0;1249}1250*size = bt_get_be16(buf);1251scanned += sizeof(uint16_t);1252break;1253case SDP_SEQ32:1254case SDP_ALT32:1255if (bufsize < (int) sizeof(uint32_t)) {1256SDPERR("Unexpected end of packet");1257return 0;1258}1259*size = bt_get_be32(buf);1260scanned += sizeof(uint32_t);1261break;1262default:1263SDPERR("Unknown sequence type, aborting");1264return 0;1265}1266return scanned;1267}12681269static sdp_data_t *extract_seq(const void *p, int bufsize, int *len,1270sdp_record_t *rec)1271{1272int seqlen, n = 0;1273sdp_data_t *curr, *prev;1274sdp_data_t *d = malloc(sizeof(sdp_data_t));12751276if (!d)1277return NULL;12781279SDPDBG("Extracting SEQ");1280memset(d, 0, sizeof(sdp_data_t));1281*len = sdp_extract_seqtype(p, bufsize, &d->dtd, &seqlen);1282SDPDBG("Sequence Type : 0x%x length : 0x%x", d->dtd, seqlen);12831284if (*len == 0)1285return d;12861287if (*len > bufsize) {1288SDPERR("Packet not big enough to hold sequence.");1289free(d);1290return NULL;1291}12921293p += *len;1294bufsize -= *len;1295prev = NULL;1296while (n < seqlen) {1297int attrlen = 0;1298curr = sdp_extract_attr(p, bufsize, &attrlen, rec);1299if (curr == NULL)1300break;13011302if (prev)1303prev->next = curr;1304else1305d->val.dataseq = curr;1306prev = curr;1307p += attrlen;1308n += attrlen;1309bufsize -= attrlen;13101311SDPDBG("Extracted: %d SequenceLength: %d", n, seqlen);1312}13131314*len += n;1315return d;1316}13171318sdp_data_t *sdp_extract_attr(const uint8_t *p, int bufsize, int *size,1319sdp_record_t *rec)1320{1321sdp_data_t *elem;1322int n = 0;1323uint8_t dtd;13241325if (bufsize < (int) sizeof(uint8_t)) {1326SDPERR("Unexpected end of packet");1327return NULL;1328}13291330dtd = *(const uint8_t *)p;13311332SDPDBG("extract_attr: dtd=0x%x", dtd);1333switch (dtd) {1334case SDP_DATA_NIL:1335case SDP_BOOL:1336case SDP_UINT8:1337case SDP_UINT16:1338case SDP_UINT32:1339case SDP_UINT64:1340case SDP_UINT128:1341case SDP_INT8:1342case SDP_INT16:1343case SDP_INT32:1344case SDP_INT64:1345case SDP_INT128:1346elem = extract_int(p, bufsize, &n);1347break;1348case SDP_UUID16:1349case SDP_UUID32:1350case SDP_UUID128:1351elem = extract_uuid(p, bufsize, &n, rec);1352break;1353case SDP_TEXT_STR8:1354case SDP_TEXT_STR16:1355case SDP_TEXT_STR32:1356case SDP_URL_STR8:1357case SDP_URL_STR16:1358case SDP_URL_STR32:1359elem = extract_str(p, bufsize, &n);1360break;1361case SDP_SEQ8:1362case SDP_SEQ16:1363case SDP_SEQ32:1364case SDP_ALT8:1365case SDP_ALT16:1366case SDP_ALT32:1367elem = extract_seq(p, bufsize, &n, rec);1368break;1369default:1370SDPERR("Unknown data descriptor : 0x%x terminating", dtd);1371return NULL;1372}1373*size += n;1374return elem;1375}13761377#ifdef SDP_DEBUG1378static void attr_print_func(void *value, void *userData)1379{1380sdp_data_t *d = (sdp_data_t *)value;13811382SDPDBG("=====================================");1383SDPDBG("ATTRIBUTE IDENTIFIER : 0x%x", d->attrId);1384SDPDBG("ATTRIBUTE VALUE PTR : %p", value);1385if (d)1386sdp_data_print(d);1387else1388SDPDBG("NULL value");1389SDPDBG("=====================================");1390}13911392void sdp_print_service_attr(sdp_list_t *svcAttrList)1393{1394SDPDBG("Printing service attr list %p", svcAttrList);1395sdp_list_foreach(svcAttrList, attr_print_func, NULL);1396SDPDBG("Printed service attr list %p", svcAttrList);1397}1398#endif13991400sdp_record_t *sdp_extract_pdu(const uint8_t *buf, int bufsize, int *scanned)1401{1402int extracted = 0, seqlen = 0;1403uint8_t dtd;1404uint16_t attr;1405sdp_record_t *rec = sdp_record_alloc();1406const uint8_t *p = buf;14071408*scanned = sdp_extract_seqtype(buf, bufsize, &dtd, &seqlen);1409p += *scanned;1410bufsize -= *scanned;1411rec->attrlist = NULL;14121413while (extracted < seqlen && bufsize > 0) {1414int n = sizeof(uint8_t), attrlen = 0;1415sdp_data_t *data = NULL;14161417SDPDBG("Extract PDU, sequenceLength: %d localExtractedLength: %d",1418seqlen, extracted);14191420if (bufsize < n + (int) sizeof(uint16_t)) {1421SDPERR("Unexpected end of packet");1422break;1423}14241425dtd = *(uint8_t *) p;1426attr = bt_get_be16(p + n);1427n += sizeof(uint16_t);14281429SDPDBG("DTD of attrId : %d Attr id : 0x%x ", dtd, attr);14301431data = sdp_extract_attr(p + n, bufsize - n, &attrlen, rec);14321433SDPDBG("Attr id : 0x%x attrValueLength : %d", attr, attrlen);14341435n += attrlen;1436if (data == NULL) {1437SDPDBG("Terminating extraction of attributes");1438break;1439}14401441if (attr == SDP_ATTR_RECORD_HANDLE)1442rec->handle = data->val.uint32;14431444if (attr == SDP_ATTR_SVCLASS_ID_LIST)1445extract_svclass_uuid(data, &rec->svclass);14461447extracted += n;1448p += n;1449bufsize -= n;1450sdp_attr_replace(rec, attr, data);14511452SDPDBG("Extract PDU, seqLength: %d localExtractedLength: %d",1453seqlen, extracted);1454}1455#ifdef SDP_DEBUG1456SDPDBG("Successful extracting of Svc Rec attributes");1457sdp_print_service_attr(rec->attrlist);1458#endif1459*scanned += seqlen;1460return rec;1461}14621463static void sdp_copy_pattern(void *value, void *udata)1464{1465uuid_t *uuid = value;1466sdp_record_t *rec = udata;14671468sdp_pattern_add_uuid(rec, uuid);1469}14701471static void *sdp_data_value(sdp_data_t *data, uint32_t *len)1472{1473void *val = NULL;14741475switch (data->dtd) {1476case SDP_DATA_NIL:1477break;1478case SDP_UINT8:1479val = &data->val.uint8;1480break;1481case SDP_INT8:1482case SDP_BOOL:1483val = &data->val.int8;1484break;1485case SDP_UINT16:1486val = &data->val.uint16;1487break;1488case SDP_INT16:1489val = &data->val.int16;1490break;1491case SDP_UINT32:1492val = &data->val.uint32;1493break;1494case SDP_INT32:1495val = &data->val.int32;1496break;1497case SDP_INT64:1498val = &data->val.int64;1499break;1500case SDP_UINT64:1501val = &data->val.uint64;1502break;1503case SDP_UINT128:1504val = &data->val.uint128;1505break;1506case SDP_INT128:1507val = &data->val.int128;1508break;1509case SDP_UUID16:1510val = &data->val.uuid.value.uuid16;1511break;1512case SDP_UUID32:1513val = &data->val.uuid.value.uuid32;1514break;1515case SDP_UUID128:1516val = &data->val.uuid.value.uuid128;1517break;1518case SDP_URL_STR8:1519case SDP_URL_STR16:1520case SDP_TEXT_STR8:1521case SDP_TEXT_STR16:1522case SDP_URL_STR32:1523case SDP_TEXT_STR32:1524val = data->val.str;1525if (len)1526*len = data->unitSize - 1;1527break;1528case SDP_ALT8:1529case SDP_ALT16:1530case SDP_ALT32:1531case SDP_SEQ8:1532case SDP_SEQ16:1533case SDP_SEQ32:1534val = sdp_copy_seq(data->val.dataseq);1535break;1536}15371538return val;1539}15401541static sdp_data_t *sdp_copy_seq(sdp_data_t *data)1542{1543sdp_data_t *tmp, *seq = NULL, *cur = NULL;15441545for (tmp = data; tmp; tmp = tmp->next) {1546sdp_data_t *datatmp;1547void *value;15481549value = sdp_data_value(tmp, NULL);1550datatmp = sdp_data_alloc_with_length(tmp->dtd, value,1551tmp->unitSize);15521553if (cur)1554cur->next = datatmp;1555else1556seq = datatmp;15571558cur = datatmp;1559}15601561return seq;1562}15631564static void sdp_copy_attrlist(void *value, void *udata)1565{1566sdp_data_t *data = value;1567sdp_record_t *rec = udata;1568void *val;1569uint32_t len = 0;15701571val = sdp_data_value(data, &len);15721573if (!len)1574sdp_attr_add_new(rec, data->attrId, data->dtd, val);1575else1576sdp_attr_add_new_with_length(rec, data->attrId,1577data->dtd, val, len);1578}15791580sdp_record_t *sdp_copy_record(sdp_record_t *rec)1581{1582sdp_record_t *cpy;15831584cpy = sdp_record_alloc();15851586cpy->handle = rec->handle;15871588sdp_list_foreach(rec->pattern, sdp_copy_pattern, cpy);1589sdp_list_foreach(rec->attrlist, sdp_copy_attrlist, cpy);15901591cpy->svclass = rec->svclass;15921593return cpy;1594}15951596#ifdef SDP_DEBUG1597static void print_dataseq(sdp_data_t *p)1598{1599sdp_data_t *d;16001601for (d = p; d; d = d->next)1602sdp_data_print(d);1603}1604#endif16051606void sdp_record_print(const sdp_record_t *rec)1607{1608sdp_data_t *d = sdp_data_get(rec, SDP_ATTR_SVCNAME_PRIMARY);1609if (d && SDP_IS_TEXT_STR(d->dtd))1610printf("Service Name: %.*s", d->unitSize, d->val.str);1611d = sdp_data_get(rec, SDP_ATTR_SVCDESC_PRIMARY);1612if (d && SDP_IS_TEXT_STR(d->dtd))1613printf("Service Description: %.*s", d->unitSize, d->val.str);1614d = sdp_data_get(rec, SDP_ATTR_PROVNAME_PRIMARY);1615if (d && SDP_IS_TEXT_STR(d->dtd))1616printf("Service Provider: %.*s", d->unitSize, d->val.str);1617}16181619#ifdef SDP_DEBUG1620void sdp_data_print(sdp_data_t *d)1621{1622switch (d->dtd) {1623case SDP_DATA_NIL:1624SDPDBG("NIL");1625break;1626case SDP_BOOL:1627case SDP_UINT8:1628case SDP_UINT16:1629case SDP_UINT32:1630case SDP_UINT64:1631case SDP_UINT128:1632case SDP_INT8:1633case SDP_INT16:1634case SDP_INT32:1635case SDP_INT64:1636case SDP_INT128:1637SDPDBG("Integer : 0x%x", d->val.uint32);1638break;1639case SDP_UUID16:1640case SDP_UUID32:1641case SDP_UUID128:1642SDPDBG("UUID");1643sdp_uuid_print(&d->val.uuid);1644break;1645case SDP_TEXT_STR8:1646case SDP_TEXT_STR16:1647case SDP_TEXT_STR32:1648SDPDBG("Text : %s", d->val.str);1649break;1650case SDP_URL_STR8:1651case SDP_URL_STR16:1652case SDP_URL_STR32:1653SDPDBG("URL : %s", d->val.str);1654break;1655case SDP_SEQ8:1656case SDP_SEQ16:1657case SDP_SEQ32:1658print_dataseq(d->val.dataseq);1659break;1660case SDP_ALT8:1661case SDP_ALT16:1662case SDP_ALT32:1663SDPDBG("Data Sequence Alternates");1664print_dataseq(d->val.dataseq);1665break;1666}1667}1668#endif16691670sdp_data_t *sdp_data_get(const sdp_record_t *rec, uint16_t attrId)1671{1672if (rec->attrlist) {1673sdp_data_t sdpTemplate;1674sdp_list_t *p;16751676sdpTemplate.attrId = attrId;1677p = sdp_list_find(rec->attrlist, &sdpTemplate, sdp_attrid_comp_func);1678if (p)1679return p->data;1680}1681return NULL;1682}16831684static int sdp_send_req(sdp_session_t *session, uint8_t *buf, uint32_t size)1685{1686uint32_t sent = 0;16871688while (sent < size) {1689int n = send(session->sock, buf + sent, size - sent, 0);1690if (n < 0)1691return -1;1692sent += n;1693}1694return 0;1695}16961697static int sdp_read_rsp(sdp_session_t *session, uint8_t *buf, uint32_t size)1698{1699fd_set readFds;1700struct timeval timeout = { SDP_RESPONSE_TIMEOUT, 0 };17011702FD_ZERO(&readFds);1703FD_SET(session->sock, &readFds);1704SDPDBG("Waiting for response");1705if (select(session->sock + 1, &readFds, NULL, NULL, &timeout) == 0) {1706SDPERR("Client timed out");1707errno = ETIMEDOUT;1708return -1;1709}1710return recv(session->sock, buf, size, 0);1711}17121713/*1714* generic send request, wait for response method.1715*/1716int sdp_send_req_w4_rsp(sdp_session_t *session, uint8_t *reqbuf,1717uint8_t *rspbuf, uint32_t reqsize, uint32_t *rspsize)1718{1719int n;1720sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *) reqbuf;1721sdp_pdu_hdr_t *rsphdr = (sdp_pdu_hdr_t *) rspbuf;17221723SDPDBG("");1724if (0 > sdp_send_req(session, reqbuf, reqsize)) {1725SDPERR("Error sending data:%m");1726return -1;1727}1728n = sdp_read_rsp(session, rspbuf, SDP_RSP_BUFFER_SIZE);1729if (0 > n)1730return -1;1731SDPDBG("Read : %d", n);1732if (n == 0 || reqhdr->tid != rsphdr->tid) {1733errno = EPROTO;1734return -1;1735}1736*rspsize = n;1737return 0;1738}17391740/*1741* singly-linked lists (after openobex implementation)1742*/1743sdp_list_t *sdp_list_append(sdp_list_t *p, void *d)1744{1745sdp_list_t *q, *n = malloc(sizeof(sdp_list_t));17461747if (!n)1748return NULL;17491750n->data = d;1751n->next = 0;17521753if (!p)1754return n;17551756for (q = p; q->next; q = q->next);1757q->next = n;17581759return p;1760}17611762sdp_list_t *sdp_list_remove(sdp_list_t *list, void *d)1763{1764sdp_list_t *p, *q;17651766for (q = 0, p = list; p; q = p, p = p->next)1767if (p->data == d) {1768if (q)1769q->next = p->next;1770else1771list = p->next;1772free(p);1773break;1774}17751776return list;1777}17781779sdp_list_t *sdp_list_insert_sorted(sdp_list_t *list, void *d,1780sdp_comp_func_t f)1781{1782sdp_list_t *q, *p, *n;17831784n = malloc(sizeof(sdp_list_t));1785if (!n)1786return NULL;1787n->data = d;1788for (q = 0, p = list; p; q = p, p = p->next)1789if (f(p->data, d) >= 0)1790break;1791/* insert between q and p; if !q insert at head */1792if (q)1793q->next = n;1794else1795list = n;1796n->next = p;1797return list;1798}17991800/*1801* Every element of the list points to things which need1802* to be free()'d. This method frees the list's contents1803*/1804void sdp_list_free(sdp_list_t *list, sdp_free_func_t f)1805{1806sdp_list_t *next;1807while (list) {1808next = list->next;1809if (f)1810f(list->data);1811free(list);1812list = next;1813}1814}18151816static inline int __find_port(sdp_data_t *seq, int proto)1817{1818if (!seq || !seq->next)1819return 0;18201821if (SDP_IS_UUID(seq->dtd) && sdp_uuid_to_proto(&seq->val.uuid) == proto) {1822seq = seq->next;1823switch (seq->dtd) {1824case SDP_UINT8:1825return seq->val.uint8;1826case SDP_UINT16:1827return seq->val.uint16;1828}1829}1830return 0;1831}18321833int sdp_get_proto_port(const sdp_list_t *list, int proto)1834{1835if (proto != L2CAP_UUID && proto != RFCOMM_UUID) {1836errno = EINVAL;1837return -1;1838}18391840for (; list; list = list->next) {1841sdp_list_t *p;1842for (p = list->data; p; p = p->next) {1843sdp_data_t *seq = p->data;1844int port = __find_port(seq, proto);1845if (port)1846return port;1847}1848}1849return 0;1850}18511852sdp_data_t *sdp_get_proto_desc(sdp_list_t *list, int proto)1853{1854for (; list; list = list->next) {1855sdp_list_t *p;1856for (p = list->data; p; p = p->next) {1857sdp_data_t *seq = p->data;1858if (SDP_IS_UUID(seq->dtd) &&1859sdp_uuid_to_proto(&seq->val.uuid) == proto)1860return seq->next;1861}1862}1863return NULL;1864}18651866static int sdp_get_proto_descs(uint16_t attr_id, const sdp_record_t *rec,1867sdp_list_t **pap)1868{1869sdp_data_t *pdlist, *curr;1870sdp_list_t *ap = NULL;18711872pdlist = sdp_data_get(rec, attr_id);1873if (pdlist == NULL) {1874errno = ENODATA;1875return -1;1876}18771878SDPDBG("Attribute value type: 0x%02x", pdlist->dtd);18791880if (attr_id == SDP_ATTR_ADD_PROTO_DESC_LIST) {1881if (!SDP_IS_SEQ(pdlist->dtd)) {1882errno = EINVAL;1883return -1;1884}1885pdlist = pdlist->val.dataseq;1886}18871888for (; pdlist; pdlist = pdlist->next) {1889sdp_list_t *pds = NULL;18901891if (!SDP_IS_SEQ(pdlist->dtd) && !SDP_IS_ALT(pdlist->dtd))1892goto failed;18931894for (curr = pdlist->val.dataseq; curr; curr = curr->next) {1895if (!SDP_IS_SEQ(curr->dtd)) {1896sdp_list_free(pds, NULL);1897goto failed;1898}1899pds = sdp_list_append(pds, curr->val.dataseq);1900}19011902ap = sdp_list_append(ap, pds);1903}19041905*pap = ap;19061907return 0;19081909failed:1910sdp_list_foreach(ap, (sdp_list_func_t) sdp_list_free, NULL);1911sdp_list_free(ap, NULL);1912errno = EINVAL;19131914return -1;1915}19161917int sdp_get_access_protos(const sdp_record_t *rec, sdp_list_t **pap)1918{1919return sdp_get_proto_descs(SDP_ATTR_PROTO_DESC_LIST, rec, pap);1920}19211922int sdp_get_add_access_protos(const sdp_record_t *rec, sdp_list_t **pap)1923{1924return sdp_get_proto_descs(SDP_ATTR_ADD_PROTO_DESC_LIST, rec, pap);1925}19261927int sdp_get_uuidseq_attr(const sdp_record_t *rec, uint16_t attr,1928sdp_list_t **seqp)1929{1930sdp_data_t *sdpdata = sdp_data_get(rec, attr);19311932*seqp = NULL;1933if (sdpdata && SDP_IS_SEQ(sdpdata->dtd)) {1934sdp_data_t *d;1935for (d = sdpdata->val.dataseq; d; d = d->next) {1936uuid_t *u;1937if (d->dtd < SDP_UUID16 || d->dtd > SDP_UUID128) {1938errno = EINVAL;1939goto fail;1940}19411942u = malloc(sizeof(uuid_t));1943if (!u)1944goto fail;19451946*u = d->val.uuid;1947*seqp = sdp_list_append(*seqp, u);1948}1949return 0;1950}1951fail:1952sdp_list_free(*seqp, free);1953*seqp = NULL;1954return -1;1955}19561957int sdp_set_uuidseq_attr(sdp_record_t *rec, uint16_t aid, sdp_list_t *seq)1958{1959int status = 0, i, len;1960void **dtds, **values;1961uint8_t uuid16 = SDP_UUID16;1962uint8_t uuid32 = SDP_UUID32;1963uint8_t uuid128 = SDP_UUID128;1964sdp_list_t *p;19651966len = sdp_list_len(seq);1967if (!seq || len == 0)1968return -1;1969dtds = malloc(len * sizeof(void *));1970if (!dtds)1971return -1;19721973values = malloc(len * sizeof(void *));1974if (!values) {1975free(dtds);1976return -1;1977}19781979for (p = seq, i = 0; i < len; i++, p = p->next) {1980uuid_t *uuid = p->data;1981if (uuid)1982switch (uuid->type) {1983case SDP_UUID16:1984dtds[i] = &uuid16;1985values[i] = &uuid->value.uuid16;1986break;1987case SDP_UUID32:1988dtds[i] = &uuid32;1989values[i] = &uuid->value.uuid32;1990break;1991case SDP_UUID128:1992dtds[i] = &uuid128;1993values[i] = &uuid->value.uuid128;1994break;1995default:1996status = -1;1997break;1998}1999else {2000status = -1;2001break;2002}2003}2004if (status == 0) {2005sdp_data_t *data = sdp_seq_alloc(dtds, values, len);2006sdp_attr_replace(rec, aid, data);2007sdp_pattern_add_uuidseq(rec, seq);2008}2009free(dtds);2010free(values);2011return status;2012}20132014int sdp_get_lang_attr(const sdp_record_t *rec, sdp_list_t **langSeq)2015{2016sdp_lang_attr_t *lang;2017sdp_data_t *sdpdata, *curr_data;20182019*langSeq = NULL;2020sdpdata = sdp_data_get(rec, SDP_ATTR_LANG_BASE_ATTR_ID_LIST);2021if (sdpdata == NULL) {2022errno = ENODATA;2023return -1;2024}20252026if (!SDP_IS_SEQ(sdpdata->dtd))2027goto invalid;2028curr_data = sdpdata->val.dataseq;20292030while (curr_data) {2031sdp_data_t *pCode, *pEncoding, *pOffset;20322033pCode = curr_data;2034if (pCode->dtd != SDP_UINT16)2035goto invalid;20362037/* LanguageBaseAttributeIDList entries are always grouped as2038* triplets */2039if (!pCode->next || !pCode->next->next)2040goto invalid;20412042pEncoding = pCode->next;2043if (pEncoding->dtd != SDP_UINT16)2044goto invalid;20452046pOffset = pEncoding->next;2047if (pOffset->dtd != SDP_UINT16)2048goto invalid;20492050lang = malloc(sizeof(sdp_lang_attr_t));2051if (!lang) {2052sdp_list_free(*langSeq, free);2053*langSeq = NULL;2054return -1;2055}2056lang->code_ISO639 = pCode->val.uint16;2057lang->encoding = pEncoding->val.uint16;2058lang->base_offset = pOffset->val.uint16;2059SDPDBG("code_ISO639 : 0x%02x", lang->code_ISO639);2060SDPDBG("encoding : 0x%02x", lang->encoding);2061SDPDBG("base_offfset : 0x%02x", lang->base_offset);2062*langSeq = sdp_list_append(*langSeq, lang);20632064curr_data = pOffset->next;2065}20662067return 0;20682069invalid:2070sdp_list_free(*langSeq, free);2071*langSeq = NULL;2072errno = EINVAL;20732074return -1;2075}20762077int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDescSeq)2078{2079sdp_profile_desc_t *profDesc;2080sdp_data_t *sdpdata, *seq;20812082*profDescSeq = NULL;2083sdpdata = sdp_data_get(rec, SDP_ATTR_PFILE_DESC_LIST);2084if (sdpdata == NULL) {2085errno = ENODATA;2086return -1;2087}20882089if (!SDP_IS_SEQ(sdpdata->dtd) || sdpdata->val.dataseq == NULL)2090goto invalid;20912092for (seq = sdpdata->val.dataseq; seq; seq = seq->next) {2093uuid_t *uuid = NULL;2094uint16_t version = 0x100;20952096if (SDP_IS_UUID(seq->dtd)) {2097/* Mac OS X 10.7.3 and old Samsung phones do not comply2098* to the SDP specification for2099* BluetoothProfileDescriptorList. This workaround2100* allows to properly parse UUID/version from SDP2101* record published by these systems. */2102sdp_data_t *next = seq->next;2103uuid = &seq->val.uuid;2104if (next && next->dtd == SDP_UINT16) {2105version = next->val.uint16;2106seq = next;2107}2108} else if (SDP_IS_SEQ(seq->dtd)) {2109sdp_data_t *puuid, *pVnum;21102111puuid = seq->val.dataseq;2112if (puuid == NULL || !SDP_IS_UUID(puuid->dtd))2113goto invalid;21142115uuid = &puuid->val.uuid;21162117pVnum = puuid->next;2118if (pVnum == NULL || pVnum->dtd != SDP_UINT16)2119goto invalid;21202121version = pVnum->val.uint16;2122} else2123goto invalid;21242125if (uuid != NULL) {2126profDesc = malloc(sizeof(sdp_profile_desc_t));2127if (!profDesc) {2128sdp_list_free(*profDescSeq, free);2129*profDescSeq = NULL;2130return -1;2131}2132profDesc->uuid = *uuid;2133profDesc->version = version;2134#ifdef SDP_DEBUG2135sdp_uuid_print(&profDesc->uuid);2136SDPDBG("Vnum : 0x%04x", profDesc->version);2137#endif2138*profDescSeq = sdp_list_append(*profDescSeq, profDesc);2139}2140}2141return 0;21422143invalid:2144sdp_list_free(*profDescSeq, free);2145*profDescSeq = NULL;2146errno = EINVAL;21472148return -1;2149}21502151int sdp_get_server_ver(const sdp_record_t *rec, sdp_list_t **u16)2152{2153sdp_data_t *d, *curr;21542155*u16 = NULL;2156d = sdp_data_get(rec, SDP_ATTR_VERSION_NUM_LIST);2157if (d == NULL) {2158errno = ENODATA;2159return -1;2160}21612162if (!SDP_IS_SEQ(d->dtd) || d->val.dataseq == NULL)2163goto invalid;21642165for (curr = d->val.dataseq; curr; curr = curr->next) {2166if (curr->dtd != SDP_UINT16)2167goto invalid;2168*u16 = sdp_list_append(*u16, &curr->val.uint16);2169}21702171return 0;21722173invalid:2174sdp_list_free(*u16, NULL);2175*u16 = NULL;2176errno = EINVAL;21772178return -1;2179}21802181/* flexible extraction of basic attributes - Jean II */2182/* How do we expect caller to extract predefined data sequences? */2183int sdp_get_int_attr(const sdp_record_t *rec, uint16_t attrid, int *value)2184{2185sdp_data_t *sdpdata = sdp_data_get(rec, attrid);21862187if (sdpdata)2188/* Verify that it is what the caller expects */2189if (sdpdata->dtd == SDP_BOOL || sdpdata->dtd == SDP_UINT8 ||2190sdpdata->dtd == SDP_UINT16 || sdpdata->dtd == SDP_UINT32 ||2191sdpdata->dtd == SDP_INT8 || sdpdata->dtd == SDP_INT16 ||2192sdpdata->dtd == SDP_INT32) {2193*value = sdpdata->val.uint32;2194return 0;2195}2196errno = EINVAL;2197return -1;2198}21992200int sdp_get_string_attr(const sdp_record_t *rec, uint16_t attrid, char *value,2201int valuelen)2202{2203sdp_data_t *sdpdata = sdp_data_get(rec, attrid);2204if (sdpdata)2205/* Verify that it is what the caller expects */2206if (SDP_IS_TEXT_STR(sdpdata->dtd))2207if ((int) strlen(sdpdata->val.str) < valuelen) {2208strcpy(value, sdpdata->val.str);2209return 0;2210}2211errno = EINVAL;2212return -1;2213}22142215#define get_basic_attr(attrID, pAttrValue, fieldName) \2216sdp_data_t *data = sdp_data_get(rec, attrID); \2217if (data) { \2218*pAttrValue = data->val.fieldName; \2219return 0; \2220} \2221errno = EINVAL; \2222return -1;22232224int sdp_get_service_id(const sdp_record_t *rec, uuid_t *uuid)2225{2226get_basic_attr(SDP_ATTR_SERVICE_ID, uuid, uuid);2227}22282229int sdp_get_group_id(const sdp_record_t *rec, uuid_t *uuid)2230{2231get_basic_attr(SDP_ATTR_GROUP_ID, uuid, uuid);2232}22332234int sdp_get_record_state(const sdp_record_t *rec, uint32_t *svcRecState)2235{2236get_basic_attr(SDP_ATTR_RECORD_STATE, svcRecState, uint32);2237}22382239int sdp_get_service_avail(const sdp_record_t *rec, uint8_t *svcAvail)2240{2241get_basic_attr(SDP_ATTR_SERVICE_AVAILABILITY, svcAvail, uint8);2242}22432244int sdp_get_service_ttl(const sdp_record_t *rec, uint32_t *svcTTLInfo)2245{2246get_basic_attr(SDP_ATTR_SVCINFO_TTL, svcTTLInfo, uint32);2247}22482249int sdp_get_database_state(const sdp_record_t *rec, uint32_t *svcDBState)2250{2251get_basic_attr(SDP_ATTR_SVCDB_STATE, svcDBState, uint32);2252}22532254/*2255* NOTE that none of the setXXX() functions below will2256* actually update the SDP server, unless the2257* {register, update}sdp_record_t() function is invoked.2258*/22592260int sdp_attr_add_new(sdp_record_t *rec, uint16_t attr, uint8_t dtd,2261const void *value)2262{2263sdp_data_t *d = sdp_data_alloc(dtd, value);2264if (d) {2265sdp_attr_replace(rec, attr, d);2266return 0;2267}2268return -1;2269}22702271static int sdp_attr_add_new_with_length(sdp_record_t *rec,2272uint16_t attr, uint8_t dtd, const void *value, uint32_t len)2273{2274sdp_data_t *d;22752276d = sdp_data_alloc_with_length(dtd, value, len);2277if (!d)2278return -1;22792280sdp_attr_replace(rec, attr, d);22812282return 0;2283}22842285/*2286* Set the information attributes of the service2287* pointed to by rec. The attributes are2288* service name, description and provider name2289*/2290void sdp_set_info_attr(sdp_record_t *rec, const char *name, const char *prov,2291const char *desc)2292{2293if (name)2294sdp_attr_add_new(rec, SDP_ATTR_SVCNAME_PRIMARY,2295SDP_TEXT_STR8, name);2296if (prov)2297sdp_attr_add_new(rec, SDP_ATTR_PROVNAME_PRIMARY,2298SDP_TEXT_STR8, prov);2299if (desc)2300sdp_attr_add_new(rec, SDP_ATTR_SVCDESC_PRIMARY,2301SDP_TEXT_STR8, desc);2302}23032304static sdp_data_t *access_proto_to_dataseq(sdp_record_t *rec, sdp_list_t *proto)2305{2306sdp_data_t *seq = NULL;2307void *dtds[10], *values[10];2308void **seqDTDs, **seqs;2309int i, seqlen;2310sdp_list_t *p;23112312seqlen = sdp_list_len(proto);2313seqDTDs = malloc(seqlen * sizeof(void *));2314if (!seqDTDs)2315return NULL;23162317seqs = malloc(seqlen * sizeof(void *));2318if (!seqs) {2319free(seqDTDs);2320return NULL;2321}23222323for (i = 0, p = proto; p; p = p->next, i++) {2324sdp_list_t *elt = p->data;2325sdp_data_t *s;2326uuid_t *uuid = NULL;2327unsigned int pslen = 0;2328for (; elt && pslen < ARRAY_SIZE(dtds); elt = elt->next, pslen++) {2329sdp_data_t *d = elt->data;2330dtds[pslen] = &d->dtd;2331switch (d->dtd) {2332case SDP_UUID16:2333uuid = (uuid_t *) d;2334values[pslen] = &uuid->value.uuid16;2335break;2336case SDP_UUID32:2337uuid = (uuid_t *) d;2338values[pslen] = &uuid->value.uuid32;2339break;2340case SDP_UUID128:2341uuid = (uuid_t *) d;2342values[pslen] = &uuid->value.uuid128;2343break;2344case SDP_UINT8:2345values[pslen] = &d->val.uint8;2346break;2347case SDP_UINT16:2348values[pslen] = &d->val.uint16;2349break;2350case SDP_SEQ8:2351case SDP_SEQ16:2352case SDP_SEQ32:2353values[pslen] = d;2354break;2355/* FIXME: more */2356}2357}2358s = sdp_seq_alloc(dtds, values, pslen);2359if (s) {2360seqDTDs[i] = &s->dtd;2361seqs[i] = s;2362if (uuid)2363sdp_pattern_add_uuid(rec, uuid);2364}2365}2366seq = sdp_seq_alloc(seqDTDs, seqs, seqlen);2367free(seqDTDs);2368free(seqs);2369return seq;2370}23712372/*2373* sets the access protocols of the service specified2374* to the value specified in "access_proto"2375*2376* Note that if there are alternate mechanisms by2377* which the service is accessed, then they should2378* be specified as sequences2379*2380* Using a value of NULL for accessProtocols has2381* effect of removing this attribute (if previously set)2382*2383* This function replaces the existing sdp_access_proto_t2384* structure (if any) with the new one specified.2385*2386* returns 0 if successful or -1 if there is a failure.2387*/2388int sdp_set_access_protos(sdp_record_t *rec, const sdp_list_t *ap)2389{2390const sdp_list_t *p;2391sdp_data_t *protos = NULL;23922393for (p = ap; p; p = p->next) {2394sdp_data_t *seq = access_proto_to_dataseq(rec, p->data);2395protos = sdp_seq_append(protos, seq);2396}23972398sdp_attr_add(rec, SDP_ATTR_PROTO_DESC_LIST, protos);23992400return 0;2401}24022403int sdp_set_add_access_protos(sdp_record_t *rec, const sdp_list_t *ap)2404{2405const sdp_list_t *p;2406sdp_data_t *protos = NULL;24072408for (p = ap; p; p = p->next) {2409sdp_data_t *seq = access_proto_to_dataseq(rec, p->data);2410protos = sdp_seq_append(protos, seq);2411}24122413sdp_attr_add(rec, SDP_ATTR_ADD_PROTO_DESC_LIST,2414protos ? sdp_data_alloc(SDP_SEQ8, protos) : NULL);24152416return 0;2417}24182419/*2420* set the "LanguageBase" attributes of the service record2421* record to the value specified in "langAttrList".2422*2423* "langAttrList" is a linked list of "sdp_lang_attr_t"2424* objects, one for each language in which user visible2425* attributes are present in the service record.2426*2427* Using a value of NULL for langAttrList has2428* effect of removing this attribute (if previously set)2429*2430* This function replaces the exisiting sdp_lang_attr_t2431* structure (if any) with the new one specified.2432*2433* returns 0 if successful or -1 if there is a failure.2434*/2435int sdp_set_lang_attr(sdp_record_t *rec, const sdp_list_t *seq)2436{2437uint8_t uint16 = SDP_UINT16;2438int status = 0, i = 0, seqlen = sdp_list_len(seq);2439void **dtds, **values;2440const sdp_list_t *p;24412442dtds = malloc(3 * seqlen * sizeof(void *));2443if (!dtds)2444return -1;24452446values = malloc(3 * seqlen * sizeof(void *));2447if (!values) {2448free(dtds);2449return -1;2450}24512452for (p = seq; p; p = p->next) {2453sdp_lang_attr_t *lang = p->data;2454if (!lang) {2455status = -1;2456break;2457}2458dtds[i] = &uint16;2459values[i] = &lang->code_ISO639;2460i++;2461dtds[i] = &uint16;2462values[i] = &lang->encoding;2463i++;2464dtds[i] = &uint16;2465values[i] = &lang->base_offset;2466i++;2467}2468if (status == 0) {2469sdp_data_t *seq = sdp_seq_alloc(dtds, values, 3 * seqlen);2470sdp_attr_add(rec, SDP_ATTR_LANG_BASE_ATTR_ID_LIST, seq);2471}2472free(dtds);2473free(values);2474return status;2475}24762477/*2478* set the "ServiceID" attribute of the service.2479*2480* This is the UUID of the service.2481*2482* returns 0 if successful or -1 if there is a failure.2483*/2484void sdp_set_service_id(sdp_record_t *rec, uuid_t uuid)2485{2486switch (uuid.type) {2487case SDP_UUID16:2488sdp_attr_add_new(rec, SDP_ATTR_SERVICE_ID, SDP_UUID16,2489&uuid.value.uuid16);2490break;2491case SDP_UUID32:2492sdp_attr_add_new(rec, SDP_ATTR_SERVICE_ID, SDP_UUID32,2493&uuid.value.uuid32);2494break;2495case SDP_UUID128:2496sdp_attr_add_new(rec, SDP_ATTR_SERVICE_ID, SDP_UUID128,2497&uuid.value.uuid128);2498break;2499}2500sdp_pattern_add_uuid(rec, &uuid);2501}25022503/*2504* set the GroupID attribute of the service record defining a group.2505*2506* This is the UUID of the group.2507*2508* returns 0 if successful or -1 if there is a failure.2509*/2510void sdp_set_group_id(sdp_record_t *rec, uuid_t uuid)2511{2512switch (uuid.type) {2513case SDP_UUID16:2514sdp_attr_add_new(rec, SDP_ATTR_GROUP_ID, SDP_UUID16,2515&uuid.value.uuid16);2516break;2517case SDP_UUID32:2518sdp_attr_add_new(rec, SDP_ATTR_GROUP_ID, SDP_UUID32,2519&uuid.value.uuid32);2520break;2521case SDP_UUID128:2522sdp_attr_add_new(rec, SDP_ATTR_GROUP_ID, SDP_UUID128,2523&uuid.value.uuid128);2524break;2525}2526sdp_pattern_add_uuid(rec, &uuid);2527}25282529/*2530* set the ProfileDescriptorList attribute of the service record2531* pointed to by record to the value specified in "profileDesc".2532*2533* Each element in the list is an object of type2534* sdp_profile_desc_t which is a definition of the2535* Bluetooth profile that this service conforms to.2536*2537* Using a value of NULL for profileDesc has2538* effect of removing this attribute (if previously set)2539*2540* This function replaces the exisiting ProfileDescriptorList2541* structure (if any) with the new one specified.2542*2543* returns 0 if successful or -1 if there is a failure.2544*/2545int sdp_set_profile_descs(sdp_record_t *rec, const sdp_list_t *profiles)2546{2547int status = 0;2548uint8_t uuid16 = SDP_UUID16;2549uint8_t uuid32 = SDP_UUID32;2550uint8_t uuid128 = SDP_UUID128;2551uint8_t uint16 = SDP_UINT16;2552int i = 0, seqlen = sdp_list_len(profiles);2553void **seqDTDs, **seqs;2554const sdp_list_t *p;2555sdp_data_t *pAPSeq;25562557seqDTDs = malloc(seqlen * sizeof(void *));2558if (!seqDTDs)2559return -1;25602561seqs = malloc(seqlen * sizeof(void *));2562if (!seqs) {2563free(seqDTDs);2564return -1;2565}25662567for (p = profiles; p; p = p->next) {2568sdp_data_t *seq;2569void *dtds[2], *values[2];2570sdp_profile_desc_t *profile = p->data;2571if (!profile) {2572status = -1;2573goto end;2574}2575switch (profile->uuid.type) {2576case SDP_UUID16:2577dtds[0] = &uuid16;2578values[0] = &profile->uuid.value.uuid16;2579break;2580case SDP_UUID32:2581dtds[0] = &uuid32;2582values[0] = &profile->uuid.value.uuid32;2583break;2584case SDP_UUID128:2585dtds[0] = &uuid128;2586values[0] = &profile->uuid.value.uuid128;2587break;2588default:2589status = -1;2590goto end;2591}2592dtds[1] = &uint16;2593values[1] = &profile->version;2594seq = sdp_seq_alloc(dtds, values, 2);25952596if (seq == NULL) {2597status = -1;2598goto end;2599}26002601seqDTDs[i] = &seq->dtd;2602seqs[i] = seq;2603sdp_pattern_add_uuid(rec, &profile->uuid);2604i++;2605}26062607pAPSeq = sdp_seq_alloc(seqDTDs, seqs, seqlen);2608sdp_attr_add(rec, SDP_ATTR_PFILE_DESC_LIST, pAPSeq);2609end:2610free(seqDTDs);2611free(seqs);2612return status;2613}26142615/*2616* sets various URL attributes of the service2617* pointed to by record. The URL include2618*2619* client: a URL to the client's2620* platform specific (WinCE, PalmOS) executable2621* code that can be used to access this service.2622*2623* doc: a URL pointing to service documentation2624*2625* icon: a URL to an icon that can be used to represent2626* this service.2627*2628* Note that you need to pass NULL for any URLs2629* that you don't want to set or remove2630*/2631void sdp_set_url_attr(sdp_record_t *rec, const char *client, const char *doc,2632const char *icon)2633{2634sdp_attr_add_new(rec, SDP_ATTR_CLNT_EXEC_URL, SDP_URL_STR8, client);2635sdp_attr_add_new(rec, SDP_ATTR_DOC_URL, SDP_URL_STR8, doc);2636sdp_attr_add_new(rec, SDP_ATTR_ICON_URL, SDP_URL_STR8, icon);2637}26382639uuid_t *sdp_uuid16_create(uuid_t *u, uint16_t val)2640{2641memset(u, 0, sizeof(uuid_t));2642u->type = SDP_UUID16;2643u->value.uuid16 = val;2644return u;2645}26462647uuid_t *sdp_uuid32_create(uuid_t *u, uint32_t val)2648{2649memset(u, 0, sizeof(uuid_t));2650u->type = SDP_UUID32;2651u->value.uuid32 = val;2652return u;2653}26542655uuid_t *sdp_uuid128_create(uuid_t *u, const void *val)2656{2657memset(u, 0, sizeof(uuid_t));2658u->type = SDP_UUID128;2659memcpy(&u->value.uuid128, val, sizeof(uint128_t));2660return u;2661}26622663/*2664* UUID comparison function2665* returns 0 if uuidValue1 == uuidValue2 else -12666*/2667int sdp_uuid_cmp(const void *p1, const void *p2)2668{2669uuid_t *u1 = sdp_uuid_to_uuid128(p1);2670uuid_t *u2 = sdp_uuid_to_uuid128(p2);2671int ret;26722673ret = sdp_uuid128_cmp(u1, u2);26742675bt_free(u1);2676bt_free(u2);26772678return ret;2679}26802681/*2682* UUID comparison function2683* returns 0 if uuidValue1 == uuidValue2 else -12684*/2685int sdp_uuid16_cmp(const void *p1, const void *p2)2686{2687const uuid_t *u1 = p1;2688const uuid_t *u2 = p2;2689return memcmp(&u1->value.uuid16, &u2->value.uuid16, sizeof(uint16_t));2690}26912692/*2693* UUID comparison function2694* returns 0 if uuidValue1 == uuidValue2 else -12695*/2696int sdp_uuid128_cmp(const void *p1, const void *p2)2697{2698const uuid_t *u1 = p1;2699const uuid_t *u2 = p2;2700return memcmp(&u1->value.uuid128, &u2->value.uuid128, sizeof(uint128_t));2701}27022703/*2704* 128 to 16 bit and 32 to 16 bit UUID conversion functions2705* yet to be implemented. Note that the input is in NBO in2706* both 32 and 128 bit UUIDs and conversion is needed2707*/2708void sdp_uuid16_to_uuid128(uuid_t *uuid128, const uuid_t *uuid16)2709{2710/*2711* We have a 16 bit value, which needs to be added to2712* bytes 3 and 4 (at indices 2 and 3) of the Bluetooth base2713*/2714unsigned short data1;27152716/* allocate a 128bit UUID and init to the Bluetooth base UUID */2717uuid128->value.uuid128 = bluetooth_base_uuid;2718uuid128->type = SDP_UUID128;27192720/* extract bytes 2 and 3 of 128bit BT base UUID */2721memcpy(&data1, &bluetooth_base_uuid.data[2], 2);27222723/* add the given UUID (16 bits) */2724data1 += htons(uuid16->value.uuid16);27252726/* set bytes 2 and 3 of the 128 bit value */2727memcpy(&uuid128->value.uuid128.data[2], &data1, 2);2728}27292730void sdp_uuid32_to_uuid128(uuid_t *uuid128, const uuid_t *uuid32)2731{2732/*2733* We have a 32 bit value, which needs to be added to2734* bytes 1->4 (at indices 0 thru 3) of the Bluetooth base2735*/2736unsigned int data0;27372738/* allocate a 128bit UUID and init to the Bluetooth base UUID */2739uuid128->value.uuid128 = bluetooth_base_uuid;2740uuid128->type = SDP_UUID128;27412742/* extract first 4 bytes */2743memcpy(&data0, &bluetooth_base_uuid.data[0], 4);27442745/* add the given UUID (32bits) */2746data0 += htonl(uuid32->value.uuid32);27472748/* set the 4 bytes of the 128 bit value */2749memcpy(&uuid128->value.uuid128.data[0], &data0, 4);2750}27512752uuid_t *sdp_uuid_to_uuid128(const uuid_t *uuid)2753{2754uuid_t *uuid128 = bt_malloc(sizeof(uuid_t));27552756if (!uuid128)2757return NULL;27582759memset(uuid128, 0, sizeof(uuid_t));2760switch (uuid->type) {2761case SDP_UUID128:2762*uuid128 = *uuid;2763break;2764case SDP_UUID32:2765sdp_uuid32_to_uuid128(uuid128, uuid);2766break;2767case SDP_UUID16:2768sdp_uuid16_to_uuid128(uuid128, uuid);2769break;2770}2771return uuid128;2772}27732774/*2775* converts a 128-bit uuid to a 16/32-bit one if possible2776* returns true if uuid contains a 16/32-bit UUID at exit2777*/2778int sdp_uuid128_to_uuid(uuid_t *uuid)2779{2780uint128_t *b = &bluetooth_base_uuid;2781uint128_t *u = &uuid->value.uuid128;2782uint32_t data;2783unsigned int i;27842785if (uuid->type != SDP_UUID128)2786return 1;27872788for (i = 4; i < sizeof(b->data); i++)2789if (b->data[i] != u->data[i])2790return 0;27912792memcpy(&data, u->data, 4);2793data = htonl(data);2794if (data <= 0xffff) {2795uuid->type = SDP_UUID16;2796uuid->value.uuid16 = (uint16_t) data;2797} else {2798uuid->type = SDP_UUID32;2799uuid->value.uuid32 = data;2800}2801return 1;2802}28032804/*2805* convert a UUID to the 16-bit short-form2806*/2807int sdp_uuid_to_proto(uuid_t *uuid)2808{2809uuid_t u = *uuid;2810if (sdp_uuid128_to_uuid(&u)) {2811switch (u.type) {2812case SDP_UUID16:2813return u.value.uuid16;2814case SDP_UUID32:2815return u.value.uuid32;2816}2817}2818return 0;2819}28202821/*2822* This function appends data to the PDU buffer "dst" from source "src".2823* The data length is also computed and set.2824* Should the PDU length exceed 2^8, then sequence type is2825* set accordingly and the data is memmove()'d.2826*/2827void sdp_append_to_buf(sdp_buf_t *dst, uint8_t *data, uint32_t len)2828{2829uint8_t *p = dst->data;2830uint8_t dtd = *p;28312832SDPDBG("Append src size: %d", len);2833SDPDBG("Append dst size: %d", dst->data_size);2834SDPDBG("Dst buffer size: %d", dst->buf_size);2835if (dst->data_size == 0 && dtd == 0) {2836/* create initial sequence */2837*p = SDP_SEQ8;2838dst->data_size += sizeof(uint8_t);2839/* reserve space for sequence size */2840dst->data_size += sizeof(uint8_t);2841}28422843memcpy(dst->data + dst->data_size, data, len);2844dst->data_size += len;28452846dtd = *(uint8_t *) dst->data;2847if (dst->data_size > UCHAR_MAX && dtd == SDP_SEQ8) {2848short offset = sizeof(uint8_t) + sizeof(uint8_t);2849memmove(dst->data + offset + 1, dst->data + offset,2850dst->data_size - offset);2851*p = SDP_SEQ16;2852dst->data_size += 1;2853}2854dtd = *(uint8_t *) p;2855p += sizeof(uint8_t);2856switch (dtd) {2857case SDP_SEQ8:2858*(uint8_t *) p = dst->data_size - sizeof(uint8_t) - sizeof(uint8_t);2859break;2860case SDP_SEQ16:2861bt_put_be16(dst->data_size - sizeof(uint8_t) - sizeof(uint16_t), p);2862break;2863case SDP_SEQ32:2864bt_put_be32(dst->data_size - sizeof(uint8_t) - sizeof(uint32_t), p);2865break;2866}2867}28682869void sdp_append_to_pdu(sdp_buf_t *pdu, sdp_data_t *d)2870{2871sdp_buf_t append;28722873memset(&append, 0, sizeof(sdp_buf_t));2874sdp_gen_buffer(&append, d);2875append.data = malloc(append.buf_size);2876if (!append.data)2877return;28782879sdp_set_attrid(&append, d->attrId);2880sdp_gen_pdu(&append, d);2881sdp_append_to_buf(pdu, append.data, append.data_size);2882free(append.data);2883}28842885/*2886* Registers an sdp record.2887*2888* It is incorrect to call this method on a record that2889* has been already registered with the server.2890*2891* Returns zero on success, otherwise -1 (and sets errno).2892*/2893int sdp_device_record_register_binary(sdp_session_t *session, bdaddr_t *device, uint8_t *data, uint32_t size, uint8_t flags, uint32_t *handle)2894{2895uint8_t *req, *rsp, *p;2896uint32_t reqsize, rspsize;2897sdp_pdu_hdr_t *reqhdr, *rsphdr;2898int status;28992900SDPDBG("");29012902if (!session->local) {2903errno = EREMOTE;2904return -1;2905}2906req = malloc(SDP_REQ_BUFFER_SIZE);2907rsp = malloc(SDP_RSP_BUFFER_SIZE);2908if (req == NULL || rsp == NULL) {2909status = -1;2910errno = ENOMEM;2911goto end;2912}29132914reqhdr = (sdp_pdu_hdr_t *)req;2915reqhdr->pdu_id = SDP_SVC_REGISTER_REQ;2916reqhdr->tid = htons(sdp_gen_tid(session));2917reqsize = sizeof(sdp_pdu_hdr_t) + 1;2918p = req + sizeof(sdp_pdu_hdr_t);29192920if (bacmp(device, BDADDR_ANY)) {2921*p++ = flags | SDP_DEVICE_RECORD;2922bacpy((bdaddr_t *) p, device);2923p += sizeof(bdaddr_t);2924reqsize += sizeof(bdaddr_t);2925} else2926*p++ = flags;29272928memcpy(p, data, size);2929reqsize += size;2930reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));29312932status = sdp_send_req_w4_rsp(session, req, rsp, reqsize, &rspsize);2933if (status < 0)2934goto end;29352936if (rspsize < sizeof(sdp_pdu_hdr_t)) {2937SDPERR("Unexpected end of packet");2938errno = EPROTO;2939status = -1;2940goto end;2941}29422943rsphdr = (sdp_pdu_hdr_t *) rsp;2944p = rsp + sizeof(sdp_pdu_hdr_t);29452946if (rsphdr->pdu_id == SDP_ERROR_RSP) {2947/* Invalid service record */2948errno = EINVAL;2949status = -1;2950} else if (rsphdr->pdu_id != SDP_SVC_REGISTER_RSP) {2951errno = EPROTO;2952status = -1;2953} else {2954if (rspsize < sizeof(sdp_pdu_hdr_t) + sizeof(uint32_t)) {2955SDPERR("Unexpected end of packet");2956errno = EPROTO;2957status = -1;2958goto end;2959}2960if (handle)2961*handle = bt_get_be32(p);2962}29632964end:2965free(req);2966free(rsp);29672968return status;2969}29702971int sdp_device_record_register(sdp_session_t *session, bdaddr_t *device, sdp_record_t *rec, uint8_t flags)2972{2973sdp_buf_t pdu;2974uint32_t handle;2975int err;29762977SDPDBG("");29782979if (rec->handle && rec->handle != 0xffffffff) {2980uint32_t handle = rec->handle;2981sdp_data_t *data = sdp_data_alloc(SDP_UINT32, &handle);2982sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, data);2983}29842985if (sdp_gen_record_pdu(rec, &pdu) < 0) {2986errno = ENOMEM;2987return -1;2988}29892990err = sdp_device_record_register_binary(session, device,2991pdu.data, pdu.data_size, flags, &handle);29922993free(pdu.data);29942995if (err == 0) {2996sdp_data_t *data = sdp_data_alloc(SDP_UINT32, &handle);2997rec->handle = handle;2998sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, data);2999}30003001return err;3002}30033004int sdp_record_register(sdp_session_t *session, sdp_record_t *rec, uint8_t flags)3005{3006return sdp_device_record_register(session, BDADDR_ANY, rec, flags);3007}30083009/*3010* unregister a service record3011*/3012int sdp_device_record_unregister_binary(sdp_session_t *session, bdaddr_t *device, uint32_t handle)3013{3014uint8_t *reqbuf, *rspbuf, *p;3015uint32_t reqsize = 0, rspsize = 0;3016sdp_pdu_hdr_t *reqhdr, *rsphdr;3017int status;30183019SDPDBG("");30203021if (handle == SDP_SERVER_RECORD_HANDLE) {3022errno = EINVAL;3023return -1;3024}30253026if (!session->local) {3027errno = EREMOTE;3028return -1;3029}30303031reqbuf = malloc(SDP_REQ_BUFFER_SIZE);3032rspbuf = malloc(SDP_RSP_BUFFER_SIZE);3033if (!reqbuf || !rspbuf) {3034errno = ENOMEM;3035status = -1;3036goto end;3037}3038reqhdr = (sdp_pdu_hdr_t *) reqbuf;3039reqhdr->pdu_id = SDP_SVC_REMOVE_REQ;3040reqhdr->tid = htons(sdp_gen_tid(session));30413042p = reqbuf + sizeof(sdp_pdu_hdr_t);3043reqsize = sizeof(sdp_pdu_hdr_t);3044bt_put_be32(handle, p);3045reqsize += sizeof(uint32_t);30463047reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));3048status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize);3049if (status < 0)3050goto end;30513052if (rspsize < sizeof(sdp_pdu_hdr_t) + sizeof(uint16_t)) {3053SDPERR("Unexpected end of packet");3054errno = EPROTO;3055status = -1;3056goto end;3057}30583059rsphdr = (sdp_pdu_hdr_t *) rspbuf;3060p = rspbuf + sizeof(sdp_pdu_hdr_t);30613062if (rsphdr->pdu_id == SDP_ERROR_RSP) {3063/* For this case the status always is invalid record handle */3064errno = EINVAL;3065status = -1;3066} else if (rsphdr->pdu_id != SDP_SVC_REMOVE_RSP) {3067errno = EPROTO;3068status = -1;3069} else {3070uint16_t tmp;30713072memcpy(&tmp, p, sizeof(tmp));30733074status = tmp;3075}3076end:3077free(reqbuf);3078free(rspbuf);30793080return status;3081}30823083int sdp_device_record_unregister(sdp_session_t *session, bdaddr_t *device, sdp_record_t *rec)3084{3085int err;30863087err = sdp_device_record_unregister_binary(session, device, rec->handle);3088if (err == 0)3089sdp_record_free(rec);30903091return err;3092}30933094int sdp_record_unregister(sdp_session_t *session, sdp_record_t *rec)3095{3096return sdp_device_record_unregister(session, BDADDR_ANY, rec);3097}30983099/*3100* modify an existing service record3101*/3102int sdp_device_record_update_binary(sdp_session_t *session, bdaddr_t *device, uint32_t handle, uint8_t *data, uint32_t size)3103{3104return -1;3105}31063107int sdp_device_record_update(sdp_session_t *session, bdaddr_t *device, const sdp_record_t *rec)3108{3109uint8_t *reqbuf, *rspbuf, *p;3110uint32_t reqsize, rspsize;3111sdp_pdu_hdr_t *reqhdr, *rsphdr;3112uint32_t handle;3113sdp_buf_t pdu;3114int status;31153116SDPDBG("");31173118handle = rec->handle;31193120if (handle == SDP_SERVER_RECORD_HANDLE) {3121errno = EINVAL;3122return -1;3123}3124if (!session->local) {3125errno = EREMOTE;3126return -1;3127}3128reqbuf = malloc(SDP_REQ_BUFFER_SIZE);3129rspbuf = malloc(SDP_RSP_BUFFER_SIZE);3130if (!reqbuf || !rspbuf) {3131errno = ENOMEM;3132status = -1;3133goto end;3134}3135reqhdr = (sdp_pdu_hdr_t *) reqbuf;3136reqhdr->pdu_id = SDP_SVC_UPDATE_REQ;3137reqhdr->tid = htons(sdp_gen_tid(session));31383139p = reqbuf + sizeof(sdp_pdu_hdr_t);3140reqsize = sizeof(sdp_pdu_hdr_t);31413142bt_put_be32(handle, p);3143reqsize += sizeof(uint32_t);3144p += sizeof(uint32_t);31453146if (sdp_gen_record_pdu(rec, &pdu) < 0) {3147errno = ENOMEM;3148status = -1;3149goto end;3150}3151memcpy(p, pdu.data, pdu.data_size);3152reqsize += pdu.data_size;3153free(pdu.data);31543155reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));3156status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize);3157if (status < 0)3158goto end;31593160if (rspsize < sizeof(sdp_pdu_hdr_t) + sizeof(uint16_t)) {3161SDPERR("Unexpected end of packet");3162errno = EPROTO;3163status = -1;3164goto end;3165}31663167SDPDBG("Send req status : %d", status);31683169rsphdr = (sdp_pdu_hdr_t *) rspbuf;3170p = rspbuf + sizeof(sdp_pdu_hdr_t);31713172if (rsphdr->pdu_id == SDP_ERROR_RSP) {3173/* The status can be invalid sintax or invalid record handle */3174errno = EINVAL;3175status = -1;3176} else if (rsphdr->pdu_id != SDP_SVC_UPDATE_RSP) {3177errno = EPROTO;3178status = -1;3179} else {3180uint16_t tmp;31813182memcpy(&tmp, p, sizeof(tmp));31833184status = tmp;3185}3186end:3187free(reqbuf);3188free(rspbuf);3189return status;3190}31913192int sdp_record_update(sdp_session_t *session, const sdp_record_t *rec)3193{3194return sdp_device_record_update(session, BDADDR_ANY, rec);3195}31963197sdp_record_t *sdp_record_alloc(void)3198{3199sdp_record_t *rec = malloc(sizeof(sdp_record_t));32003201if (!rec)3202return NULL;32033204memset(rec, 0, sizeof(sdp_record_t));3205rec->handle = 0xffffffff;3206return rec;3207}32083209/*3210* Free the contents of a service record3211*/3212void sdp_record_free(sdp_record_t *rec)3213{3214sdp_list_free(rec->attrlist, (sdp_free_func_t) sdp_data_free);3215sdp_list_free(rec->pattern, free);3216free(rec);3217}32183219void sdp_pattern_add_uuid(sdp_record_t *rec, uuid_t *uuid)3220{3221uuid_t *uuid128 = sdp_uuid_to_uuid128(uuid);32223223SDPDBG("Elements in target pattern : %d", sdp_list_len(rec->pattern));3224SDPDBG("Trying to add : 0x%lx", (unsigned long) uuid128);32253226if (sdp_list_find(rec->pattern, uuid128, sdp_uuid128_cmp) == NULL)3227rec->pattern = sdp_list_insert_sorted(rec->pattern, uuid128, sdp_uuid128_cmp);3228else3229bt_free(uuid128);32303231SDPDBG("Elements in target pattern : %d", sdp_list_len(rec->pattern));3232}32333234void sdp_pattern_add_uuidseq(sdp_record_t *rec, sdp_list_t *seq)3235{3236for (; seq; seq = seq->next) {3237uuid_t *uuid = (uuid_t *)seq->data;3238sdp_pattern_add_uuid(rec, uuid);3239}3240}32413242/*3243* Extract a sequence of service record handles from a PDU buffer3244* and add the entries to a sdp_list_t. Note that the service record3245* handles are not in "data element sequence" form, but just like3246* an array of service handles3247*/3248static void extract_record_handle_seq(uint8_t *pdu, int bufsize, sdp_list_t **seq, int count, unsigned int *scanned)3249{3250sdp_list_t *pSeq = *seq;3251uint8_t *pdata = pdu;3252int n;32533254for (n = 0; n < count; n++) {3255uint32_t *pSvcRec;3256if (bufsize < (int) sizeof(uint32_t)) {3257SDPERR("Unexpected end of packet");3258break;3259}3260pSvcRec = malloc(sizeof(uint32_t));3261if (!pSvcRec)3262break;3263*pSvcRec = bt_get_be32(pdata);3264pSeq = sdp_list_append(pSeq, pSvcRec);3265pdata += sizeof(uint32_t);3266*scanned += sizeof(uint32_t);3267bufsize -= sizeof(uint32_t);3268}3269*seq = pSeq;3270}3271/*3272* Generate the attribute sequence pdu form3273* from sdp_list_t elements. Return length of attr seq3274*/3275static int gen_dataseq_pdu(uint8_t *dst, const sdp_list_t *seq, uint8_t dtd)3276{3277sdp_data_t *dataseq;3278void **types, **values;3279sdp_buf_t buf;3280int i, seqlen = sdp_list_len(seq);32813282/* Fill up the value and the dtd arrays */3283SDPDBG("");32843285SDPDBG("Seq length : %d", seqlen);32863287types = malloc(seqlen * sizeof(void *));3288if (!types)3289return -ENOMEM;32903291values = malloc(seqlen * sizeof(void *));3292if (!values) {3293free(types);3294return -ENOMEM;3295}32963297for (i = 0; i < seqlen; i++) {3298void *data = seq->data;3299types[i] = &dtd;3300if (SDP_IS_UUID(dtd))3301data = &((uuid_t *)data)->value;3302values[i] = data;3303seq = seq->next;3304}33053306dataseq = sdp_seq_alloc(types, values, seqlen);3307if (!dataseq) {3308free(types);3309free(values);3310return -ENOMEM;3311}33123313memset(&buf, 0, sizeof(sdp_buf_t));3314sdp_gen_buffer(&buf, dataseq);3315buf.data = malloc(buf.buf_size);33163317if (!buf.data) {3318sdp_data_free(dataseq);3319free(types);3320free(values);3321return -ENOMEM;3322}33233324SDPDBG("Data Seq : 0x%p", seq);3325seqlen = sdp_gen_pdu(&buf, dataseq);3326SDPDBG("Copying : %d", buf.data_size);3327memcpy(dst, buf.data, buf.data_size);33283329sdp_data_free(dataseq);33303331free(types);3332free(values);3333free(buf.data);3334return seqlen;3335}33363337static int gen_searchseq_pdu(uint8_t *dst, const sdp_list_t *seq)3338{3339uuid_t *uuid = seq->data;3340return gen_dataseq_pdu(dst, seq, uuid->type);3341}33423343static int gen_attridseq_pdu(uint8_t *dst, const sdp_list_t *seq, uint8_t dataType)3344{3345return gen_dataseq_pdu(dst, seq, dataType);3346}33473348typedef struct {3349uint8_t length;3350unsigned char data[16];3351} __attribute__ ((packed)) sdp_cstate_t;33523353static int copy_cstate(uint8_t *pdata, int pdata_len, const sdp_cstate_t *cstate)3354{3355if (cstate) {3356uint8_t len = cstate->length;3357if (len >= pdata_len) {3358SDPERR("Continuation state size exceeds internal buffer");3359len = pdata_len - 1;3360}3361*pdata++ = len;3362memcpy(pdata, cstate->data, len);3363return len + 1;3364}3365*pdata = 0;3366return 1;3367}33683369/*3370* This is a service search request.3371*3372* INPUT :3373*3374* sdp_list_t *search3375* Singly linked list containing elements of the search3376* pattern. Each entry in the list is a UUID (DataTypeSDP_UUID16)3377* of the service to be searched3378*3379* uint16_t max_rec_num3380* A 16 bit integer which tells the service, the maximum3381* entries that the client can handle in the response. The3382* server is obliged not to return > max_rec_num entries3383*3384* OUTPUT :3385*3386* int return value3387* 0:3388* The request completed successfully. This does not3389* mean the requested services were found3390* -1:3391* On any failure and sets errno3392*3393* sdp_list_t **rsp_list3394* This variable is set on a successful return if there are3395* non-zero service handles. It is a singly linked list of3396* service record handles (uint16_t)3397*/3398int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search,3399uint16_t max_rec_num, sdp_list_t **rsp)3400{3401int status = 0;3402uint32_t reqsize = 0, _reqsize;3403uint32_t rspsize = 0, rsplen;3404int seqlen = 0;3405int rec_count;3406unsigned scanned, pdata_len;3407uint8_t *pdata, *_pdata;3408uint8_t *reqbuf, *rspbuf;3409sdp_pdu_hdr_t *reqhdr, *rsphdr;3410sdp_cstate_t *cstate = NULL;34113412reqbuf = malloc(SDP_REQ_BUFFER_SIZE);3413rspbuf = malloc(SDP_RSP_BUFFER_SIZE);3414if (!reqbuf || !rspbuf) {3415errno = ENOMEM;3416status = -1;3417goto end;3418}3419reqhdr = (sdp_pdu_hdr_t *) reqbuf;3420reqhdr->pdu_id = SDP_SVC_SEARCH_REQ;3421pdata = reqbuf + sizeof(sdp_pdu_hdr_t);3422reqsize = sizeof(sdp_pdu_hdr_t);34233424/* add service class IDs for search */3425seqlen = gen_searchseq_pdu(pdata, search);34263427SDPDBG("Data seq added : %d", seqlen);34283429/* set the length and increment the pointer */3430reqsize += seqlen;3431pdata += seqlen;34323433/* specify the maximum svc rec count that client expects */3434bt_put_be16(max_rec_num, pdata);3435reqsize += sizeof(uint16_t);3436pdata += sizeof(uint16_t);34373438_reqsize = reqsize;3439_pdata = pdata;3440*rsp = NULL;34413442do {3443/* Add continuation state or NULL (first time) */3444reqsize = _reqsize + copy_cstate(_pdata,3445SDP_REQ_BUFFER_SIZE - _reqsize, cstate);34463447/* Set the request header's param length */3448reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));34493450reqhdr->tid = htons(sdp_gen_tid(session));3451/*3452* Send the request, wait for response and if3453* no error, set the appropriate values and return3454*/3455status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize);3456if (status < 0)3457goto end;34583459if (rspsize < sizeof(sdp_pdu_hdr_t)) {3460SDPERR("Unexpected end of packet");3461status = -1;3462goto end;3463}34643465rsphdr = (sdp_pdu_hdr_t *) rspbuf;3466rsplen = ntohs(rsphdr->plen);34673468if (rsphdr->pdu_id == SDP_ERROR_RSP) {3469SDPDBG("Status : 0x%x", rsphdr->pdu_id);3470status = -1;3471goto end;3472}3473scanned = 0;3474pdata = rspbuf + sizeof(sdp_pdu_hdr_t);3475pdata_len = rspsize - sizeof(sdp_pdu_hdr_t);34763477if (pdata_len < sizeof(uint16_t) + sizeof(uint16_t)) {3478SDPERR("Unexpected end of packet");3479status = -1;3480goto end;3481}34823483/* net service record match count */3484pdata += sizeof(uint16_t);3485scanned += sizeof(uint16_t);3486pdata_len -= sizeof(uint16_t);3487rec_count = bt_get_be16(pdata);3488pdata += sizeof(uint16_t);3489scanned += sizeof(uint16_t);3490pdata_len -= sizeof(uint16_t);34913492SDPDBG("Current svc count: %d", rec_count);3493SDPDBG("ResponseLength: %d", rsplen);34943495if (!rec_count) {3496status = -1;3497goto end;3498}3499extract_record_handle_seq(pdata, pdata_len, rsp, rec_count, &scanned);3500SDPDBG("BytesScanned : %d", scanned);35013502if (rsplen > scanned) {3503uint8_t cstate_len;35043505if (rspsize < sizeof(sdp_pdu_hdr_t) + scanned + sizeof(uint8_t)) {3506SDPERR("Unexpected end of packet: continuation state data missing");3507status = -1;3508goto end;3509}35103511pdata = rspbuf + sizeof(sdp_pdu_hdr_t) + scanned;3512cstate_len = *(uint8_t *) pdata;3513if (cstate_len > 0) {3514cstate = (sdp_cstate_t *)pdata;3515SDPDBG("Cont state length: %d", cstate_len);3516} else3517cstate = NULL;3518}3519} while (cstate);35203521end:3522free(reqbuf);3523free(rspbuf);35243525return status;3526}35273528/*3529* This is a service attribute request.3530*3531* INPUT :3532*3533* uint32_t handle3534* The handle of the service for which the attribute(s) are3535* requested3536*3537* sdp_attrreq_type_t reqtype3538* Attribute identifiers are 16 bit unsigned integers specified3539* in one of 2 ways described below :3540* SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers3541* They are the actual attribute identifiers in ascending order3542*3543* SDP_ATTR_REQ_RANGE - 32bit identifier range3544* The high-order 16bits is the start of range3545* the low-order 16bits are the end of range3546* 0x0000 to 0xFFFF gets all attributes3547*3548* sdp_list_t *attrid3549* Singly linked list containing attribute identifiers desired.3550* Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)3551* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)3552*3553* OUTPUT :3554* return sdp_record_t *3555* 0:3556* On any error and sets errno3557* !0:3558* The service record3559*/3560sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,3561sdp_attrreq_type_t reqtype, const sdp_list_t *attrids)3562{3563uint32_t reqsize = 0, _reqsize;3564uint32_t rspsize = 0, rsp_count;3565int attr_list_len = 0;3566int seqlen = 0;3567unsigned int pdata_len;3568uint8_t *pdata, *_pdata;3569uint8_t *reqbuf, *rspbuf;3570sdp_pdu_hdr_t *reqhdr, *rsphdr;3571sdp_cstate_t *cstate = NULL;3572uint8_t cstate_len = 0;3573sdp_buf_t rsp_concat_buf;3574sdp_record_t *rec = 0;35753576if (reqtype != SDP_ATTR_REQ_INDIVIDUAL && reqtype != SDP_ATTR_REQ_RANGE) {3577errno = EINVAL;3578return NULL;3579}35803581memset(&rsp_concat_buf, 0, sizeof(sdp_buf_t));35823583reqbuf = malloc(SDP_REQ_BUFFER_SIZE);3584rspbuf = malloc(SDP_RSP_BUFFER_SIZE);3585if (!reqbuf || !rspbuf) {3586errno = ENOMEM;3587goto end;3588}3589reqhdr = (sdp_pdu_hdr_t *) reqbuf;3590reqhdr->pdu_id = SDP_SVC_ATTR_REQ;35913592pdata = reqbuf + sizeof(sdp_pdu_hdr_t);3593reqsize = sizeof(sdp_pdu_hdr_t);35943595/* add the service record handle */3596bt_put_be32(handle, pdata);3597reqsize += sizeof(uint32_t);3598pdata += sizeof(uint32_t);35993600/* specify the response limit */3601bt_put_be16(65535, pdata);3602reqsize += sizeof(uint16_t);3603pdata += sizeof(uint16_t);36043605/* get attr seq PDU form */3606seqlen = gen_attridseq_pdu(pdata, attrids,3607reqtype == SDP_ATTR_REQ_INDIVIDUAL? SDP_UINT16 : SDP_UINT32);3608if (seqlen == -1) {3609errno = EINVAL;3610goto end;3611}3612pdata += seqlen;3613reqsize += seqlen;3614SDPDBG("Attr list length : %d", seqlen);36153616/* save before Continuation State */3617_pdata = pdata;3618_reqsize = reqsize;36193620do {3621int status;36223623/* add NULL continuation state */3624reqsize = _reqsize + copy_cstate(_pdata,3625SDP_REQ_BUFFER_SIZE - _reqsize, cstate);36263627/* set the request header's param length */3628reqhdr->tid = htons(sdp_gen_tid(session));3629reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));36303631status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize);3632if (status < 0)3633goto end;36343635if (rspsize < sizeof(sdp_pdu_hdr_t)) {3636SDPERR("Unexpected end of packet");3637goto end;3638}36393640rsphdr = (sdp_pdu_hdr_t *) rspbuf;3641if (rsphdr->pdu_id == SDP_ERROR_RSP) {3642SDPDBG("PDU ID : 0x%x", rsphdr->pdu_id);3643goto end;3644}3645pdata = rspbuf + sizeof(sdp_pdu_hdr_t);3646pdata_len = rspsize - sizeof(sdp_pdu_hdr_t);36473648if (pdata_len < sizeof(uint16_t)) {3649SDPERR("Unexpected end of packet");3650goto end;3651}36523653rsp_count = bt_get_be16(pdata);3654attr_list_len += rsp_count;3655pdata += sizeof(uint16_t);3656pdata_len -= sizeof(uint16_t);36573658/*3659* if continuation state set need to re-issue request before3660* parsing3661*/3662if (pdata_len < rsp_count + sizeof(uint8_t)) {3663SDPERR("Unexpected end of packet: continuation state data missing");3664goto end;3665}3666cstate_len = *(uint8_t *) (pdata + rsp_count);36673668SDPDBG("Response id : %d", rsphdr->pdu_id);3669SDPDBG("Attrlist byte count : %d", rsp_count);3670SDPDBG("sdp_cstate_t length : %d", cstate_len);36713672/*3673* a split response: concatenate intermediate responses3674* and the last one (which has cstate_len == 0)3675*/3676if (cstate_len > 0 || rsp_concat_buf.data_size != 0) {3677uint8_t *targetPtr = NULL;36783679cstate = cstate_len > 0 ? (sdp_cstate_t *) (pdata + rsp_count) : 0;36803681/* build concatenated response buffer */3682rsp_concat_buf.data = realloc(rsp_concat_buf.data, rsp_concat_buf.data_size + rsp_count);3683rsp_concat_buf.buf_size = rsp_concat_buf.data_size + rsp_count;3684targetPtr = rsp_concat_buf.data + rsp_concat_buf.data_size;3685memcpy(targetPtr, pdata, rsp_count);3686rsp_concat_buf.data_size += rsp_count;3687}3688} while (cstate);36893690if (attr_list_len > 0) {3691int scanned = 0;3692if (rsp_concat_buf.data_size != 0) {3693pdata = rsp_concat_buf.data;3694pdata_len = rsp_concat_buf.data_size;3695}3696rec = sdp_extract_pdu(pdata, pdata_len, &scanned);3697}36983699end:3700free(reqbuf);3701free(rsp_concat_buf.data);3702free(rspbuf);3703return rec;3704}37053706/*3707* SDP transaction structure for asynchronous search3708*/3709struct sdp_transaction {3710sdp_callback_t *cb; /* called when the transaction finishes */3711void *udata; /* client user data */3712uint8_t *reqbuf; /* pointer to request PDU */3713sdp_buf_t rsp_concat_buf;3714uint32_t reqsize; /* without cstate */3715int err; /* ZERO if success or the errno if failed */3716};37173718/*3719* Creates a new sdp session for asynchronous search3720* INPUT:3721* int sk3722* non-blocking L2CAP socket3723*3724* RETURN:3725* sdp_session_t *3726* NULL - On memory allocation failure3727*/3728sdp_session_t *sdp_create(int sk, uint32_t flags)3729{3730sdp_session_t *session;3731struct sdp_transaction *t;37323733session = malloc(sizeof(sdp_session_t));3734if (!session) {3735errno = ENOMEM;3736return NULL;3737}3738memset(session, 0, sizeof(*session));37393740session->flags = flags;3741session->sock = sk;37423743t = malloc(sizeof(struct sdp_transaction));3744if (!t) {3745errno = ENOMEM;3746free(session);3747return NULL;3748}3749memset(t, 0, sizeof(*t));37503751session->priv = t;37523753return session;3754}37553756/*3757* Sets the callback function/user data used to notify the application3758* that the asynchronous transaction finished. This function must be3759* called before request an asynchronous search.3760*3761* INPUT:3762* sdp_session_t *session3763* Current sdp session to be handled3764* sdp_callback_t *cb3765* callback to be called when the transaction finishes3766* void *udata3767* user data passed to callback3768* RETURN:3769* 0 - Success3770* -1 - Failure3771*/3772int sdp_set_notify(sdp_session_t *session, sdp_callback_t *func, void *udata)3773{3774struct sdp_transaction *t;37753776if (!session || !session->priv)3777return -1;37783779t = session->priv;3780t->cb = func;3781t->udata = udata;37823783return 0;3784}37853786/*3787* This function starts an asynchronous service search request.3788* The incoming and outgoing data are stored in the transaction structure3789* buffers. When there is incoming data the sdp_process function must be3790* called to get the data and handle the continuation state.3791*3792* INPUT :3793* sdp_session_t *session3794* Current sdp session to be handled3795*3796* sdp_list_t *search3797* Singly linked list containing elements of the search3798* pattern. Each entry in the list is a UUID (DataTypeSDP_UUID16)3799* of the service to be searched3800*3801* uint16_t max_rec_num3802* A 16 bit integer which tells the service, the maximum3803* entries that the client can handle in the response. The3804* server is obliged not to return > max_rec_num entries3805*3806* OUTPUT :3807*3808* int return value3809* 0 - if the request has been sent properly3810* -1 - On any failure and sets errno3811*/38123813int sdp_service_search_async(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num)3814{3815struct sdp_transaction *t;3816sdp_pdu_hdr_t *reqhdr;3817uint8_t *pdata;3818int cstate_len, seqlen = 0;38193820if (!session || !session->priv)3821return -1;38223823t = session->priv;38243825/* clean possible allocated buffer */3826free(t->rsp_concat_buf.data);3827memset(&t->rsp_concat_buf, 0, sizeof(sdp_buf_t));38283829if (!t->reqbuf) {3830t->reqbuf = malloc(SDP_REQ_BUFFER_SIZE);3831if (!t->reqbuf) {3832t->err = ENOMEM;3833goto end;3834}3835}3836memset(t->reqbuf, 0, SDP_REQ_BUFFER_SIZE);38373838reqhdr = (sdp_pdu_hdr_t *) t->reqbuf;3839reqhdr->tid = htons(sdp_gen_tid(session));3840reqhdr->pdu_id = SDP_SVC_SEARCH_REQ;38413842/* generate PDU */3843pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t);3844t->reqsize = sizeof(sdp_pdu_hdr_t);38453846/* add service class IDs for search */3847seqlen = gen_searchseq_pdu(pdata, search);38483849SDPDBG("Data seq added : %d", seqlen);38503851/* now set the length and increment the pointer */3852t->reqsize += seqlen;3853pdata += seqlen;38543855bt_put_be16(max_rec_num, pdata);3856t->reqsize += sizeof(uint16_t);3857pdata += sizeof(uint16_t);38583859/* set the request header's param length */3860cstate_len = copy_cstate(pdata, SDP_REQ_BUFFER_SIZE - t->reqsize, NULL);3861reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));38623863if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) {3864SDPERR("Error sendind data:%m");3865t->err = errno;3866goto end;3867}38683869return 0;3870end:38713872free(t->reqbuf);3873t->reqbuf = NULL;38743875return -1;3876}38773878/*3879* This function starts an asynchronous service attribute request.3880* The incoming and outgoing data are stored in the transaction structure3881* buffers. When there is incoming data the sdp_process function must be3882* called to get the data and handle the continuation state.3883*3884* INPUT :3885* sdp_session_t *session3886* Current sdp session to be handled3887*3888* uint32_t handle3889* The handle of the service for which the attribute(s) are3890* requested3891*3892* sdp_attrreq_type_t reqtype3893* Attribute identifiers are 16 bit unsigned integers specified3894* in one of 2 ways described below :3895* SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers3896* They are the actual attribute identifiers in ascending order3897*3898* SDP_ATTR_REQ_RANGE - 32bit identifier range3899* The high-order 16bits is the start of range3900* the low-order 16bits are the end of range3901* 0x0000 to 0xFFFF gets all attributes3902*3903* sdp_list_t *attrid_list3904* Singly linked list containing attribute identifiers desired.3905* Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)3906* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)3907*3908* OUTPUT :3909* int return value3910* 0 - if the request has been sent properly3911* -1 - On any failure and sets errno3912*/39133914int sdp_service_attr_async(sdp_session_t *session, uint32_t handle, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list)3915{3916struct sdp_transaction *t;3917sdp_pdu_hdr_t *reqhdr;3918uint8_t *pdata;3919int cstate_len, seqlen = 0;39203921if (!session || !session->priv)3922return -1;39233924t = session->priv;39253926/* clean possible allocated buffer */3927free(t->rsp_concat_buf.data);3928memset(&t->rsp_concat_buf, 0, sizeof(sdp_buf_t));39293930if (!t->reqbuf) {3931t->reqbuf = malloc(SDP_REQ_BUFFER_SIZE);3932if (!t->reqbuf) {3933t->err = ENOMEM;3934goto end;3935}3936}3937memset(t->reqbuf, 0, SDP_REQ_BUFFER_SIZE);39383939reqhdr = (sdp_pdu_hdr_t *) t->reqbuf;3940reqhdr->tid = htons(sdp_gen_tid(session));3941reqhdr->pdu_id = SDP_SVC_ATTR_REQ;39423943/* generate PDU */3944pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t);3945t->reqsize = sizeof(sdp_pdu_hdr_t);39463947/* add the service record handle */3948bt_put_be32(handle, pdata);3949t->reqsize += sizeof(uint32_t);3950pdata += sizeof(uint32_t);39513952/* specify the response limit */3953bt_put_be16(65535, pdata);3954t->reqsize += sizeof(uint16_t);3955pdata += sizeof(uint16_t);39563957/* get attr seq PDU form */3958seqlen = gen_attridseq_pdu(pdata, attrid_list,3959reqtype == SDP_ATTR_REQ_INDIVIDUAL? SDP_UINT16 : SDP_UINT32);3960if (seqlen == -1) {3961t->err = EINVAL;3962goto end;3963}39643965/* now set the length and increment the pointer */3966t->reqsize += seqlen;3967pdata += seqlen;3968SDPDBG("Attr list length : %d", seqlen);39693970/* set the request header's param length */3971cstate_len = copy_cstate(pdata, SDP_REQ_BUFFER_SIZE - t->reqsize, NULL);3972reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));39733974if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) {3975SDPERR("Error sendind data:%m");3976t->err = errno;3977goto end;3978}39793980return 0;3981end:39823983free(t->reqbuf);3984t->reqbuf = NULL;39853986return -1;3987}39883989/*3990* This function starts an asynchronous service search attributes.3991* It is a service search request combined with attribute request. The incoming3992* and outgoing data are stored in the transaction structure buffers. When there3993* is incoming data the sdp_process function must be called to get the data3994* and handle the continuation state.3995*3996* INPUT:3997* sdp_session_t *session3998* Current sdp session to be handled3999*4000* sdp_list_t *search4001* Singly linked list containing elements of the search4002* pattern. Each entry in the list is a UUID(DataTypeSDP_UUID16)4003* of the service to be searched4004*4005* AttributeSpecification attrSpec4006* Attribute identifiers are 16 bit unsigned integers specified4007* in one of 2 ways described below :4008* SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers4009* They are the actual attribute identifiers in ascending order4010*4011* SDP_ATTR_REQ_RANGE - 32bit identifier range4012* The high-order 16bits is the start of range4013* the low-order 16bits are the end of range4014* 0x0000 to 0xFFFF gets all attributes4015*4016* sdp_list_t *attrid_list4017* Singly linked list containing attribute identifiers desired.4018* Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)4019* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)4020*40214022* RETURN:4023* 0 - if the request has been sent properly4024* -1 - On any failure4025*/4026int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list)4027{4028struct sdp_transaction *t;4029sdp_pdu_hdr_t *reqhdr;4030uint8_t *pdata;4031int cstate_len, seqlen = 0;40324033if (!session || !session->priv)4034return -1;40354036t = session->priv;40374038/* clean possible allocated buffer */4039free(t->rsp_concat_buf.data);4040memset(&t->rsp_concat_buf, 0, sizeof(sdp_buf_t));40414042if (!t->reqbuf) {4043t->reqbuf = malloc(SDP_REQ_BUFFER_SIZE);4044if (!t->reqbuf) {4045t->err = ENOMEM;4046goto end;4047}4048}4049memset(t->reqbuf, 0, SDP_REQ_BUFFER_SIZE);40504051reqhdr = (sdp_pdu_hdr_t *) t->reqbuf;4052reqhdr->tid = htons(sdp_gen_tid(session));4053reqhdr->pdu_id = SDP_SVC_SEARCH_ATTR_REQ;40544055/* generate PDU */4056pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t);4057t->reqsize = sizeof(sdp_pdu_hdr_t);40584059/* add service class IDs for search */4060seqlen = gen_searchseq_pdu(pdata, search);40614062SDPDBG("Data seq added : %d", seqlen);40634064/* now set the length and increment the pointer */4065t->reqsize += seqlen;4066pdata += seqlen;40674068bt_put_be16(SDP_MAX_ATTR_LEN, pdata);4069t->reqsize += sizeof(uint16_t);4070pdata += sizeof(uint16_t);40714072SDPDBG("Max attr byte count : %d", SDP_MAX_ATTR_LEN);40734074/* get attr seq PDU form */4075seqlen = gen_attridseq_pdu(pdata, attrid_list,4076reqtype == SDP_ATTR_REQ_INDIVIDUAL ? SDP_UINT16 : SDP_UINT32);4077if (seqlen == -1) {4078t->err = EINVAL;4079goto end;4080}40814082pdata += seqlen;4083SDPDBG("Attr list length : %d", seqlen);4084t->reqsize += seqlen;40854086/* set the request header's param length */4087cstate_len = copy_cstate(pdata, SDP_REQ_BUFFER_SIZE - t->reqsize, NULL);4088reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));40894090if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) {4091SDPERR("Error sendind data:%m");4092t->err = errno;4093goto end;4094}40954096return 0;4097end:40984099free(t->reqbuf);4100t->reqbuf = NULL;41014102return -1;4103}41044105/*4106* Function used to get the error reason after sdp_callback_t function has been called4107* and the status is 0xffff or if sdp_service_{search, attr, search_attr}_async returns -1.4108* It indicates that an error NOT related to SDP_ErrorResponse happened. Get errno directly4109* is not safe because multiple transactions can be triggered.4110* This function must be used with asynchronous sdp functions only.4111*4112* INPUT:4113* sdp_session_t *session4114* Current sdp session to be handled4115* RETURN:4116* 0 = No error in the current transaction4117* -1 - if the session is invalid4118* positive value - the errno value4119*4120*/4121int sdp_get_error(sdp_session_t *session)4122{4123struct sdp_transaction *t;41244125if (!session || !session->priv) {4126SDPERR("Invalid session");4127return -1;4128}41294130t = session->priv;41314132return t->err;4133}41344135/*4136* Receive the incoming SDP PDU. This function must be called when there is data4137* available to be read. On continuation state, the original request (with a new4138* transaction ID) and the continuation state data will be appended in the initial PDU.4139* If an error happens or the transaction finishes the callback function will be called.4140*4141* INPUT:4142* sdp_session_t *session4143* Current sdp session to be handled4144* RETURN:4145* 0 - if the transaction is on continuation state4146* -1 - On any failure or the transaction finished4147*/4148int sdp_process(sdp_session_t *session)4149{4150struct sdp_transaction *t;4151sdp_pdu_hdr_t *reqhdr, *rsphdr;4152sdp_cstate_t *pcstate;4153uint8_t *pdata, *rspbuf, *targetPtr;4154int rsp_count, err = -1;4155size_t size = 0;4156int n, plen;4157uint16_t status = 0xffff;4158uint8_t pdu_id = 0x00;41594160if (!session || !session->priv) {4161SDPERR("Invalid session");4162return -1;4163}41644165rspbuf = malloc(SDP_RSP_BUFFER_SIZE);4166if (!rspbuf) {4167SDPERR("Response buffer alloc failure:%m (%d)", errno);4168return -1;4169}41704171memset(rspbuf, 0, SDP_RSP_BUFFER_SIZE);41724173t = session->priv;4174reqhdr = (sdp_pdu_hdr_t *)t->reqbuf;4175rsphdr = (sdp_pdu_hdr_t *)rspbuf;41764177pdata = rspbuf + sizeof(sdp_pdu_hdr_t);41784179n = sdp_read_rsp(session, rspbuf, SDP_RSP_BUFFER_SIZE);4180if (n < 0) {4181SDPERR("Read response:%m (%d)", errno);4182t->err = errno;4183goto end;4184}41854186if (n == 0 || reqhdr->tid != rsphdr->tid ||4187(n != (int) (ntohs(rsphdr->plen) + sizeof(sdp_pdu_hdr_t)))) {4188t->err = EPROTO;4189SDPERR("Protocol error.");4190goto end;4191}41924193pdu_id = rsphdr->pdu_id;4194switch (rsphdr->pdu_id) {4195uint8_t *ssr_pdata;4196uint16_t tsrc, csrc;4197case SDP_SVC_SEARCH_RSP:4198/*4199* TSRC: Total Service Record Count (2 bytes)4200* CSRC: Current Service Record Count (2 bytes)4201*/4202ssr_pdata = pdata;4203tsrc = bt_get_be16(ssr_pdata);4204ssr_pdata += sizeof(uint16_t);4205csrc = bt_get_be16(ssr_pdata);42064207/* csrc should never be larger than tsrc */4208if (csrc > tsrc) {4209t->err = EPROTO;4210SDPERR("Protocol error: wrong current service record count value.");4211goto end;4212}42134214SDPDBG("Total svc count: %d", tsrc);4215SDPDBG("Current svc count: %d", csrc);42164217/* parameter length without continuation state */4218plen = sizeof(tsrc) + sizeof(csrc) + csrc * 4;42194220if (t->rsp_concat_buf.data_size == 0) {4221/* first fragment */4222rsp_count = sizeof(tsrc) + sizeof(csrc) + csrc * 4;4223} else if (t->rsp_concat_buf.data_size >= sizeof(uint16_t) * 2) {4224/* point to the first csrc */4225uint8_t *pcsrc = t->rsp_concat_buf.data + 2;4226uint16_t tcsrc, tcsrc2;42274228/* FIXME: update the interface later. csrc doesn't need be passed to clients */42294230pdata += sizeof(uint16_t); /* point to csrc */42314232/* the first csrc contains the sum of partial csrc responses */4233memcpy(&tcsrc, pcsrc, sizeof(tcsrc));4234memcpy(&tcsrc2, pdata, sizeof(tcsrc2));4235tcsrc += tcsrc2;4236memcpy(pcsrc, &tcsrc, sizeof(tcsrc));42374238pdata += sizeof(uint16_t); /* point to the first handle */4239rsp_count = csrc * 4;4240} else {4241t->err = EPROTO;4242SDPERR("Protocol error: invalid PDU size");4243status = SDP_INVALID_PDU_SIZE;4244goto end;4245}4246status = 0x0000;4247break;4248case SDP_SVC_ATTR_RSP:4249case SDP_SVC_SEARCH_ATTR_RSP:4250rsp_count = bt_get_be16(pdata);4251SDPDBG("Attrlist byte count : %d", rsp_count);42524253/* Valid range for rsp_count is 0x0002-0xFFFF */4254if (t->rsp_concat_buf.data_size == 0 && rsp_count < 0x0002) {4255t->err = EPROTO;4256SDPERR("Protocol error: invalid AttrList size");4257status = SDP_INVALID_PDU_SIZE;4258goto end;4259}42604261/*4262* Number of bytes in the AttributeLists parameter(without4263* continuation state) + AttributeListsByteCount field size.4264*/4265plen = sizeof(uint16_t) + rsp_count;42664267pdata += sizeof(uint16_t); /* points to attribute list */4268status = 0x0000;4269break;4270case SDP_ERROR_RSP:4271status = bt_get_be16(pdata);4272size = ntohs(rsphdr->plen);42734274goto end;4275default:4276t->err = EPROTO;4277SDPERR("Illegal PDU ID: 0x%x", rsphdr->pdu_id);4278goto end;4279}42804281/* Out of bound check before using rsp_count as offset for4282* continuation state, which has at least a one byte size4283* field.4284*/4285if ((n - (int) sizeof(sdp_pdu_hdr_t)) < plen + 1) {4286t->err = EPROTO;4287SDPERR("Protocol error: invalid PDU size");4288status = SDP_INVALID_PDU_SIZE;4289goto end;4290}42914292pcstate = (sdp_cstate_t *) (pdata + rsp_count);42934294SDPDBG("Cstate length : %d", pcstate->length);42954296/*4297* Check out of bound. Continuation state must have at least4298* 1 byte: ZERO to indicate that it is not a partial response.4299*/4300if ((n - (int) sizeof(sdp_pdu_hdr_t)) != (plen + pcstate->length + 1)) {4301t->err = EPROTO;4302SDPERR("Protocol error: wrong PDU size.");4303status = 0xffff;4304goto end;4305}43064307/*4308* This is a split response, need to concatenate intermediate4309* responses and the last one which will have cstate length == 04310*/4311t->rsp_concat_buf.data = realloc(t->rsp_concat_buf.data, t->rsp_concat_buf.data_size + rsp_count);4312targetPtr = t->rsp_concat_buf.data + t->rsp_concat_buf.data_size;4313t->rsp_concat_buf.buf_size = t->rsp_concat_buf.data_size + rsp_count;4314memcpy(targetPtr, pdata, rsp_count);4315t->rsp_concat_buf.data_size += rsp_count;43164317if (pcstate->length > 0) {4318int reqsize, cstate_len;43194320reqhdr->tid = htons(sdp_gen_tid(session));43214322/* add continuation state */4323cstate_len = copy_cstate(t->reqbuf + t->reqsize,4324SDP_REQ_BUFFER_SIZE - t->reqsize, pcstate);43254326reqsize = t->reqsize + cstate_len;43274328/* set the request header's param length */4329reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));43304331if (sdp_send_req(session, t->reqbuf, reqsize) < 0) {4332SDPERR("Error sendind data:%m(%d)", errno);4333status = 0xffff;4334t->err = errno;4335goto end;4336}4337err = 0;4338}43394340end:4341if (err) {4342if (t->rsp_concat_buf.data_size != 0) {4343pdata = t->rsp_concat_buf.data;4344size = t->rsp_concat_buf.data_size;4345}4346if (t->cb)4347t->cb(pdu_id, status, pdata, size, t->udata);4348}43494350free(rspbuf);43514352return err;4353}43544355/*4356* This is a service search request combined with the service4357* attribute request. First a service class match is done and4358* for matching service, requested attributes are extracted4359*4360* INPUT :4361*4362* sdp_list_t *search4363* Singly linked list containing elements of the search4364* pattern. Each entry in the list is a UUID(DataTypeSDP_UUID16)4365* of the service to be searched4366*4367* AttributeSpecification attrSpec4368* Attribute identifiers are 16 bit unsigned integers specified4369* in one of 2 ways described below :4370* SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers4371* They are the actual attribute identifiers in ascending order4372*4373* SDP_ATTR_REQ_RANGE - 32bit identifier range4374* The high-order 16bits is the start of range4375* the low-order 16bits are the end of range4376* 0x0000 to 0xFFFF gets all attributes4377*4378* sdp_list_t *attrids4379* Singly linked list containing attribute identifiers desired.4380* Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)4381* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)4382*4383* OUTPUT :4384* int return value4385* 0:4386* The request completed successfully. This does not4387* mean the requested services were found4388* -1:4389* On any error and sets errno4390*4391* sdp_list_t **rsp4392* This variable is set on a successful return to point to4393* service(s) found. Each element of this list is of type4394* sdp_record_t* (of the services which matched the search list)4395*/4396int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrids, sdp_list_t **rsp)4397{4398int status = 0;4399uint32_t reqsize = 0, _reqsize;4400uint32_t rspsize = 0;4401int seqlen = 0, attr_list_len = 0;4402int rsp_count = 0, cstate_len = 0;4403unsigned int pdata_len;4404uint8_t *pdata, *_pdata;4405uint8_t *reqbuf, *rspbuf;4406sdp_pdu_hdr_t *reqhdr, *rsphdr;4407uint8_t dataType;4408sdp_list_t *rec_list = NULL;4409sdp_buf_t rsp_concat_buf;4410sdp_cstate_t *cstate = NULL;44114412if (reqtype != SDP_ATTR_REQ_INDIVIDUAL && reqtype != SDP_ATTR_REQ_RANGE) {4413errno = EINVAL;4414return -1;4415}44164417memset(&rsp_concat_buf, 0, sizeof(sdp_buf_t));44184419reqbuf = malloc(SDP_REQ_BUFFER_SIZE);4420rspbuf = malloc(SDP_RSP_BUFFER_SIZE);4421if (!reqbuf || !rspbuf) {4422errno = ENOMEM;4423status = -1;4424goto end;4425}44264427reqhdr = (sdp_pdu_hdr_t *) reqbuf;4428reqhdr->pdu_id = SDP_SVC_SEARCH_ATTR_REQ;44294430/* generate PDU */4431pdata = reqbuf + sizeof(sdp_pdu_hdr_t);4432reqsize = sizeof(sdp_pdu_hdr_t);44334434/* add service class IDs for search */4435seqlen = gen_searchseq_pdu(pdata, search);4436if (seqlen < 0) {4437errno = EINVAL;4438status = -1;4439goto end;4440}44414442SDPDBG("Data seq added : %d", seqlen);44434444/* now set the length and increment the pointer */4445reqsize += seqlen;4446pdata += seqlen;44474448bt_put_be16(SDP_MAX_ATTR_LEN, pdata);4449reqsize += sizeof(uint16_t);4450pdata += sizeof(uint16_t);44514452SDPDBG("Max attr byte count : %d", SDP_MAX_ATTR_LEN);44534454/* get attr seq PDU form */4455seqlen = gen_attridseq_pdu(pdata, attrids,4456reqtype == SDP_ATTR_REQ_INDIVIDUAL ? SDP_UINT16 : SDP_UINT32);4457if (seqlen == -1) {4458errno = EINVAL;4459status = -1;4460goto end;4461}4462pdata += seqlen;4463SDPDBG("Attr list length : %d", seqlen);4464reqsize += seqlen;4465*rsp = 0;44664467/* save before Continuation State */4468_pdata = pdata;4469_reqsize = reqsize;44704471do {4472reqhdr->tid = htons(sdp_gen_tid(session));44734474/* add continuation state (can be null) */4475reqsize = _reqsize + copy_cstate(_pdata,4476SDP_REQ_BUFFER_SIZE - _reqsize, cstate);44774478/* set the request header's param length */4479reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));4480rsphdr = (sdp_pdu_hdr_t *) rspbuf;4481status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize);4482if (rspsize < sizeof(sdp_pdu_hdr_t)) {4483SDPERR("Unexpected end of packet");4484status = -1;4485goto end;4486}44874488if (status < 0) {4489SDPDBG("Status : 0x%x", rsphdr->pdu_id);4490goto end;4491}44924493if (rsphdr->pdu_id == SDP_ERROR_RSP) {4494status = -1;4495goto end;4496}44974498pdata = rspbuf + sizeof(sdp_pdu_hdr_t);4499pdata_len = rspsize - sizeof(sdp_pdu_hdr_t);45004501if (pdata_len < sizeof(uint16_t)) {4502SDPERR("Unexpected end of packet");4503status = -1;4504goto end;4505}45064507rsp_count = bt_get_be16(pdata);4508attr_list_len += rsp_count;4509pdata += sizeof(uint16_t); /* pdata points to attribute list */4510pdata_len -= sizeof(uint16_t);45114512if (pdata_len < rsp_count + sizeof(uint8_t)) {4513SDPERR("Unexpected end of packet: continuation state data missing");4514status = -1;4515goto end;4516}45174518cstate_len = *(uint8_t *) (pdata + rsp_count);45194520SDPDBG("Attrlist byte count : %d", attr_list_len);4521SDPDBG("Response byte count : %d", rsp_count);4522SDPDBG("Cstate length : %d", cstate_len);4523/*4524* This is a split response, need to concatenate intermediate4525* responses and the last one which will have cstate_len == 04526*/4527if (cstate_len > 0 || rsp_concat_buf.data_size != 0) {4528uint8_t *targetPtr = NULL;45294530cstate = cstate_len > 0 ? (sdp_cstate_t *) (pdata + rsp_count) : 0;45314532/* build concatenated response buffer */4533rsp_concat_buf.data = realloc(rsp_concat_buf.data, rsp_concat_buf.data_size + rsp_count);4534targetPtr = rsp_concat_buf.data + rsp_concat_buf.data_size;4535rsp_concat_buf.buf_size = rsp_concat_buf.data_size + rsp_count;4536memcpy(targetPtr, pdata, rsp_count);4537rsp_concat_buf.data_size += rsp_count;4538}4539} while (cstate);45404541if (attr_list_len > 0) {4542int scanned = 0;45434544if (rsp_concat_buf.data_size != 0) {4545pdata = rsp_concat_buf.data;4546pdata_len = rsp_concat_buf.data_size;4547}45484549/*4550* Response is a sequence of sequence(s) for one or4551* more data element sequence(s) representing services4552* for which attributes are returned4553*/4554scanned = sdp_extract_seqtype(pdata, pdata_len, &dataType, &seqlen);45554556SDPDBG("Bytes scanned : %d", scanned);4557SDPDBG("Seq length : %d", seqlen);45584559if (scanned && seqlen) {4560pdata += scanned;4561pdata_len -= scanned;4562do {4563int recsize = 0;4564sdp_record_t *rec = sdp_extract_pdu(pdata, pdata_len, &recsize);4565if (rec == NULL) {4566SDPERR("SVC REC is null");4567status = -1;4568goto end;4569}4570if (!recsize) {4571sdp_record_free(rec);4572break;4573}4574scanned += recsize;4575pdata += recsize;4576pdata_len -= recsize;45774578SDPDBG("Loc seq length : %d", recsize);4579SDPDBG("Svc Rec Handle : 0x%x", rec->handle);4580SDPDBG("Bytes scanned : %d", scanned);4581SDPDBG("Attrlist byte count : %d", attr_list_len);4582rec_list = sdp_list_append(rec_list, rec);4583} while (scanned < attr_list_len && pdata_len > 0);45844585SDPDBG("Successful scan of service attr lists");4586*rsp = rec_list;4587}4588}4589end:4590free(rsp_concat_buf.data);4591free(reqbuf);4592free(rspbuf);4593return status;4594}45954596/*4597* Find devices in the piconet.4598*/4599int sdp_general_inquiry(inquiry_info *ii, int num_dev, int duration, uint8_t *found)4600{4601int n = hci_inquiry(-1, 10, num_dev, NULL, &ii, 0);4602if (n < 0) {4603SDPERR("Inquiry failed:%m");4604return -1;4605}4606*found = n;4607return 0;4608}46094610int sdp_close(sdp_session_t *session)4611{4612struct sdp_transaction *t;4613int ret;46144615if (!session)4616return -1;46174618ret = close(session->sock);46194620t = session->priv;46214622if (t) {4623free(t->reqbuf);46244625free(t->rsp_concat_buf.data);46264627free(t);4628}4629free(session);4630return ret;4631}46324633static inline int sdp_is_local(const bdaddr_t *device)4634{4635return memcmp(device, BDADDR_LOCAL, sizeof(bdaddr_t)) == 0;4636}46374638static int sdp_connect_local(sdp_session_t *session)4639{4640struct sockaddr_un sa;46414642session->sock = socket(PF_UNIX, SOCK_STREAM | O_CLOEXEC, 0);4643if (session->sock < 0)4644return -1;4645session->local = 1;46464647sa.sun_family = AF_UNIX;4648strcpy(sa.sun_path, SDP_UNIX_PATH);46494650return connect(session->sock, (struct sockaddr *) &sa, sizeof(sa));4651}46524653static int sdp_connect_l2cap(const bdaddr_t *src,4654const bdaddr_t *dst, sdp_session_t *session)4655{4656uint32_t flags = session->flags;4657struct sockaddr_l2 sa;4658int sk;4659int sockflags = SOCK_SEQPACKET | O_CLOEXEC;46604661if (flags & SDP_NON_BLOCKING)4662sockflags |= O_NONBLOCK;46634664session->sock = socket(PF_BLUETOOTH, sockflags, BTPROTO_L2CAP);4665if (session->sock < 0)4666return -1;4667session->local = 0;46684669sk = session->sock;46704671memset(&sa, 0, sizeof(sa));46724673sa.l2_family = AF_BLUETOOTH;4674sa.l2_psm = 0;46754676if (bacmp(src, BDADDR_ANY)) {4677sa.l2_bdaddr = *src;4678if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0)4679return -1;4680}46814682if (flags & SDP_WAIT_ON_CLOSE) {4683struct linger l = { .l_onoff = 1, .l_linger = 1 };4684setsockopt(sk, SOL_SOCKET, SO_LINGER, &l, sizeof(l));4685}46864687sa.l2_psm = htobs(SDP_PSM);4688sa.l2_bdaddr = *dst;46894690do {4691int ret = connect(sk, (struct sockaddr *) &sa, sizeof(sa));4692if (!ret)4693return 0;4694if (ret < 0 && (flags & SDP_NON_BLOCKING) &&4695(errno == EAGAIN || errno == EINPROGRESS))4696return 0;4697} while (errno == EBUSY && (flags & SDP_RETRY_IF_BUSY));46984699return -1;4700}47014702sdp_session_t *sdp_connect(const bdaddr_t *src,4703const bdaddr_t *dst, uint32_t flags)4704{4705sdp_session_t *session;4706int err;47074708if ((flags & SDP_RETRY_IF_BUSY) && (flags & SDP_NON_BLOCKING)) {4709errno = EINVAL;4710return NULL;4711}47124713session = sdp_create(-1, flags);4714if (!session)4715return NULL;47164717if (sdp_is_local(dst)) {4718if (sdp_connect_local(session) < 0)4719goto fail;4720} else {4721if (sdp_connect_l2cap(src, dst, session) < 0)4722goto fail;4723}47244725return session;47264727fail:4728err = errno;4729if (session->sock >= 0)4730close(session->sock);4731free(session->priv);4732free(session);4733errno = err;47344735return NULL;4736}47374738int sdp_get_socket(const sdp_session_t *session)4739{4740return session->sock;4741}47424743uint16_t sdp_gen_tid(sdp_session_t *session)4744{4745return session->tid++;4746}47474748/*4749* Set the supported features4750*/4751int sdp_set_supp_feat(sdp_record_t *rec, const sdp_list_t *sf)4752{4753const sdp_list_t *p, *r;4754sdp_data_t *feat, *seq_feat;4755int seqlen, i;4756void **seqDTDs, **seqVals;47574758seqlen = sdp_list_len(sf);4759seqDTDs = malloc(seqlen * sizeof(void *));4760if (!seqDTDs)4761return -1;4762seqVals = malloc(seqlen * sizeof(void *));4763if (!seqVals) {4764free(seqDTDs);4765return -1;4766}47674768for (p = sf, i = 0; p; p = p->next, i++) {4769int plen, j;4770void **dtds, **vals;4771int *lengths;47724773plen = sdp_list_len(p->data);4774dtds = malloc(plen * sizeof(void *));4775if (!dtds)4776goto fail;4777vals = malloc(plen * sizeof(void *));4778if (!vals) {4779free(dtds);4780goto fail;4781}4782lengths = malloc(plen * sizeof(int *));4783if (!lengths) {4784free(dtds);4785free(vals);4786goto fail;4787}4788for (r = p->data, j = 0; r; r = r->next, j++) {4789sdp_data_t *data = (sdp_data_t *) r->data;4790dtds[j] = &data->dtd;4791switch (data->dtd) {4792case SDP_URL_STR8:4793case SDP_URL_STR16:4794case SDP_TEXT_STR8:4795case SDP_TEXT_STR16:4796vals[j] = data->val.str;4797lengths[j] = data->unitSize - sizeof(uint8_t);4798break;4799case SDP_ALT8:4800case SDP_ALT16:4801case SDP_ALT32:4802case SDP_SEQ8:4803case SDP_SEQ16:4804case SDP_SEQ32:4805vals[j] = data->val.dataseq;4806lengths[j] = 0;4807break;4808default:4809vals[j] = &data->val;4810lengths[j] = 0;4811break;4812}4813}4814feat = sdp_seq_alloc_with_length(dtds, vals, lengths, plen);4815free(dtds);4816free(vals);4817free(lengths);4818if (!feat)4819goto fail;4820seqDTDs[i] = &feat->dtd;4821seqVals[i] = feat;4822}4823seq_feat = sdp_seq_alloc(seqDTDs, seqVals, seqlen);4824if (!seq_feat)4825goto fail;4826sdp_attr_replace(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST, seq_feat);48274828free(seqVals);4829free(seqDTDs);4830return 0;48314832fail:4833free(seqVals);4834free(seqDTDs);4835return -1;4836}48374838/*4839* Get the supported features4840* If an error occurred -1 is returned and errno is set4841*/4842int sdp_get_supp_feat(const sdp_record_t *rec, sdp_list_t **seqp)4843{4844sdp_data_t *sdpdata, *d;4845sdp_list_t *tseq;4846tseq = NULL;48474848sdpdata = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST);48494850if (!sdpdata || !SDP_IS_SEQ(sdpdata->dtd))4851return sdp_get_uuidseq_attr(rec,4852SDP_ATTR_SUPPORTED_FEATURES_LIST, seqp);48534854for (d = sdpdata->val.dataseq; d; d = d->next) {4855sdp_data_t *dd;4856sdp_list_t *subseq;48574858if (!SDP_IS_SEQ(d->dtd))4859goto fail;48604861subseq = NULL;48624863for (dd = d->val.dataseq; dd; dd = dd->next) {4864sdp_data_t *data;4865void *val;4866int length;48674868switch (dd->dtd) {4869case SDP_URL_STR8:4870case SDP_URL_STR16:4871case SDP_TEXT_STR8:4872case SDP_TEXT_STR16:4873val = dd->val.str;4874length = dd->unitSize - sizeof(uint8_t);4875break;4876case SDP_UINT8:4877case SDP_UINT16:4878val = &dd->val;4879length = 0;4880break;4881default:4882goto fail;4883}48844885data = sdp_data_alloc_with_length(dd->dtd, val, length);4886if (data)4887subseq = sdp_list_append(subseq, data);4888}4889tseq = sdp_list_append(tseq, subseq);4890}4891*seqp = tseq;4892return 0;48934894fail:4895while (tseq) {4896sdp_list_t * next;48974898next = tseq->next;4899sdp_list_free(tseq, free);4900tseq = next;4901}4902errno = EINVAL;4903return -1;4904}49054906void sdp_add_lang_attr(sdp_record_t *rec)4907{4908sdp_lang_attr_t base_lang;4909sdp_list_t *langs;49104911base_lang.code_ISO639 = (0x65 << 8) | 0x6e;4912base_lang.encoding = 106;4913base_lang.base_offset = SDP_PRIMARY_LANG_BASE;49144915langs = sdp_list_append(0, &base_lang);4916sdp_set_lang_attr(rec, langs);4917sdp_list_free(langs, NULL);4918}491949204921