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 29 #include <sys/queue.h> 30 #define L2CAP_SOCKET_CHECKED 31 #include <bluetooth.h> 32 #include <sdp.h> 33 #include <string.h> 34 #include "profile.h" 35 #include "provider.h" 36 37 static int32_t 38 audio_sink_profile_create_service_class_id_list( 39 uint8_t *buf, uint8_t const *const eob, 40 uint8_t const *data, uint32_t datalen) 41 { 42 static const uint16_t service_classes[] = { 43 SDP_SERVICE_CLASS_AUDIO_SINK, 44 }; 45 46 return (common_profile_create_service_class_id_list( 47 buf, eob, 48 (uint8_t const *)service_classes, 49 sizeof(service_classes))); 50 } 51 52 static int32_t 53 audio_sink_profile_create_protocol_descriptor_list( 54 uint8_t *buf, uint8_t const *const eob, 55 uint8_t const *data, uint32_t datalen) 56 { 57 provider_p provider = (provider_p) data; 58 sdp_audio_sink_profile_p audio_sink = (sdp_audio_sink_profile_p) provider->data; 59 60 if (buf + 18 > eob) 61 return (-1); 62 63 SDP_PUT8(SDP_DATA_SEQ8, buf); 64 SDP_PUT8(16, buf); 65 66 SDP_PUT8(SDP_DATA_SEQ8, buf); 67 SDP_PUT8(6, buf); 68 69 SDP_PUT8(SDP_DATA_UUID16, buf); 70 SDP_PUT16(SDP_UUID_PROTOCOL_L2CAP, buf); 71 72 SDP_PUT8(SDP_DATA_UINT16, buf); 73 SDP_PUT16(audio_sink->psm, buf); 74 75 SDP_PUT8(SDP_DATA_SEQ8, buf); 76 SDP_PUT8(6, buf); 77 78 SDP_PUT8(SDP_DATA_UUID16, buf); 79 SDP_PUT16(SDP_UUID_PROTOCOL_AVDTP, buf); 80 81 SDP_PUT8(SDP_DATA_UINT16, buf); 82 SDP_PUT16(audio_sink->protover, buf); 83 84 return (18); 85 } 86 87 static int32_t 88 audio_sink_profile_create_browse_group_list( 89 uint8_t *buf, uint8_t const *const eob, 90 uint8_t const *data, uint32_t datalen) 91 { 92 93 if (buf + 5 > eob) 94 return (-1); 95 96 SDP_PUT8(SDP_DATA_SEQ8, buf); 97 SDP_PUT8(3, buf); 98 99 SDP_PUT8(SDP_DATA_UUID16, buf); 100 SDP_PUT16(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP, buf); 101 102 return (5); 103 } 104 105 static int32_t 106 audio_sink_profile_create_bluetooth_profile_descriptor_list( 107 uint8_t *buf, uint8_t const *const eob, 108 uint8_t const *data, uint32_t datalen) 109 { 110 static const uint16_t profile_descriptor_list[] = { 111 SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION, 112 0x0100 113 }; 114 115 return (common_profile_create_bluetooth_profile_descriptor_list( 116 buf, eob, 117 (uint8_t const *)profile_descriptor_list, 118 sizeof(profile_descriptor_list))); 119 } 120 121 static int32_t 122 audio_sink_profile_create_service_name( 123 uint8_t *buf, uint8_t const *const eob, 124 uint8_t const *data, uint32_t datalen) 125 { 126 static const char service_name[] = "Audio SNK"; 127 128 return (common_profile_create_string8( 129 buf, eob, 130 (uint8_t const *)service_name, strlen(service_name))); 131 } 132 133 static int32_t 134 audio_sink_create_supported_features( 135 uint8_t *buf, uint8_t const *const eob, 136 uint8_t const *data, uint32_t datalen) 137 { 138 provider_p provider = (provider_p) data; 139 sdp_audio_sink_profile_p audio_sink = (sdp_audio_sink_profile_p) provider->data; 140 141 if (buf + 3 > eob) 142 return (-1); 143 144 SDP_PUT8(SDP_DATA_UINT16, buf); 145 SDP_PUT16(audio_sink->features, buf); 146 147 return (3); 148 } 149 150 static int32_t 151 audio_sink_profile_valid(uint8_t const *data, uint32_t datalen) 152 { 153 154 if (datalen < sizeof(struct sdp_audio_sink_profile)) 155 return (0); 156 return (1); 157 } 158 159 static const attr_t audio_sink_profile_attrs[] = { 160 {SDP_ATTR_SERVICE_RECORD_HANDLE, 161 common_profile_create_service_record_handle}, 162 {SDP_ATTR_SERVICE_CLASS_ID_LIST, 163 audio_sink_profile_create_service_class_id_list}, 164 {SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 165 audio_sink_profile_create_protocol_descriptor_list}, 166 {SDP_ATTR_BROWSE_GROUP_LIST, 167 audio_sink_profile_create_browse_group_list}, 168 {SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST, 169 common_profile_create_language_base_attribute_id_list}, 170 {SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST, 171 audio_sink_profile_create_bluetooth_profile_descriptor_list}, 172 {SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_SERVICE_NAME_OFFSET, 173 audio_sink_profile_create_service_name}, 174 {SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID + SDP_ATTR_PROVIDER_NAME_OFFSET, 175 common_profile_create_service_provider_name}, 176 {SDP_ATTR_SUPPORTED_FEATURES, 177 audio_sink_create_supported_features}, 178 {} /* end entry */ 179 }; 180 181 profile_t audio_sink_profile_descriptor = { 182 SDP_SERVICE_CLASS_AUDIO_SINK, 183 sizeof(sdp_audio_sink_profile_t), 184 audio_sink_profile_valid, 185 (attr_t const *const)&audio_sink_profile_attrs 186 }; 187