1*1de7b4b8SPedro F. Giffuni /*- 20986ab12SMaksim Yevmenkin * rfcomm_sdp.c 30986ab12SMaksim Yevmenkin * 4*1de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 5*1de7b4b8SPedro F. Giffuni * 60986ab12SMaksim Yevmenkin * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 70986ab12SMaksim Yevmenkin * All rights reserved. 80986ab12SMaksim Yevmenkin * 90986ab12SMaksim Yevmenkin * Redistribution and use in source and binary forms, with or without 100986ab12SMaksim Yevmenkin * modification, are permitted provided that the following conditions 110986ab12SMaksim Yevmenkin * are met: 120986ab12SMaksim Yevmenkin * 1. Redistributions of source code must retain the above copyright 130986ab12SMaksim Yevmenkin * notice, this list of conditions and the following disclaimer. 140986ab12SMaksim Yevmenkin * 2. Redistributions in binary form must reproduce the above copyright 150986ab12SMaksim Yevmenkin * notice, this list of conditions and the following disclaimer in the 160986ab12SMaksim Yevmenkin * documentation and/or other materials provided with the distribution. 170986ab12SMaksim Yevmenkin * 180986ab12SMaksim Yevmenkin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 190986ab12SMaksim Yevmenkin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 200986ab12SMaksim Yevmenkin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 210986ab12SMaksim Yevmenkin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 220986ab12SMaksim Yevmenkin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 230986ab12SMaksim Yevmenkin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 240986ab12SMaksim Yevmenkin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 250986ab12SMaksim Yevmenkin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 260986ab12SMaksim Yevmenkin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 270986ab12SMaksim Yevmenkin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 280986ab12SMaksim Yevmenkin * SUCH DAMAGE. 290986ab12SMaksim Yevmenkin * 300986ab12SMaksim Yevmenkin * $Id: rfcomm_sdp.c,v 1.1 2003/09/07 18:15:55 max Exp $ 310986ab12SMaksim Yevmenkin * $FreeBSD$ 320986ab12SMaksim Yevmenkin */ 338d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED 340986ab12SMaksim Yevmenkin #include <bluetooth.h> 350986ab12SMaksim Yevmenkin #include <errno.h> 360986ab12SMaksim Yevmenkin #include <sdp.h> 370986ab12SMaksim Yevmenkin #include <stdio.h> 380986ab12SMaksim Yevmenkin 390986ab12SMaksim Yevmenkin #undef PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE 400986ab12SMaksim Yevmenkin #define PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE 256 410986ab12SMaksim Yevmenkin 420986ab12SMaksim Yevmenkin #undef PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE 430986ab12SMaksim Yevmenkin #define PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE 12 440986ab12SMaksim Yevmenkin 452f122b6eSMaksim Yevmenkin static int rfcomm_proto_list_parse (uint8_t const *start, uint8_t const *end, 460986ab12SMaksim Yevmenkin int *channel, int *error); 470986ab12SMaksim Yevmenkin 480986ab12SMaksim Yevmenkin /* 490986ab12SMaksim Yevmenkin * Lookup RFCOMM channel number in the Protocol Descriptor List 500986ab12SMaksim Yevmenkin */ 510986ab12SMaksim Yevmenkin 520986ab12SMaksim Yevmenkin #undef rfcomm_channel_lookup_exit 530986ab12SMaksim Yevmenkin #define rfcomm_channel_lookup_exit(e) { \ 540986ab12SMaksim Yevmenkin if (error != NULL) \ 550986ab12SMaksim Yevmenkin *error = (e); \ 560986ab12SMaksim Yevmenkin if (ss != NULL) { \ 570986ab12SMaksim Yevmenkin sdp_close(ss); \ 580986ab12SMaksim Yevmenkin ss = NULL; \ 590986ab12SMaksim Yevmenkin } \ 600986ab12SMaksim Yevmenkin return (((e) == 0)? 0 : -1); \ 610986ab12SMaksim Yevmenkin } 620986ab12SMaksim Yevmenkin 630986ab12SMaksim Yevmenkin int 640986ab12SMaksim Yevmenkin rfcomm_channel_lookup(bdaddr_t const *local, bdaddr_t const *remote, 650986ab12SMaksim Yevmenkin int service, int *channel, int *error) 660986ab12SMaksim Yevmenkin { 672f122b6eSMaksim Yevmenkin uint8_t buffer[PROTOCOL_DESCRIPTOR_LIST_BUFFER_SIZE]; 680986ab12SMaksim Yevmenkin void *ss = NULL; 692f122b6eSMaksim Yevmenkin uint16_t serv = (uint16_t) service; 702f122b6eSMaksim Yevmenkin uint32_t attr = SDP_ATTR_RANGE( 710986ab12SMaksim Yevmenkin SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 720986ab12SMaksim Yevmenkin SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST); 730986ab12SMaksim Yevmenkin sdp_attr_t proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer }; 742f122b6eSMaksim Yevmenkin uint32_t type, len; 750986ab12SMaksim Yevmenkin 760986ab12SMaksim Yevmenkin if (local == NULL) 770986ab12SMaksim Yevmenkin local = NG_HCI_BDADDR_ANY; 780986ab12SMaksim Yevmenkin if (remote == NULL || channel == NULL) 790986ab12SMaksim Yevmenkin rfcomm_channel_lookup_exit(EINVAL); 800986ab12SMaksim Yevmenkin 810986ab12SMaksim Yevmenkin if ((ss = sdp_open(local, remote)) == NULL) 820986ab12SMaksim Yevmenkin rfcomm_channel_lookup_exit(ENOMEM); 830986ab12SMaksim Yevmenkin if (sdp_error(ss) != 0) 840986ab12SMaksim Yevmenkin rfcomm_channel_lookup_exit(sdp_error(ss)); 850986ab12SMaksim Yevmenkin 860986ab12SMaksim Yevmenkin if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0) 870986ab12SMaksim Yevmenkin rfcomm_channel_lookup_exit(sdp_error(ss)); 880986ab12SMaksim Yevmenkin if (proto.flags != SDP_ATTR_OK) 890986ab12SMaksim Yevmenkin rfcomm_channel_lookup_exit(ENOATTR); 900986ab12SMaksim Yevmenkin 910986ab12SMaksim Yevmenkin sdp_close(ss); 920986ab12SMaksim Yevmenkin ss = NULL; 930986ab12SMaksim Yevmenkin 940986ab12SMaksim Yevmenkin /* 950986ab12SMaksim Yevmenkin * If it is possible for more than one kind of protocol stack to be 960986ab12SMaksim Yevmenkin * used to gain access to the service, the ProtocolDescriptorList 970986ab12SMaksim Yevmenkin * takes the form of a data element alternative. We always use the 980986ab12SMaksim Yevmenkin * first protocol stack. 990986ab12SMaksim Yevmenkin * 1000986ab12SMaksim Yevmenkin * A minimal Protocol Descriptor List for RFCOMM based service would 1010986ab12SMaksim Yevmenkin * look like 1020986ab12SMaksim Yevmenkin * 1030986ab12SMaksim Yevmenkin * seq8 len8 - 2 bytes 1040986ab12SMaksim Yevmenkin * seq8 len8 - 2 bytes 1050986ab12SMaksim Yevmenkin * uuid16 value16 - 3 bytes L2CAP 1060986ab12SMaksim Yevmenkin * seq8 len8 - 2 bytes 1070986ab12SMaksim Yevmenkin * uuid16 value16 - 3 bytes RFCOMM 1080986ab12SMaksim Yevmenkin * uint8 value8 - 2 bytes RFCOMM param #1 1090986ab12SMaksim Yevmenkin * ========= 1100986ab12SMaksim Yevmenkin * 14 bytes 1110986ab12SMaksim Yevmenkin * 1120986ab12SMaksim Yevmenkin * Lets not count first [seq8 len8] wrapper, so the minimal size of 1130986ab12SMaksim Yevmenkin * the Protocol Descriptor List (the data we are actually interested 1140986ab12SMaksim Yevmenkin * in) for RFCOMM based service would be 12 bytes. 1150986ab12SMaksim Yevmenkin */ 1160986ab12SMaksim Yevmenkin 1170986ab12SMaksim Yevmenkin if (proto.vlen < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE) 1180986ab12SMaksim Yevmenkin rfcomm_channel_lookup_exit(EINVAL); 1190986ab12SMaksim Yevmenkin 1200986ab12SMaksim Yevmenkin SDP_GET8(type, proto.value); 1210986ab12SMaksim Yevmenkin 1220986ab12SMaksim Yevmenkin if (type == SDP_DATA_ALT8) { 1230986ab12SMaksim Yevmenkin SDP_GET8(len, proto.value); 1240986ab12SMaksim Yevmenkin } else if (type == SDP_DATA_ALT16) { 1250986ab12SMaksim Yevmenkin SDP_GET16(len, proto.value); 1260986ab12SMaksim Yevmenkin } else if (type == SDP_DATA_ALT32) { 1270986ab12SMaksim Yevmenkin SDP_GET32(len, proto.value); 1280986ab12SMaksim Yevmenkin } else 1290986ab12SMaksim Yevmenkin len = 0; 1300986ab12SMaksim Yevmenkin 1310986ab12SMaksim Yevmenkin if (len > 0) 1320986ab12SMaksim Yevmenkin SDP_GET8(type, proto.value); 1330986ab12SMaksim Yevmenkin 1340986ab12SMaksim Yevmenkin switch (type) { 1350986ab12SMaksim Yevmenkin case SDP_DATA_SEQ8: 1360986ab12SMaksim Yevmenkin SDP_GET8(len, proto.value); 1370986ab12SMaksim Yevmenkin break; 1380986ab12SMaksim Yevmenkin 1390986ab12SMaksim Yevmenkin case SDP_DATA_SEQ16: 1400986ab12SMaksim Yevmenkin SDP_GET16(len, proto.value); 1410986ab12SMaksim Yevmenkin break; 1420986ab12SMaksim Yevmenkin 1430986ab12SMaksim Yevmenkin case SDP_DATA_SEQ32: 1440986ab12SMaksim Yevmenkin SDP_GET32(len, proto.value); 1450986ab12SMaksim Yevmenkin break; 1460986ab12SMaksim Yevmenkin 1470986ab12SMaksim Yevmenkin default: 1480986ab12SMaksim Yevmenkin rfcomm_channel_lookup_exit(ENOATTR); 1490986ab12SMaksim Yevmenkin /* NOT REACHED */ 1500986ab12SMaksim Yevmenkin } 1510986ab12SMaksim Yevmenkin 1520986ab12SMaksim Yevmenkin if (len < PROTOCOL_DESCRIPTOR_LIST_MINIMAL_SIZE) 1530986ab12SMaksim Yevmenkin rfcomm_channel_lookup_exit(EINVAL); 1540986ab12SMaksim Yevmenkin 1550986ab12SMaksim Yevmenkin return (rfcomm_proto_list_parse(proto.value, 1560986ab12SMaksim Yevmenkin buffer + proto.vlen, channel, error)); 1570986ab12SMaksim Yevmenkin } 1580986ab12SMaksim Yevmenkin 1590986ab12SMaksim Yevmenkin /* 1600986ab12SMaksim Yevmenkin * Parse protocol descriptor list 1610986ab12SMaksim Yevmenkin * 1620986ab12SMaksim Yevmenkin * The ProtocolDescriptorList attribute describes one or more protocol 1630986ab12SMaksim Yevmenkin * stacks that may be used to gain access to the service described by 1640986ab12SMaksim Yevmenkin * the service record. If the ProtocolDescriptorList describes a single 1650986ab12SMaksim Yevmenkin * stack, it takes the form of a data element sequence in which each 1660986ab12SMaksim Yevmenkin * element of the sequence is a protocol descriptor. 1670986ab12SMaksim Yevmenkin */ 1680986ab12SMaksim Yevmenkin 1690986ab12SMaksim Yevmenkin #undef rfcomm_proto_list_parse_exit 1700986ab12SMaksim Yevmenkin #define rfcomm_proto_list_parse_exit(e) { \ 1710986ab12SMaksim Yevmenkin if (error != NULL) \ 1720986ab12SMaksim Yevmenkin *error = (e); \ 1730986ab12SMaksim Yevmenkin return (((e) == 0)? 0 : -1); \ 1740986ab12SMaksim Yevmenkin } 1750986ab12SMaksim Yevmenkin 1760986ab12SMaksim Yevmenkin static int 1772f122b6eSMaksim Yevmenkin rfcomm_proto_list_parse(uint8_t const *start, uint8_t const *end, 1780986ab12SMaksim Yevmenkin int *channel, int *error) 1790986ab12SMaksim Yevmenkin { 1800986ab12SMaksim Yevmenkin int type, len, value; 1810986ab12SMaksim Yevmenkin 1820986ab12SMaksim Yevmenkin while (start < end) { 1830986ab12SMaksim Yevmenkin 1840986ab12SMaksim Yevmenkin /* 1850986ab12SMaksim Yevmenkin * Parse protocol descriptor 1860986ab12SMaksim Yevmenkin * 1870986ab12SMaksim Yevmenkin * A protocol descriptor identifies a communications protocol 1880986ab12SMaksim Yevmenkin * and provides protocol specific parameters. A protocol 1890986ab12SMaksim Yevmenkin * descriptor is represented as a data element sequence. The 1900986ab12SMaksim Yevmenkin * first data element in the sequence must be the UUID that 1910986ab12SMaksim Yevmenkin * identifies the protocol. Additional data elements optionally 1920986ab12SMaksim Yevmenkin * provide protocol specific information, such as the L2CAP 1930986ab12SMaksim Yevmenkin * protocol/service multiplexer (PSM) and the RFCOMM server 1940986ab12SMaksim Yevmenkin * channel number (CN). 1950986ab12SMaksim Yevmenkin */ 1960986ab12SMaksim Yevmenkin 1970986ab12SMaksim Yevmenkin /* We must have at least one byte (type) */ 1980986ab12SMaksim Yevmenkin if (end - start < 1) 1990986ab12SMaksim Yevmenkin rfcomm_proto_list_parse_exit(EINVAL) 2000986ab12SMaksim Yevmenkin 2010986ab12SMaksim Yevmenkin SDP_GET8(type, start); 2020986ab12SMaksim Yevmenkin switch (type) { 2030986ab12SMaksim Yevmenkin case SDP_DATA_SEQ8: 2040986ab12SMaksim Yevmenkin SDP_GET8(len, start); 2050986ab12SMaksim Yevmenkin break; 2060986ab12SMaksim Yevmenkin 2070986ab12SMaksim Yevmenkin case SDP_DATA_SEQ16: 2080986ab12SMaksim Yevmenkin SDP_GET16(len, start); 2090986ab12SMaksim Yevmenkin break; 2100986ab12SMaksim Yevmenkin 2110986ab12SMaksim Yevmenkin case SDP_DATA_SEQ32: 2120986ab12SMaksim Yevmenkin SDP_GET32(len, start); 2130986ab12SMaksim Yevmenkin break; 2140986ab12SMaksim Yevmenkin 2150986ab12SMaksim Yevmenkin default: 2160986ab12SMaksim Yevmenkin rfcomm_proto_list_parse_exit(ENOATTR) 2170986ab12SMaksim Yevmenkin /* NOT REACHED */ 2180986ab12SMaksim Yevmenkin } 2190986ab12SMaksim Yevmenkin 2200986ab12SMaksim Yevmenkin /* We must have at least 3 bytes (type + UUID16) */ 2210986ab12SMaksim Yevmenkin if (end - start < 3) 2220986ab12SMaksim Yevmenkin rfcomm_proto_list_parse_exit(EINVAL); 2230986ab12SMaksim Yevmenkin 2240986ab12SMaksim Yevmenkin /* Get protocol UUID */ 2252f122b6eSMaksim Yevmenkin SDP_GET8(type, start); len -= sizeof(uint8_t); 2260986ab12SMaksim Yevmenkin switch (type) { 2270986ab12SMaksim Yevmenkin case SDP_DATA_UUID16: 2282f122b6eSMaksim Yevmenkin SDP_GET16(value, start); len -= sizeof(uint16_t); 2290986ab12SMaksim Yevmenkin if (value != SDP_UUID_PROTOCOL_RFCOMM) 2300986ab12SMaksim Yevmenkin goto next_protocol; 2310986ab12SMaksim Yevmenkin break; 2320986ab12SMaksim Yevmenkin 2330986ab12SMaksim Yevmenkin case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */ 2340986ab12SMaksim Yevmenkin case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */ 2350986ab12SMaksim Yevmenkin default: 2360986ab12SMaksim Yevmenkin rfcomm_proto_list_parse_exit(ENOATTR); 2370986ab12SMaksim Yevmenkin /* NOT REACHED */ 2380986ab12SMaksim Yevmenkin } 2390986ab12SMaksim Yevmenkin 2400986ab12SMaksim Yevmenkin /* 2410986ab12SMaksim Yevmenkin * First protocol specific parameter for RFCOMM procotol must 2420986ab12SMaksim Yevmenkin * be uint8 that represents RFCOMM channel number. So we must 2430986ab12SMaksim Yevmenkin * have at least two bytes. 2440986ab12SMaksim Yevmenkin */ 2450986ab12SMaksim Yevmenkin 2460986ab12SMaksim Yevmenkin if (end - start < 2) 2470986ab12SMaksim Yevmenkin rfcomm_proto_list_parse_exit(EINVAL); 2480986ab12SMaksim Yevmenkin 2490986ab12SMaksim Yevmenkin SDP_GET8(type, start); 2500986ab12SMaksim Yevmenkin if (type != SDP_DATA_UINT8) 2510986ab12SMaksim Yevmenkin rfcomm_proto_list_parse_exit(ENOATTR); 2520986ab12SMaksim Yevmenkin 2530986ab12SMaksim Yevmenkin SDP_GET8(*channel, start); 2540986ab12SMaksim Yevmenkin 2550986ab12SMaksim Yevmenkin rfcomm_proto_list_parse_exit(0); 2560986ab12SMaksim Yevmenkin /* NOT REACHED */ 2570986ab12SMaksim Yevmenkin next_protocol: 2580986ab12SMaksim Yevmenkin start += len; 2590986ab12SMaksim Yevmenkin } 2600986ab12SMaksim Yevmenkin 2610986ab12SMaksim Yevmenkin /* 2620986ab12SMaksim Yevmenkin * If we got here then it means we could not find RFCOMM protocol 2630986ab12SMaksim Yevmenkin * descriptor, but the reply format was actually valid. 2640986ab12SMaksim Yevmenkin */ 2650986ab12SMaksim Yevmenkin 2660986ab12SMaksim Yevmenkin rfcomm_proto_list_parse_exit(ENOATTR); 2670986ab12SMaksim Yevmenkin } 2680986ab12SMaksim Yevmenkin 269