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