xref: /freebsd-src/usr.sbin/bluetooth/sdpd/ssar.c (revision 42b388439bd3795e09258c57a74ce9eec3651c7b)
11de7b4b8SPedro F. Giffuni /*-
207be7a6cSMaksim Yevmenkin  * ssar.c
307be7a6cSMaksim Yevmenkin  *
4*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
51de7b4b8SPedro F. Giffuni  *
607be7a6cSMaksim Yevmenkin  * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
707be7a6cSMaksim Yevmenkin  * All rights reserved.
807be7a6cSMaksim Yevmenkin  *
907be7a6cSMaksim Yevmenkin  * Redistribution and use in source and binary forms, with or without
1007be7a6cSMaksim Yevmenkin  * modification, are permitted provided that the following conditions
1107be7a6cSMaksim Yevmenkin  * are met:
1207be7a6cSMaksim Yevmenkin  * 1. Redistributions of source code must retain the above copyright
1307be7a6cSMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer.
1407be7a6cSMaksim Yevmenkin  * 2. Redistributions in binary form must reproduce the above copyright
1507be7a6cSMaksim Yevmenkin  *    notice, this list of conditions and the following disclaimer in the
1607be7a6cSMaksim Yevmenkin  *    documentation and/or other materials provided with the distribution.
1707be7a6cSMaksim Yevmenkin  *
1807be7a6cSMaksim Yevmenkin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1907be7a6cSMaksim Yevmenkin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2007be7a6cSMaksim Yevmenkin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2107be7a6cSMaksim Yevmenkin  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2207be7a6cSMaksim Yevmenkin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2307be7a6cSMaksim Yevmenkin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2407be7a6cSMaksim Yevmenkin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2507be7a6cSMaksim Yevmenkin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2607be7a6cSMaksim Yevmenkin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2707be7a6cSMaksim Yevmenkin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2807be7a6cSMaksim Yevmenkin  * SUCH DAMAGE.
2907be7a6cSMaksim Yevmenkin  *
3007be7a6cSMaksim Yevmenkin  * $Id: ssar.c,v 1.4 2004/01/12 22:54:31 max Exp $
3107be7a6cSMaksim Yevmenkin  */
3207be7a6cSMaksim Yevmenkin 
3307be7a6cSMaksim Yevmenkin #include <sys/queue.h>
348d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
3507be7a6cSMaksim Yevmenkin #include <bluetooth.h>
3607be7a6cSMaksim Yevmenkin #include <sdp.h>
3707be7a6cSMaksim Yevmenkin #include <string.h>
3807be7a6cSMaksim Yevmenkin #include "profile.h"
3907be7a6cSMaksim Yevmenkin #include "provider.h"
4007be7a6cSMaksim Yevmenkin #include "server.h"
41ee935b58SMaksim Yevmenkin #include "uuid-private.h"
4207be7a6cSMaksim Yevmenkin 
4307be7a6cSMaksim Yevmenkin /* from sar.c */
4407be7a6cSMaksim Yevmenkin int32_t server_prepare_attr_list(provider_p const provider,
4507be7a6cSMaksim Yevmenkin 		uint8_t const *req, uint8_t const * const req_end,
4607be7a6cSMaksim Yevmenkin 		uint8_t *rsp, uint8_t const * const rsp_end);
4707be7a6cSMaksim Yevmenkin 
4807be7a6cSMaksim Yevmenkin /*
492d3a84f5SHans Petter Selasky  * Scan an attribute for matching UUID.
502d3a84f5SHans Petter Selasky  */
512d3a84f5SHans Petter Selasky static int
server_search_uuid_sub(uint8_t * buf,uint8_t const * const eob,const uint128_t * uuid)522d3a84f5SHans Petter Selasky server_search_uuid_sub(uint8_t *buf, uint8_t const * const eob, const uint128_t *uuid)
532d3a84f5SHans Petter Selasky {
542d3a84f5SHans Petter Selasky         int128_t duuid;
552d3a84f5SHans Petter Selasky         uint32_t value;
562d3a84f5SHans Petter Selasky         uint8_t type;
572d3a84f5SHans Petter Selasky 
582d3a84f5SHans Petter Selasky         while (buf < eob) {
592d3a84f5SHans Petter Selasky 
602d3a84f5SHans Petter Selasky                 SDP_GET8(type, buf);
612d3a84f5SHans Petter Selasky 
622d3a84f5SHans Petter Selasky                 switch (type) {
632d3a84f5SHans Petter Selasky                 case SDP_DATA_UUID16:
642d3a84f5SHans Petter Selasky                         if (buf + 2 > eob)
652d3a84f5SHans Petter Selasky                                 continue;
662d3a84f5SHans Petter Selasky                         SDP_GET16(value, buf);
672d3a84f5SHans Petter Selasky 
682d3a84f5SHans Petter Selasky                         memcpy(&duuid, &uuid_base, sizeof(duuid));
692d3a84f5SHans Petter Selasky                         duuid.b[2] = value >> 8 & 0xff;
702d3a84f5SHans Petter Selasky                         duuid.b[3] = value & 0xff;
712d3a84f5SHans Petter Selasky 
722d3a84f5SHans Petter Selasky                         if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
732d3a84f5SHans Petter Selasky                                 return (0);
742d3a84f5SHans Petter Selasky                         break;
752d3a84f5SHans Petter Selasky                 case SDP_DATA_UUID32:
762d3a84f5SHans Petter Selasky                         if (buf + 4 > eob)
772d3a84f5SHans Petter Selasky                                 continue;
782d3a84f5SHans Petter Selasky                         SDP_GET32(value, buf);
792d3a84f5SHans Petter Selasky                         memcpy(&duuid, &uuid_base, sizeof(duuid));
802d3a84f5SHans Petter Selasky                         duuid.b[0] = value >> 24 & 0xff;
812d3a84f5SHans Petter Selasky                         duuid.b[1] = value >> 16 & 0xff;
822d3a84f5SHans Petter Selasky                         duuid.b[2] = value >> 8 & 0xff;
832d3a84f5SHans Petter Selasky                         duuid.b[3] = value & 0xff;
842d3a84f5SHans Petter Selasky 
852d3a84f5SHans Petter Selasky                         if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
862d3a84f5SHans Petter Selasky                                 return (0);
872d3a84f5SHans Petter Selasky                         break;
882d3a84f5SHans Petter Selasky                 case SDP_DATA_UUID128:
892d3a84f5SHans Petter Selasky                         if (buf + 16 > eob)
902d3a84f5SHans Petter Selasky                                 continue;
912d3a84f5SHans Petter Selasky                         SDP_GET_UUID128(&duuid, buf);
922d3a84f5SHans Petter Selasky 
932d3a84f5SHans Petter Selasky                         if (memcmp(&duuid, uuid, sizeof(duuid)) == 0)
942d3a84f5SHans Petter Selasky                                 return (0);
952d3a84f5SHans Petter Selasky                         break;
962d3a84f5SHans Petter Selasky                 case SDP_DATA_UINT8:
972d3a84f5SHans Petter Selasky                 case SDP_DATA_INT8:
982d3a84f5SHans Petter Selasky                 case SDP_DATA_SEQ8:
992d3a84f5SHans Petter Selasky                         buf++;
1002d3a84f5SHans Petter Selasky                         break;
1012d3a84f5SHans Petter Selasky                 case SDP_DATA_UINT16:
1022d3a84f5SHans Petter Selasky                 case SDP_DATA_INT16:
1032d3a84f5SHans Petter Selasky                 case SDP_DATA_SEQ16:
1042d3a84f5SHans Petter Selasky                         buf += 2;
1052d3a84f5SHans Petter Selasky                         break;
1062d3a84f5SHans Petter Selasky                 case SDP_DATA_UINT32:
1072d3a84f5SHans Petter Selasky                 case SDP_DATA_INT32:
1082d3a84f5SHans Petter Selasky                 case SDP_DATA_SEQ32:
1092d3a84f5SHans Petter Selasky                         buf += 4;
1102d3a84f5SHans Petter Selasky                         break;
1112d3a84f5SHans Petter Selasky                 case SDP_DATA_UINT64:
1122d3a84f5SHans Petter Selasky                 case SDP_DATA_INT64:
1132d3a84f5SHans Petter Selasky                         buf += 8;
1142d3a84f5SHans Petter Selasky                         break;
1152d3a84f5SHans Petter Selasky                 case SDP_DATA_UINT128:
1162d3a84f5SHans Petter Selasky                 case SDP_DATA_INT128:
1172d3a84f5SHans Petter Selasky                         buf += 16;
1182d3a84f5SHans Petter Selasky                         break;
1192d3a84f5SHans Petter Selasky                 case SDP_DATA_STR8:
1202d3a84f5SHans Petter Selasky                         if (buf + 1 > eob)
1212d3a84f5SHans Petter Selasky                                 continue;
1222d3a84f5SHans Petter Selasky                         SDP_GET8(value, buf);
1232d3a84f5SHans Petter Selasky                         buf += value;
1242d3a84f5SHans Petter Selasky                         break;
1252d3a84f5SHans Petter Selasky                 case SDP_DATA_STR16:
1262d3a84f5SHans Petter Selasky                         if (buf + 2 > eob)
1272d3a84f5SHans Petter Selasky                                 continue;
1282d3a84f5SHans Petter Selasky                         SDP_GET16(value, buf);
1292d3a84f5SHans Petter Selasky                         if (value > (eob - buf))
1302d3a84f5SHans Petter Selasky                                 return (1);
1312d3a84f5SHans Petter Selasky                         buf += value;
1322d3a84f5SHans Petter Selasky                         break;
1332d3a84f5SHans Petter Selasky                 case SDP_DATA_STR32:
1342d3a84f5SHans Petter Selasky                         if (buf + 4 > eob)
1352d3a84f5SHans Petter Selasky                                 continue;
1362d3a84f5SHans Petter Selasky                         SDP_GET32(value, buf);
1372d3a84f5SHans Petter Selasky                         if (value > (eob - buf))
1382d3a84f5SHans Petter Selasky                                 return (1);
1392d3a84f5SHans Petter Selasky                         buf += value;
1402d3a84f5SHans Petter Selasky                         break;
1412d3a84f5SHans Petter Selasky                 case SDP_DATA_BOOL:
1422d3a84f5SHans Petter Selasky                         buf += 1;
1432d3a84f5SHans Petter Selasky                         break;
1442d3a84f5SHans Petter Selasky                 default:
1452d3a84f5SHans Petter Selasky                         return (1);
1462d3a84f5SHans Petter Selasky                 }
1472d3a84f5SHans Petter Selasky         }
1482d3a84f5SHans Petter Selasky         return (1);
1492d3a84f5SHans Petter Selasky }
1502d3a84f5SHans Petter Selasky 
1512d3a84f5SHans Petter Selasky /*
1522d3a84f5SHans Petter Selasky  * Search a provider for matching UUID in its attributes.
1532d3a84f5SHans Petter Selasky  */
1542d3a84f5SHans Petter Selasky static int
server_search_uuid(provider_p const provider,const uint128_t * uuid)1552d3a84f5SHans Petter Selasky server_search_uuid(provider_p const provider, const uint128_t *uuid)
1562d3a84f5SHans Petter Selasky {
1572d3a84f5SHans Petter Selasky         uint8_t buffer[256];
1582d3a84f5SHans Petter Selasky         const attr_t *attr;
1592d3a84f5SHans Petter Selasky         int len;
1602d3a84f5SHans Petter Selasky 
1612d3a84f5SHans Petter Selasky         for (attr = provider->profile->attrs; attr->create != NULL; attr++) {
1622d3a84f5SHans Petter Selasky 
1632d3a84f5SHans Petter Selasky                 len = attr->create(buffer, buffer + sizeof(buffer),
1642d3a84f5SHans Petter Selasky                     (const uint8_t *)provider->profile, sizeof(*provider->profile));
1652d3a84f5SHans Petter Selasky                 if (len < 0)
1662d3a84f5SHans Petter Selasky                         continue;
1672d3a84f5SHans Petter Selasky                 if (server_search_uuid_sub(buffer, buffer + len, uuid) == 0)
1682d3a84f5SHans Petter Selasky                         return (0);
1692d3a84f5SHans Petter Selasky         }
1702d3a84f5SHans Petter Selasky         return (1);
1712d3a84f5SHans Petter Selasky }
1722d3a84f5SHans Petter Selasky 
1732d3a84f5SHans Petter Selasky /*
17407be7a6cSMaksim Yevmenkin  * Prepare SDP Service Search Attribute Response
17507be7a6cSMaksim Yevmenkin  */
17607be7a6cSMaksim Yevmenkin 
17707be7a6cSMaksim Yevmenkin int32_t
server_prepare_service_search_attribute_response(server_p srv,int32_t fd)17807be7a6cSMaksim Yevmenkin server_prepare_service_search_attribute_response(server_p srv, int32_t fd)
17907be7a6cSMaksim Yevmenkin {
18007be7a6cSMaksim Yevmenkin 	uint8_t const	*req = srv->req + sizeof(sdp_pdu_t);
18107be7a6cSMaksim Yevmenkin 	uint8_t const	*req_end = req + ((sdp_pdu_p)(srv->req))->len;
18207be7a6cSMaksim Yevmenkin 	uint8_t		*rsp = srv->fdidx[fd].rsp;
18307be7a6cSMaksim Yevmenkin 	uint8_t const	*rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
18407be7a6cSMaksim Yevmenkin 
18507be7a6cSMaksim Yevmenkin 	uint8_t const	*sspptr = NULL, *aidptr = NULL;
18607be7a6cSMaksim Yevmenkin 	uint8_t		*ptr = NULL;
18707be7a6cSMaksim Yevmenkin 
18807be7a6cSMaksim Yevmenkin 	provider_t	*provider = NULL;
189ee935b58SMaksim Yevmenkin 	int32_t		 type, rsp_limit, ssplen, aidlen, cslen, cs;
190ee935b58SMaksim Yevmenkin 	uint128_t	 uuid, puuid;
19107be7a6cSMaksim Yevmenkin 
19207be7a6cSMaksim Yevmenkin 	/*
19307be7a6cSMaksim Yevmenkin 	 * Minimal Service Search Attribute Request request
19407be7a6cSMaksim Yevmenkin 	 *
19507be7a6cSMaksim Yevmenkin 	 * seq8 len8		- 2 bytes
19607be7a6cSMaksim Yevmenkin 	 *	uuid16 value16  - 3 bytes ServiceSearchPattern
19707be7a6cSMaksim Yevmenkin 	 * value16		- 2 bytes MaximumAttributeByteCount
19807be7a6cSMaksim Yevmenkin 	 * seq8 len8		- 2 bytes
19907be7a6cSMaksim Yevmenkin 	 *	uint16 value16	- 3 bytes AttributeIDList
20007be7a6cSMaksim Yevmenkin 	 * value8		- 1 byte  ContinuationState
20107be7a6cSMaksim Yevmenkin 	 */
20207be7a6cSMaksim Yevmenkin 
20307be7a6cSMaksim Yevmenkin 	if (req_end - req < 13)
20407be7a6cSMaksim Yevmenkin 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
20507be7a6cSMaksim Yevmenkin 
20607be7a6cSMaksim Yevmenkin 	/* Get size of ServiceSearchPattern */
20707be7a6cSMaksim Yevmenkin 	ssplen = 0;
20807be7a6cSMaksim Yevmenkin 	SDP_GET8(type, req);
20907be7a6cSMaksim Yevmenkin 	switch (type) {
21007be7a6cSMaksim Yevmenkin 	case SDP_DATA_SEQ8:
21107be7a6cSMaksim Yevmenkin 		SDP_GET8(ssplen, req);
21207be7a6cSMaksim Yevmenkin 		break;
21307be7a6cSMaksim Yevmenkin 
21407be7a6cSMaksim Yevmenkin 	case SDP_DATA_SEQ16:
21507be7a6cSMaksim Yevmenkin 		SDP_GET16(ssplen, req);
21607be7a6cSMaksim Yevmenkin 		break;
21707be7a6cSMaksim Yevmenkin 
21807be7a6cSMaksim Yevmenkin 	case SDP_DATA_SEQ32:
21907be7a6cSMaksim Yevmenkin 		SDP_GET32(ssplen, req);
22007be7a6cSMaksim Yevmenkin 		break;
22107be7a6cSMaksim Yevmenkin 	}
22207be7a6cSMaksim Yevmenkin 	if (ssplen <= 0)
22307be7a6cSMaksim Yevmenkin 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
22407be7a6cSMaksim Yevmenkin 
22507be7a6cSMaksim Yevmenkin 	sspptr = req;
22607be7a6cSMaksim Yevmenkin 	req += ssplen;
22707be7a6cSMaksim Yevmenkin 
22807be7a6cSMaksim Yevmenkin 	/* Get MaximumAttributeByteCount */
22907be7a6cSMaksim Yevmenkin 	if (req + 2 > req_end)
23007be7a6cSMaksim Yevmenkin 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
23107be7a6cSMaksim Yevmenkin 
23207be7a6cSMaksim Yevmenkin 	SDP_GET16(rsp_limit, req);
23307be7a6cSMaksim Yevmenkin 	if (rsp_limit <= 0)
23407be7a6cSMaksim Yevmenkin 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
23507be7a6cSMaksim Yevmenkin 
23607be7a6cSMaksim Yevmenkin 	/* Get size of AttributeIDList */
23707be7a6cSMaksim Yevmenkin 	if (req + 1 > req_end)
23807be7a6cSMaksim Yevmenkin 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
23907be7a6cSMaksim Yevmenkin 
24007be7a6cSMaksim Yevmenkin 	aidlen = 0;
24107be7a6cSMaksim Yevmenkin 	SDP_GET8(type, req);
24207be7a6cSMaksim Yevmenkin 	switch (type) {
24307be7a6cSMaksim Yevmenkin 	case SDP_DATA_SEQ8:
24407be7a6cSMaksim Yevmenkin 		if (req + 1 > req_end)
24507be7a6cSMaksim Yevmenkin 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
24607be7a6cSMaksim Yevmenkin 
24707be7a6cSMaksim Yevmenkin 		SDP_GET8(aidlen, req);
24807be7a6cSMaksim Yevmenkin 		break;
24907be7a6cSMaksim Yevmenkin 
25007be7a6cSMaksim Yevmenkin 	case SDP_DATA_SEQ16:
25107be7a6cSMaksim Yevmenkin 		if (req + 2 > req_end)
25207be7a6cSMaksim Yevmenkin 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
25307be7a6cSMaksim Yevmenkin 
25407be7a6cSMaksim Yevmenkin 		SDP_GET16(aidlen, req);
25507be7a6cSMaksim Yevmenkin 		break;
25607be7a6cSMaksim Yevmenkin 
25707be7a6cSMaksim Yevmenkin 	case SDP_DATA_SEQ32:
25807be7a6cSMaksim Yevmenkin 		if (req + 4 > req_end)
25907be7a6cSMaksim Yevmenkin 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
26007be7a6cSMaksim Yevmenkin 
26107be7a6cSMaksim Yevmenkin 		SDP_GET32(aidlen, req);
26207be7a6cSMaksim Yevmenkin 		break;
26307be7a6cSMaksim Yevmenkin 	}
26407be7a6cSMaksim Yevmenkin 	if (aidlen <= 0)
26507be7a6cSMaksim Yevmenkin 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
26607be7a6cSMaksim Yevmenkin 
26707be7a6cSMaksim Yevmenkin 	aidptr = req;
26807be7a6cSMaksim Yevmenkin 	req += aidlen;
26907be7a6cSMaksim Yevmenkin 
27007be7a6cSMaksim Yevmenkin 	/* Get ContinuationState */
27107be7a6cSMaksim Yevmenkin 	if (req + 1 > req_end)
27207be7a6cSMaksim Yevmenkin 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
27307be7a6cSMaksim Yevmenkin 
27407be7a6cSMaksim Yevmenkin 	SDP_GET8(cslen, req);
27507be7a6cSMaksim Yevmenkin 	if (cslen != 0) {
27607be7a6cSMaksim Yevmenkin 		if (cslen != 2 || req_end - req != 2)
27707be7a6cSMaksim Yevmenkin 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
27807be7a6cSMaksim Yevmenkin 
27907be7a6cSMaksim Yevmenkin 		SDP_GET16(cs, req);
28007be7a6cSMaksim Yevmenkin 	} else
28107be7a6cSMaksim Yevmenkin 		cs = 0;
28207be7a6cSMaksim Yevmenkin 
28307be7a6cSMaksim Yevmenkin 	/* Process the request. First, check continuation state */
28407be7a6cSMaksim Yevmenkin 	if (srv->fdidx[fd].rsp_cs != cs)
28507be7a6cSMaksim Yevmenkin 		return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
28607be7a6cSMaksim Yevmenkin 	if (srv->fdidx[fd].rsp_size > 0)
28707be7a6cSMaksim Yevmenkin 		return (0);
28807be7a6cSMaksim Yevmenkin 
28907be7a6cSMaksim Yevmenkin 	/*
29007be7a6cSMaksim Yevmenkin 	 * Service Search Attribute Response format
29107be7a6cSMaksim Yevmenkin 	 *
29207be7a6cSMaksim Yevmenkin 	 * value16		- 2 bytes  AttributeListByteCount (not incl.)
29307be7a6cSMaksim Yevmenkin 	 * seq8 len16		- 3 bytes
29407be7a6cSMaksim Yevmenkin 	 *	attr list	- 3+ bytes AttributeLists
29507be7a6cSMaksim Yevmenkin 	 *	[ attr list ]
29607be7a6cSMaksim Yevmenkin 	 */
29707be7a6cSMaksim Yevmenkin 
29807be7a6cSMaksim Yevmenkin 	ptr = rsp + 3;
29907be7a6cSMaksim Yevmenkin 
30007be7a6cSMaksim Yevmenkin 	while (ssplen > 0) {
30107be7a6cSMaksim Yevmenkin 		SDP_GET8(type, sspptr);
30207be7a6cSMaksim Yevmenkin 		ssplen --;
30307be7a6cSMaksim Yevmenkin 
30407be7a6cSMaksim Yevmenkin 		switch (type) {
30507be7a6cSMaksim Yevmenkin 		case SDP_DATA_UUID16:
30607be7a6cSMaksim Yevmenkin 			if (ssplen < 2)
30707be7a6cSMaksim Yevmenkin 				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
30807be7a6cSMaksim Yevmenkin 
309ee935b58SMaksim Yevmenkin 			memcpy(&uuid, &uuid_base, sizeof(uuid));
310ee935b58SMaksim Yevmenkin 			uuid.b[2] = *sspptr ++;
311ee935b58SMaksim Yevmenkin 			uuid.b[3] = *sspptr ++;
31207be7a6cSMaksim Yevmenkin 			ssplen -= 2;
31307be7a6cSMaksim Yevmenkin 			break;
31407be7a6cSMaksim Yevmenkin 
315ee935b58SMaksim Yevmenkin 		case SDP_DATA_UUID32:
316ee935b58SMaksim Yevmenkin 			if (ssplen < 4)
317ee935b58SMaksim Yevmenkin 				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
318ee935b58SMaksim Yevmenkin 
319ee935b58SMaksim Yevmenkin 			memcpy(&uuid, &uuid_base, sizeof(uuid));
320ee935b58SMaksim Yevmenkin 			uuid.b[0] = *sspptr ++;
321ee935b58SMaksim Yevmenkin 			uuid.b[1] = *sspptr ++;
322ee935b58SMaksim Yevmenkin 			uuid.b[2] = *sspptr ++;
323ee935b58SMaksim Yevmenkin 			uuid.b[3] = *sspptr ++;
324ee935b58SMaksim Yevmenkin 			ssplen -= 4;
325ee935b58SMaksim Yevmenkin 			break;
326ee935b58SMaksim Yevmenkin 
327ee935b58SMaksim Yevmenkin 		case SDP_DATA_UUID128:
328ee935b58SMaksim Yevmenkin 			if (ssplen < 16)
329ee935b58SMaksim Yevmenkin 				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
330ee935b58SMaksim Yevmenkin 
331ee935b58SMaksim Yevmenkin 			memcpy(uuid.b, sspptr, 16);
332ee935b58SMaksim Yevmenkin 			sspptr += 16;
333ee935b58SMaksim Yevmenkin 			ssplen -= 16;
334ee935b58SMaksim Yevmenkin 			break;
335ee935b58SMaksim Yevmenkin 
33607be7a6cSMaksim Yevmenkin 		default:
33707be7a6cSMaksim Yevmenkin 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
33807be7a6cSMaksim Yevmenkin 			/* NOT REACHED */
33907be7a6cSMaksim Yevmenkin 		}
34007be7a6cSMaksim Yevmenkin 
34107be7a6cSMaksim Yevmenkin 		for (provider = provider_get_first();
34207be7a6cSMaksim Yevmenkin 		     provider != NULL;
34307be7a6cSMaksim Yevmenkin 		     provider = provider_get_next(provider)) {
34407be7a6cSMaksim Yevmenkin 			if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
34507be7a6cSMaksim Yevmenkin 				continue;
34607be7a6cSMaksim Yevmenkin 
347ee935b58SMaksim Yevmenkin 			memcpy(&puuid, &uuid_base, sizeof(puuid));
348ee935b58SMaksim Yevmenkin 			puuid.b[2] = provider->profile->uuid >> 8;
349ee935b58SMaksim Yevmenkin 			puuid.b[3] = provider->profile->uuid;
350ee935b58SMaksim Yevmenkin 
351ee935b58SMaksim Yevmenkin 			if (memcmp(&uuid, &puuid, sizeof(uuid)) != 0 &&
3522d3a84f5SHans Petter Selasky 			    memcmp(&uuid, &uuid_public_browse_group, sizeof(uuid)) != 0 &&
3532d3a84f5SHans Petter Selasky 			    server_search_uuid(provider, &uuid) != 0)
35407be7a6cSMaksim Yevmenkin 				continue;
35507be7a6cSMaksim Yevmenkin 
35607be7a6cSMaksim Yevmenkin 			cs = server_prepare_attr_list(provider,
35707be7a6cSMaksim Yevmenkin 				aidptr, aidptr + aidlen, ptr, rsp_end);
35807be7a6cSMaksim Yevmenkin 			if (cs < 0)
35907be7a6cSMaksim Yevmenkin 				return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
36007be7a6cSMaksim Yevmenkin 
36107be7a6cSMaksim Yevmenkin 			ptr += cs;
36207be7a6cSMaksim Yevmenkin 		}
36307be7a6cSMaksim Yevmenkin 	}
36407be7a6cSMaksim Yevmenkin 
36507be7a6cSMaksim Yevmenkin 	/* Set reply size (not counting PDU header and continuation state) */
36607be7a6cSMaksim Yevmenkin 	srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 2;
36707be7a6cSMaksim Yevmenkin 	if (srv->fdidx[fd].rsp_limit > rsp_limit)
36807be7a6cSMaksim Yevmenkin 		srv->fdidx[fd].rsp_limit = rsp_limit;
36907be7a6cSMaksim Yevmenkin 
37007be7a6cSMaksim Yevmenkin 	srv->fdidx[fd].rsp_size = ptr - rsp;
37107be7a6cSMaksim Yevmenkin 	srv->fdidx[fd].rsp_cs = 0;
37207be7a6cSMaksim Yevmenkin 
37307be7a6cSMaksim Yevmenkin 	/* Fix AttributeLists sequence header */
37407be7a6cSMaksim Yevmenkin 	ptr = rsp;
37507be7a6cSMaksim Yevmenkin 	SDP_PUT8(SDP_DATA_SEQ16, ptr);
37607be7a6cSMaksim Yevmenkin 	SDP_PUT16(srv->fdidx[fd].rsp_size - 3, ptr);
37707be7a6cSMaksim Yevmenkin 
37807be7a6cSMaksim Yevmenkin 	return (0);
37907be7a6cSMaksim Yevmenkin }
38007be7a6cSMaksim Yevmenkin 
381