Path: blob/main/usr.sbin/bluetooth/sdpd/profile.c
103755 views
/*1* profile.c2*/34/*-5* SPDX-License-Identifier: BSD-2-Clause6*7* Copyright (c) 2004 Maksim Yevmenkin <[email protected]>8* All rights reserved.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions and the following disclaimer.15* 2. Redistributions in binary form must reproduce the above copyright16* notice, this list of conditions and the following disclaimer in the17* documentation and/or other materials provided with the distribution.18*19* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND20* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE21* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE22* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE23* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL24* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS25* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT27* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY28* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF29* SUCH DAMAGE.30*31* $Id: profile.c,v 1.6 2004/01/13 19:31:54 max Exp $32*/3334#include <sys/param.h>35#include <sys/queue.h>36#define L2CAP_SOCKET_CHECKED37#include <bluetooth.h>38#include <sdp.h>39#include <string.h>40#include "profile.h"41#include "provider.h"4243/*44* Lookup profile descriptor45*/4647profile_p48profile_get_descriptor(uint16_t uuid)49{50extern profile_t audio_sink_profile_descriptor;51extern profile_t audio_source_profile_descriptor;52extern profile_t dun_profile_descriptor;53extern profile_t ftrn_profile_descriptor;54extern profile_t irmc_profile_descriptor;55extern profile_t irmc_command_profile_descriptor;56extern profile_t lan_profile_descriptor;57extern profile_t opush_profile_descriptor;58extern profile_t sp_profile_descriptor;59extern profile_t nap_profile_descriptor;60extern profile_t gn_profile_descriptor;61extern profile_t panu_profile_descriptor;6263static const profile_p profiles[] = {64&audio_sink_profile_descriptor,65&audio_source_profile_descriptor,66&dun_profile_descriptor,67&ftrn_profile_descriptor,68&irmc_profile_descriptor,69&irmc_command_profile_descriptor,70&lan_profile_descriptor,71&opush_profile_descriptor,72&sp_profile_descriptor,73&nap_profile_descriptor,74&gn_profile_descriptor,75&panu_profile_descriptor76};7778int32_t i;7980for (i = 0; i < nitems(profiles); i++)81if (profiles[i]->uuid == uuid)82return (profiles[i]);8384return (NULL);85}8687/*88* Look attribute in the profile descripror89*/9091profile_attr_create_p92profile_get_attr(const profile_p profile, uint16_t attr)93{94attr_p ad = (attr_p) profile->attrs;9596for (; ad->create != NULL; ad ++)97if (ad->attr == attr)98return (ad->create);99100return (NULL);101}102103/*104* uint32 value32 - 5 bytes105*/106107int32_t108common_profile_create_service_record_handle(109uint8_t *buf, uint8_t const * const eob,110uint8_t const *data, uint32_t datalen)111{112if (buf + 5 > eob)113return (-1);114115SDP_PUT8(SDP_DATA_UINT32, buf);116SDP_PUT32(((provider_p) data)->handle, buf);117118return (5);119}120121/*122* seq8 len8 - 2 bytes123* uuid16 value16 - 3 bytes124* [ uuid16 value ]125*/126127int32_t128common_profile_create_service_class_id_list(129uint8_t *buf, uint8_t const * const eob,130uint8_t const *data, uint32_t datalen)131{132int32_t len = 3 * (datalen >>= 1);133134if (len <= 0 || len > 0xff || buf + 2 + len > eob)135return (-1);136137SDP_PUT8(SDP_DATA_SEQ8, buf);138SDP_PUT8(len, buf);139140for (; datalen > 0; datalen --) {141SDP_PUT8(SDP_DATA_UUID16, buf);142SDP_PUT16(*((uint16_t const *)data), buf);143data += sizeof(uint16_t);144}145146return (2 + len);147}148149/*150* seq8 len8 - 2 bytes151* seq 8 len8 - 2 bytes152* uuid16 value16 - 3 bytes153* uint16 value16 - 3 bytes154* [ seq 8 len8155* uuid16 value16156* uint16 value16 ]157*/158159int32_t160common_profile_create_bluetooth_profile_descriptor_list(161uint8_t *buf, uint8_t const * const eob,162uint8_t const *data, uint32_t datalen)163{164int32_t len = 8 * (datalen >>= 2);165166if (len <= 0 || len > 0xff || buf + 2 + len > eob)167return (-1);168169SDP_PUT8(SDP_DATA_SEQ8, buf);170SDP_PUT8(len, buf);171172for (; datalen > 0; datalen --) {173SDP_PUT8(SDP_DATA_SEQ8, buf);174SDP_PUT8(6, buf);175SDP_PUT8(SDP_DATA_UUID16, buf);176SDP_PUT16(*((uint16_t const *)data), buf);177data += sizeof(uint16_t);178SDP_PUT8(SDP_DATA_UINT16, buf);179SDP_PUT16(*((uint16_t const *)data), buf);180data += sizeof(uint16_t);181}182183return (2 + len);184}185186/*187* seq8 len8 - 2 bytes188* uint16 value16 - 3 bytes189* uint16 value16 - 3 bytes190* uint16 value16 - 3 bytes191*/192193int32_t194common_profile_create_language_base_attribute_id_list(195uint8_t *buf, uint8_t const * const eob,196uint8_t const *data, uint32_t datalen)197{198if (buf + 11 > eob)199return (-1);200201SDP_PUT8(SDP_DATA_SEQ8, buf);202SDP_PUT8(9, buf);203204/*205* Language code per ISO 639:1988. Use "en".206*/207208SDP_PUT8(SDP_DATA_UINT16, buf);209SDP_PUT16(((0x65 << 8) | 0x6e), buf);210211/*212* Encoding. Recommended is UTF-8. ISO639 UTF-8 MIBenum is 106213* (http://www.iana.org/assignments/character-sets)214*/215216SDP_PUT8(SDP_DATA_UINT16, buf);217SDP_PUT16(106, buf);218219/*220* Offset (Primary Language Base is 0x100)221*/222223SDP_PUT8(SDP_DATA_UINT16, buf);224SDP_PUT16(SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID, buf);225226return (11);227}228229/*230* Common provider name is "FreeBSD"231*/232233int32_t234common_profile_create_service_provider_name(235uint8_t *buf, uint8_t const * const eob,236uint8_t const *data, uint32_t datalen)237{238char provider_name[] = "FreeBSD";239240return (common_profile_create_string8(buf, eob,241(uint8_t const *) provider_name,242strlen(provider_name)));243}244245/*246* str8 len8 string247*/248249int32_t250common_profile_create_string8(251uint8_t *buf, uint8_t const * const eob,252uint8_t const *data, uint32_t datalen)253{254if (datalen == 0 || datalen > 0xff || buf + 2 + datalen > eob)255return (-1);256257SDP_PUT8(SDP_DATA_STR8, buf);258SDP_PUT8(datalen, buf);259memcpy(buf, data, datalen);260261return (2 + datalen);262}263264/*265* Service Availability266*/267268int32_t269common_profile_create_service_availability(270uint8_t *buf, uint8_t const * const eob,271uint8_t const *data, uint32_t datalen)272{273if (datalen != 1 || buf + 2 > eob)274return (-1);275276SDP_PUT8(SDP_DATA_UINT8, buf);277SDP_PUT8(data[0], buf);278279return (2);280}281282/*283* seq8 len8 - 2 bytes284* seq8 len8 - 2 bytes285* uuid16 value16 - 3 bytes286* seq8 len8 - 2 bytes287* uuid16 value16 - 3 bytes288* uint8 value8 - 2 bytes289*/290291int32_t292rfcomm_profile_create_protocol_descriptor_list(293uint8_t *buf, uint8_t const * const eob,294uint8_t const *data, uint32_t datalen)295{296if (datalen != 1 || buf + 14 > eob)297return (-1);298299SDP_PUT8(SDP_DATA_SEQ8, buf);300SDP_PUT8(12, buf);301302SDP_PUT8(SDP_DATA_SEQ8, buf);303SDP_PUT8(3, buf);304SDP_PUT8(SDP_DATA_UUID16, buf);305SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);306307SDP_PUT8(SDP_DATA_SEQ8, buf);308SDP_PUT8(5, buf);309SDP_PUT8(SDP_DATA_UUID16, buf);310SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);311SDP_PUT8(SDP_DATA_UINT8, buf);312SDP_PUT8(*data, buf);313314return (14);315}316317/*318* seq8 len8 - 2 bytes319* seq8 len8 - 2 bytes320* uuid16 value16 - 3 bytes321* seq8 len8 - 2 bytes322* uuid16 value16 - 3 bytes323* uint8 value8 - 2 bytes324* seq8 len8 - 2 bytes325* uuid16 value16 - 3 bytes326*/327328int32_t329obex_profile_create_protocol_descriptor_list(330uint8_t *buf, uint8_t const * const eob,331uint8_t const *data, uint32_t datalen)332{333if (datalen != 1 || buf + 19 > eob)334return (-1);335336SDP_PUT8(SDP_DATA_SEQ8, buf);337SDP_PUT8(17, buf);338339SDP_PUT8(SDP_DATA_SEQ8, buf);340SDP_PUT8(3, buf);341SDP_PUT8(SDP_DATA_UUID16, buf);342SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);343344SDP_PUT8(SDP_DATA_SEQ8, buf);345SDP_PUT8(5, buf);346SDP_PUT8(SDP_DATA_UUID16, buf);347SDP_PUT16(SDP_UUID_PROTOCOL_RFCOMM, buf);348SDP_PUT8(SDP_DATA_UINT8, buf);349SDP_PUT8(*data, buf);350351SDP_PUT8(SDP_DATA_SEQ8, buf);352SDP_PUT8(3, buf);353SDP_PUT8(SDP_DATA_UUID16, buf);354SDP_PUT16(SDP_UUID_PROTOCOL_OBEX, buf);355356return (19);357}358359/*360* seq8 len8361* uint8 value8 - bytes362* [ uint8 value 8 ]363*/364365int32_t366obex_profile_create_supported_formats_list(367uint8_t *buf, uint8_t const * const eob,368uint8_t const *data, uint32_t datalen)369{370int32_t len = 2 * datalen;371372if (len <= 0 || len > 0xff || buf + 2 + len > eob)373return (-1);374375SDP_PUT8(SDP_DATA_SEQ8, buf);376SDP_PUT8(len, buf);377378for (; datalen > 0; datalen --) {379SDP_PUT8(SDP_DATA_UINT8, buf);380SDP_PUT8(*data++, buf);381}382383return (2 + len);384}385386/*387* do not check anything388*/389390int32_t391common_profile_always_valid(uint8_t const *data, uint32_t datalen)392{393return (1);394}395396/*397* verify server channel number (the first byte in the data)398*/399400int32_t401common_profile_server_channel_valid(uint8_t const *data, uint32_t datalen)402{403if (data[0] < 1 || data[0] > 30)404return (0);405406return (1);407}408409/*410* verify server channel number and supported_formats_size411* sdp_opush_profile and sdp_irmc_profile412*/413414int32_t415obex_profile_data_valid(uint8_t const *data, uint32_t datalen)416{417sdp_opush_profile_p opush = (sdp_opush_profile_p) data;418419if (opush->server_channel < 1 ||420opush->server_channel > 30 ||421opush->supported_formats_size == 0 ||422opush->supported_formats_size > sizeof(opush->supported_formats))423return (0);424425return (1);426}427428/*429* BNEP protocol descriptor430*/431432int32_t433bnep_profile_create_protocol_descriptor_list(434uint8_t *buf, uint8_t const * const eob,435uint8_t const *data, uint32_t datalen)436{437/* supported protocol types */438uint16_t ptype[] = {4390x0800, /* IPv4 */4400x0806, /* ARP */441#ifdef INET64420x86dd, /* IPv6 */443#endif444};445446uint16_t i, psm, version = 0x0100,447nptypes = nitems(ptype),448nptypes_size = nptypes * 3;449450if (datalen != 2 || 18 + nptypes_size > 255 ||451buf + 20 + nptypes_size > eob)452return (-1);453454memcpy(&psm, data, sizeof(psm));455456SDP_PUT8(SDP_DATA_SEQ8, buf);457SDP_PUT8(18 + nptypes_size, buf);458459SDP_PUT8(SDP_DATA_SEQ8, buf);460SDP_PUT8(6, buf);461SDP_PUT8(SDP_DATA_UUID16, buf);462SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf);463SDP_PUT8(SDP_DATA_UINT16, buf);464SDP_PUT16(psm, buf);465466SDP_PUT8(SDP_DATA_SEQ8, buf);467SDP_PUT8(8 + nptypes_size, buf);468SDP_PUT8(SDP_DATA_UUID16, buf);469SDP_PUT16(SDP_UUID_PROTOCOL_BNEP, buf);470SDP_PUT8(SDP_DATA_UINT16, buf);471SDP_PUT16(version, buf);472SDP_PUT8(SDP_DATA_SEQ8, buf);473SDP_PUT8(nptypes_size, buf);474for (i = 0; i < nptypes; i ++) {475SDP_PUT8(SDP_DATA_UINT16, buf);476SDP_PUT16(ptype[i], buf);477}478479return (20 + nptypes_size);480}481482/*483* BNEP security description484*/485486int32_t487bnep_profile_create_security_description(488uint8_t *buf, uint8_t const * const eob,489uint8_t const *data, uint32_t datalen)490{491uint16_t security_descr;492493if (datalen != 2 || buf + 3 > eob)494return (-1);495496memcpy(&security_descr, data, sizeof(security_descr));497498SDP_PUT8(SDP_DATA_UINT16, buf);499SDP_PUT16(security_descr, buf);500501return (3);502}503504505506