1/* 2 * ssar.c 3 * 4 * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com> 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 * $Id: ssar.c,v 1.4 2004/01/12 22:54:31 max Exp $ 29 * $FreeBSD: stable/10/usr.sbin/bluetooth/sdpd/ssar.c 344146 2019-02-15 09:22:23Z hselasky $ 30 */ 31 32#include <sys/queue.h> 33#include <bluetooth.h> 34#include <sdp.h> 35#include <string.h> 36#include "profile.h" 37#include "provider.h" 38#include "server.h" 39#include "uuid-private.h" 40 41/* from sar.c */ 42int32_t server_prepare_attr_list(provider_p const provider, 43 uint8_t const *req, uint8_t const * const req_end, 44 uint8_t *rsp, uint8_t const * const rsp_end); 45 46/* 47 * Scan an attribute for matching UUID. 48 */ 49static int 50server_search_uuid_sub(uint8_t *buf, uint8_t const * const eob, const uint128_t *uuid) 51{ 52 int128_t duuid; 53 uint32_t value; 54 uint8_t type; 55 56 while (buf < eob) { 57 58 SDP_GET8(type, buf); 59 60 switch (type) { 61 case SDP_DATA_UUID16: 62 if (buf + 2 > eob) 63 continue; 64 SDP_GET16(value, buf); 65 66 memcpy(&duuid, &uuid_base, sizeof(duuid)); 67 duuid.b[2] = value >> 8 & 0xff; 68 duuid.b[3] = value & 0xff; 69 70 if (memcmp(&duuid, uuid, sizeof(duuid)) == 0) 71 return (0); 72 break; 73 case SDP_DATA_UUID32: 74 if (buf + 4 > eob) 75 continue; 76 SDP_GET32(value, buf); 77 memcpy(&duuid, &uuid_base, sizeof(duuid)); 78 duuid.b[0] = value >> 24 & 0xff; 79 duuid.b[1] = value >> 16 & 0xff; 80 duuid.b[2] = value >> 8 & 0xff; 81 duuid.b[3] = value & 0xff; 82 83 if (memcmp(&duuid, uuid, sizeof(duuid)) == 0) 84 return (0); 85 break; 86 case SDP_DATA_UUID128: 87 if (buf + 16 > eob) 88 continue; 89 SDP_GET_UUID128(&duuid, buf); 90 91 if (memcmp(&duuid, uuid, sizeof(duuid)) == 0) 92 return (0); 93 break; 94 case SDP_DATA_UINT8: 95 case SDP_DATA_INT8: 96 case SDP_DATA_SEQ8: 97 buf++; 98 break; 99 case SDP_DATA_UINT16: 100 case SDP_DATA_INT16: 101 case SDP_DATA_SEQ16: 102 buf += 2; 103 break; 104 case SDP_DATA_UINT32: 105 case SDP_DATA_INT32: 106 case SDP_DATA_SEQ32: 107 buf += 4; 108 break; 109 case SDP_DATA_UINT64: 110 case SDP_DATA_INT64: 111 buf += 8; 112 break; 113 case SDP_DATA_UINT128: 114 case SDP_DATA_INT128: 115 buf += 16; 116 break; 117 case SDP_DATA_STR8: 118 if (buf + 1 > eob) 119 continue; 120 SDP_GET8(value, buf); 121 buf += value; 122 break; 123 case SDP_DATA_STR16: 124 if (buf + 2 > eob) 125 continue; 126 SDP_GET16(value, buf); 127 if (value > (eob - buf)) 128 return (1); 129 buf += value; 130 break; 131 case SDP_DATA_STR32: 132 if (buf + 4 > eob) 133 continue; 134 SDP_GET32(value, buf); 135 if (value > (eob - buf)) 136 return (1); 137 buf += value; 138 break; 139 case SDP_DATA_BOOL: 140 buf += 1; 141 break; 142 default: 143 return (1); 144 } 145 } 146 return (1); 147} 148 149/* 150 * Search a provider for matching UUID in its attributes. 151 */ 152static int 153server_search_uuid(provider_p const provider, const uint128_t *uuid) 154{ 155 uint8_t buffer[256]; 156 const attr_t *attr; 157 int len; 158 159 for (attr = provider->profile->attrs; attr->create != NULL; attr++) { 160 161 len = attr->create(buffer, buffer + sizeof(buffer), 162 (const uint8_t *)provider->profile, sizeof(*provider->profile)); 163 if (len < 0) 164 continue; 165 if (server_search_uuid_sub(buffer, buffer + len, uuid) == 0) 166 return (0); 167 } 168 return (1); 169} 170 171/* 172 * Prepare SDP Service Search Attribute Response 173 */ 174 175int32_t 176server_prepare_service_search_attribute_response(server_p srv, int32_t fd) 177{ 178 uint8_t const *req = srv->req + sizeof(sdp_pdu_t); 179 uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len; 180 uint8_t *rsp = srv->fdidx[fd].rsp; 181 uint8_t const *rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM; 182 183 uint8_t const *sspptr = NULL, *aidptr = NULL; 184 uint8_t *ptr = NULL; 185 186 provider_t *provider = NULL; 187 int32_t type, rsp_limit, ssplen, aidlen, cslen, cs; 188 uint128_t uuid, puuid; 189 190 /* 191 * Minimal Service Search Attribute Request request 192 * 193 * seq8 len8 - 2 bytes 194 * uuid16 value16 - 3 bytes ServiceSearchPattern 195 * value16 - 2 bytes MaximumAttributeByteCount 196 * seq8 len8 - 2 bytes 197 * uint16 value16 - 3 bytes AttributeIDList 198 * value8 - 1 byte ContinuationState 199 */ 200 201 if (req_end - req < 13) 202 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 203 204 /* Get size of ServiceSearchPattern */ 205 ssplen = 0; 206 SDP_GET8(type, req); 207 switch (type) { 208 case SDP_DATA_SEQ8: 209 SDP_GET8(ssplen, req); 210 break; 211 212 case SDP_DATA_SEQ16: 213 SDP_GET16(ssplen, req); 214 break; 215 216 case SDP_DATA_SEQ32: 217 SDP_GET32(ssplen, req); 218 break; 219 } 220 if (ssplen <= 0) 221 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 222 223 sspptr = req; 224 req += ssplen; 225 226 /* Get MaximumAttributeByteCount */ 227 if (req + 2 > req_end) 228 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 229 230 SDP_GET16(rsp_limit, req); 231 if (rsp_limit <= 0) 232 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 233 234 /* Get size of AttributeIDList */ 235 if (req + 1 > req_end) 236 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 237 238 aidlen = 0; 239 SDP_GET8(type, req); 240 switch (type) { 241 case SDP_DATA_SEQ8: 242 if (req + 1 > req_end) 243 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 244 245 SDP_GET8(aidlen, req); 246 break; 247 248 case SDP_DATA_SEQ16: 249 if (req + 2 > req_end) 250 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 251 252 SDP_GET16(aidlen, req); 253 break; 254 255 case SDP_DATA_SEQ32: 256 if (req + 4 > req_end) 257 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 258 259 SDP_GET32(aidlen, req); 260 break; 261 } 262 if (aidlen <= 0) 263 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 264 265 aidptr = req; 266 req += aidlen; 267 268 /* Get ContinuationState */ 269 if (req + 1 > req_end) 270 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 271 272 SDP_GET8(cslen, req); 273 if (cslen != 0) { 274 if (cslen != 2 || req_end - req != 2) 275 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 276 277 SDP_GET16(cs, req); 278 } else 279 cs = 0; 280 281 /* Process the request. First, check continuation state */ 282 if (srv->fdidx[fd].rsp_cs != cs) 283 return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE); 284 if (srv->fdidx[fd].rsp_size > 0) 285 return (0); 286 287 /* 288 * Service Search Attribute Response format 289 * 290 * value16 - 2 bytes AttributeListByteCount (not incl.) 291 * seq8 len16 - 3 bytes 292 * attr list - 3+ bytes AttributeLists 293 * [ attr list ] 294 */ 295 296 ptr = rsp + 3; 297 298 while (ssplen > 0) { 299 SDP_GET8(type, sspptr); 300 ssplen --; 301 302 switch (type) { 303 case SDP_DATA_UUID16: 304 if (ssplen < 2) 305 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 306 307 memcpy(&uuid, &uuid_base, sizeof(uuid)); 308 uuid.b[2] = *sspptr ++; 309 uuid.b[3] = *sspptr ++; 310 ssplen -= 2; 311 break; 312 313 case SDP_DATA_UUID32: 314 if (ssplen < 4) 315 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 316 317 memcpy(&uuid, &uuid_base, sizeof(uuid)); 318 uuid.b[0] = *sspptr ++; 319 uuid.b[1] = *sspptr ++; 320 uuid.b[2] = *sspptr ++; 321 uuid.b[3] = *sspptr ++; 322 ssplen -= 4; 323 break; 324 325 case SDP_DATA_UUID128: 326 if (ssplen < 16) 327 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 328 329 memcpy(uuid.b, sspptr, 16); 330 sspptr += 16; 331 ssplen -= 16; 332 break; 333 334 default: 335 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 336 /* NOT REACHED */ 337 } 338 339 for (provider = provider_get_first(); 340 provider != NULL; 341 provider = provider_get_next(provider)) { 342 if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr)) 343 continue; 344 345 memcpy(&puuid, &uuid_base, sizeof(puuid)); 346 puuid.b[2] = provider->profile->uuid >> 8; 347 puuid.b[3] = provider->profile->uuid; 348 349 if (memcmp(&uuid, &puuid, sizeof(uuid)) != 0 && 350 memcmp(&uuid, &uuid_public_browse_group, sizeof(uuid)) != 0 && 351 server_search_uuid(provider, &uuid) != 0) 352 continue; 353 354 cs = server_prepare_attr_list(provider, 355 aidptr, aidptr + aidlen, ptr, rsp_end); 356 if (cs < 0) 357 return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES); 358 359 ptr += cs; 360 } 361 } 362 363 /* Set reply size (not counting PDU header and continuation state) */ 364 srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 2; 365 if (srv->fdidx[fd].rsp_limit > rsp_limit) 366 srv->fdidx[fd].rsp_limit = rsp_limit; 367 368 srv->fdidx[fd].rsp_size = ptr - rsp; 369 srv->fdidx[fd].rsp_cs = 0; 370 371 /* Fix AttributeLists sequence header */ 372 ptr = rsp; 373 SDP_PUT8(SDP_DATA_SEQ16, ptr); 374 SDP_PUT16(srv->fdidx[fd].rsp_size - 3, ptr); 375 376 return (0); 377} 378 379