1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019 Hans Petter Selasky <hselasky@freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/queue.h> 32 #define L2CAP_SOCKET_CHECKED 33 #include <bluetooth.h> 34 #include <sdp.h> 35 #include <string.h> 36 #include "profile.h" 37 #include "provider.h" 38 39 static int32_t 40 audio_sink_profile_create_service_class_id_list( 41 uint8_t *buf, uint8_t const *const eob, 42 uint8_t const *data, uint32_t datalen) 43 { 44 static const uint16_t service_classes[] = { 45 SDP_SERVICE_CLASS_AUDIO_SINK, 46 }; 47 48 return (common_profile_create_service_class_id_list( 49 buf, eob, 50 (uint8_t const *)service_classes, 51 sizeof(service_classes))); 52 } 53 54 static int32_t 55 audio_sink_profile_create_protocol_descriptor_list( 56 uint8_t *buf, uint8_t const *const eob, 57 uint8_t const *data, uint32_t datalen) 58 { 59 provider_p provider = (provider_p) data; 60 sdp_audio_sink_profile_p audio_sink = (sdp_audio_sink_profile_p) provider->data; 61 62 if (buf + 18 > eob) 63 return (-1); 64 65 SDP_PUT8(SDP_DATA_SEQ8, buf); 66 SDP_PUT8(16, buf); 67 68 SDP_PUT8(SDP_DATA_SEQ8, buf); 69 SDP_PUT8(6, buf); 70 71 SDP_PUT8(SDP_DATA_UUID16, buf); 72 SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf); 73 74 SDP_PUT8(SDP_DATA_UINT16, buf); 75 SDP_PUT16(audio_sink->psm, buf); 76 77 SDP_PUT8(SDP_DATA_SEQ8, buf); 78 SDP_PUT8(6, buf); 79 80 SDP_PUT8(SDP_DATA_UUID16, buf); 81 SDP_PUT16(SDP_UUID_PROTOCOL_AVDTP, buf); 82 83 SDP_PUT8(SDP_DATA_UINT16, buf); 84 SDP_PUT16(audio_sink->protover, buf); 85 86 return (18); 87 } 88 89 static int32_t 90 audio_sink_profile_create_browse_group_list( 91 uint8_t *buf, uint8_t const *const eob, 92 uint8_t const *data, uint32_t datalen) 93 { 94 95 if (buf + 5 > eob) 96 return (-1); 97 98 SDP_PUT8(SDP_DATA_SEQ8, buf); 99 SDP_PUT8(3, buf); 100 101 SDP_PUT8(SDP_DATA_UUID16, buf); 102 SDP_PUT16(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP, buf); 103 104 return (5); 105 } 106 107 static int32_t 108 audio_sink_profile_create_bluetooth_profile_descriptor_list( 109 uint8_t *buf, uint8_t const *const eob, 110 uint8_t const *data, uint32_t datalen) 111 { 112 static const uint16_t profile_descriptor_list[] = { 113 SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION, 114 0x0100 115 }; 116 117 return (common_profile_create_bluetooth_profile_descriptor_list( 118 buf, eob, 119 (uint8_t const *)profile_descriptor_list, 120 sizeof(profile_descriptor_list))); 121 } 122 123 static int32_t 124 audio_sink_profile_create_service_name( 125 uint8_t *buf, uint8_t const *const eob, 126 uint8_t const *data, uint32_t datalen) 127 { 128 static const char service_name[] = "Audio SNK"; 129 130 return (common_profile_create_string8( 131 buf, eob, 132 (uint8_t const *)service_name, strlen(service_name))); 133 } 134 135 static int32_t 136 audio_sink_create_supported_features( 137 uint8_t *buf, uint8_t const *const eob, 138 uint8_t const *data, uint32_t datalen) 139 { 140 provider_p provider = (provider_p) data; 141 sdp_audio_sink_profile_p audio_sink = (sdp_audio_sink_profile_p) provider->data; 142 143 if (buf + 3 > eob) 144 return (-1); 145 146 SDP_PUT8(SDP_DATA_UINT16, buf); 147 SDP_PUT16(audio_sink->features, buf); 148 149 return (3); 150 } 151 152 static int32_t 153 audio_sink_profile_valid(uint8_t const *data, uint32_t datalen) 154 { 155 156 if (datalen < sizeof(struct sdp_audio_sink_profile)) 157 return (0); 158 return (1); 159 } 160 161 static const attr_t audio_sink_profile_attrs[] = { 162 {SDP_ATTR_SERVICE_RECORD_HANDLE, 163 common_profile_create_service_record_handle}, 164 {SDP_ATTR_SERVICE_CLASS_ID_LIST, 165 audio_sink_profile_create_service_class_id_list}, 166 {SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 167 audio_sink_profile_create_protocol_descriptor_list}, 168 {SDP_ATTR_BROWSE_GROUP_LIST, 169 audio_sink_profile_create_browse_group_list}, 170 {SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST, 171 common_profile_create_language_base_attribute_id_list}, 172 {SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST, 173 audio_sink_profile_create_bluetooth_profile_descriptor_list}, 174 {SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET, 175 audio_sink_profile_create_service_name}, 176 {SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_PROVIDER_NAME_OFFSET, 177 common_profile_create_service_provider_name}, 178 {SDP_ATTR_SUPPORTED_FEATURES, 179 audio_sink_create_supported_features}, 180 {} /* end entry */ 181 }; 182 183 profile_t audio_sink_profile_descriptor = { 184 SDP_SERVICE_CLASS_AUDIO_SINK, 185 sizeof(sdp_audio_sink_profile_t), 186 audio_sink_profile_valid, 187 (attr_t const *const)&audio_sink_profile_attrs 188 }; 189