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