Path: blob/main/usr.bin/bluetooth/rfcomm_sppd/rfcomm_sdp.c
34865 views
/*-1* rfcomm_sdp.c2*3* SPDX-License-Identifier: BSD-2-Clause4*5* Copyright (c) 2003 Maksim Yevmenkin <[email protected]>6* All rights reserved.7*8* Redistribution and use in source and binary forms, with or without9* modification, are permitted provided that the following conditions10* are met:11* 1. Redistributions of source code must retain the above copyright12* notice, this list of conditions and the following disclaimer.13* 2. Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in the15* documentation and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND18* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE19* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE20* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE21* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL22* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS23* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)24* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT25* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY26* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF27* SUCH DAMAGE.28*29* $Id: rfcomm_sdp.c,v 1.1 2003/09/07 18:15:55 max Exp $30*/31#define L2CAP_SOCKET_CHECKED32#include <bluetooth.h>33#include <errno.h>34#include <sdp.h>35#include <stdio.h>3637#undef PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE38#define PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE 2563940#undef PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE41#define PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE 124243static int rfcomm_proto_list_parse (uint8_t const *start, uint8_t const *end,44int *channel, int *error);4546/*47* Lookup RFCOMM channel number in the Protocol Descriptor List48*/4950#undef rfcomm_channel_lookup_exit51#define rfcomm_channel_lookup_exit(e) { \52if (error != NULL) \53*error = (e); \54if (ss != NULL) { \55sdp_close(ss); \56ss = NULL; \57} \58return (((e) == 0)? 0 : -1); \59}6061int62rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote,63int service, int *channel, int *error)64{65uint8_t buffer[PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE];66void *ss = NULL;67uint16_t serv = (uint16_t) service;68uint32_t attr = SDP_ATTR_RANGE(69SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,70SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);71sdp_attr_t proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer };72uint32_t type, len;7374if (local == NULL)75local = NG_HCI_BDADDR_ANY;76if (remote == NULL || channel == NULL)77rfcomm_channel_lookup_exit(EINVAL);7879if ((ss = sdp_open(local, remote)) == NULL)80rfcomm_channel_lookup_exit(ENOMEM);81if (sdp_error(ss) != 0)82rfcomm_channel_lookup_exit(sdp_error(ss));8384if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0)85rfcomm_channel_lookup_exit(sdp_error(ss));86if (proto.flags != SDP_ATTR_OK)87rfcomm_channel_lookup_exit(ENOATTR);8889sdp_close(ss);90ss = NULL;9192/*93* If it is possible for more than one kind of protocol stack to be94* used to gain access to the service, the ProtocolDescriptorList95* takes the form of a data element alternative. We always use the96* first protocol stack.97*98* A minimal Protocol Descriptor List for RFCOMM based service would99* look like100*101* seq8 len8 - 2 bytes102* seq8 len8 - 2 bytes103* uuid16 value16 - 3 bytes L2CAP104* seq8 len8 - 2 bytes105* uuid16 value16 - 3 bytes RFCOMM106* uint8 value8 - 2 bytes RFCOMM param #1107* =========108* 14 bytes109*110* Lets not count first [seq8 len8] wrapper, so the minimal size of111* the Protocol Descriptor List (the data we are actually interested112* in) for RFCOMM based service would be 12 bytes.113*/114115if (proto.vlen < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE)116rfcomm_channel_lookup_exit(EINVAL);117118SDP_GET8(type, proto.value);119120if (type == SDP_DATA_ALT8) {121SDP_GET8(len, proto.value);122} else if (type == SDP_DATA_ALT16) {123SDP_GET16(len, proto.value);124} else if (type == SDP_DATA_ALT32) {125SDP_GET32(len, proto.value);126} else127len = 0;128129if (len > 0)130SDP_GET8(type, proto.value);131132switch (type) {133case SDP_DATA_SEQ8:134SDP_GET8(len, proto.value);135break;136137case SDP_DATA_SEQ16:138SDP_GET16(len, proto.value);139break;140141case SDP_DATA_SEQ32:142SDP_GET32(len, proto.value);143break;144145default:146rfcomm_channel_lookup_exit(ENOATTR);147/* NOT REACHED */148}149150if (len < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE)151rfcomm_channel_lookup_exit(EINVAL);152153return (rfcomm_proto_list_parse(proto.value,154buffer + proto.vlen, channel, error));155}156157/*158* Parse protocol descriptor list159*160* The ProtocolDescriptorList attribute describes one or more protocol161* stacks that may be used to gain access to the service described by162* the service record. If the ProtocolDescriptorList describes a single163* stack, it takes the form of a data element sequence in which each164* element of the sequence is a protocol descriptor.165*/166167#undef rfcomm_proto_list_parse_exit168#define rfcomm_proto_list_parse_exit(e) { \169if (error != NULL) \170*error = (e); \171return (((e) == 0)? 0 : -1); \172}173174static int175rfcomm_proto_list_parse(uint8_t const *start, uint8_t const *end,176int *channel, int *error)177{178int type, len, value;179180while (start < end) {181182/*183* Parse protocol descriptor184*185* A protocol descriptor identifies a communications protocol186* and provides protocol specific parameters. A protocol187* descriptor is represented as a data element sequence. The188* first data element in the sequence must be the UUID that189* identifies the protocol. Additional data elements optionally190* provide protocol specific information, such as the L2CAP191* protocol/service multiplexer (PSM) and the RFCOMM server192* channel number (CN).193*/194195/* We must have at least one byte (type) */196if (end - start < 1)197rfcomm_proto_list_parse_exit(EINVAL)198199SDP_GET8(type, start);200switch (type) {201case SDP_DATA_SEQ8:202SDP_GET8(len, start);203break;204205case SDP_DATA_SEQ16:206SDP_GET16(len, start);207break;208209case SDP_DATA_SEQ32:210SDP_GET32(len, start);211break;212213default:214rfcomm_proto_list_parse_exit(ENOATTR)215/* NOT REACHED */216}217218/* We must have at least 3 bytes (type + UUID16) */219if (end - start < 3)220rfcomm_proto_list_parse_exit(EINVAL);221222/* Get protocol UUID */223SDP_GET8(type, start); len -= sizeof(uint8_t);224switch (type) {225case SDP_DATA_UUID16:226SDP_GET16(value, start); len -= sizeof(uint16_t);227if (value != SDP_UUID_PROTOCOL_RFCOMM)228goto next_protocol;229break;230231case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */232case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */233default:234rfcomm_proto_list_parse_exit(ENOATTR);235/* NOT REACHED */236}237238/*239* First protocol specific parameter for RFCOMM procotol must240* be uint8 that represents RFCOMM channel number. So we must241* have at least two bytes.242*/243244if (end - start < 2)245rfcomm_proto_list_parse_exit(EINVAL);246247SDP_GET8(type, start);248if (type != SDP_DATA_UINT8)249rfcomm_proto_list_parse_exit(ENOATTR);250251SDP_GET8(*channel, start);252253rfcomm_proto_list_parse_exit(0);254/* NOT REACHED */255next_protocol:256start += len;257}258259/*260* If we got here then it means we could not find RFCOMM protocol261* descriptor, but the reply format was actually valid.262*/263264rfcomm_proto_list_parse_exit(ENOATTR);265}266267268269