xref: /freebsd/usr.sbin/bluetooth/sdpd/ssar.c (revision 6b3455a7665208c366849f0b2b3bc916fb97516e)
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$
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 
40 /* from sar.c */
41 int32_t server_prepare_attr_list(provider_p const provider,
42 		uint8_t const *req, uint8_t const * const req_end,
43 		uint8_t *rsp, uint8_t const * const rsp_end);
44 
45 /*
46  * Prepare SDP Service Search Attribute Response
47  */
48 
49 int32_t
50 server_prepare_service_search_attribute_response(server_p srv, int32_t fd)
51 {
52 	uint8_t const	*req = srv->req + sizeof(sdp_pdu_t);
53 	uint8_t const	*req_end = req + ((sdp_pdu_p)(srv->req))->len;
54 	uint8_t		*rsp = srv->fdidx[fd].rsp;
55 	uint8_t const	*rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM;
56 
57 	uint8_t const	*sspptr = NULL, *aidptr = NULL;
58 	uint8_t		*ptr = NULL;
59 
60 	provider_t	*provider = NULL;
61 	int32_t		 type, rsp_limit, ssplen, aidlen, cslen, cs, uuid;
62 
63 	/*
64 	 * Minimal Service Search Attribute Request request
65 	 *
66 	 * seq8 len8		- 2 bytes
67 	 *	uuid16 value16  - 3 bytes ServiceSearchPattern
68 	 * value16		- 2 bytes MaximumAttributeByteCount
69 	 * seq8 len8		- 2 bytes
70 	 *	uint16 value16	- 3 bytes AttributeIDList
71 	 * value8		- 1 byte  ContinuationState
72 	 */
73 
74 	if (req_end - req < 13)
75 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
76 
77 	/* Get size of ServiceSearchPattern */
78 	ssplen = 0;
79 	SDP_GET8(type, req);
80 	switch (type) {
81 	case SDP_DATA_SEQ8:
82 		SDP_GET8(ssplen, req);
83 		break;
84 
85 	case SDP_DATA_SEQ16:
86 		SDP_GET16(ssplen, req);
87 		break;
88 
89 	case SDP_DATA_SEQ32:
90 		SDP_GET32(ssplen, req);
91 		break;
92 	}
93 	if (ssplen <= 0)
94 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
95 
96 	sspptr = req;
97 	req += ssplen;
98 
99 	/* Get MaximumAttributeByteCount */
100 	if (req + 2 > req_end)
101 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
102 
103 	SDP_GET16(rsp_limit, req);
104 	if (rsp_limit <= 0)
105 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
106 
107 	/* Get size of AttributeIDList */
108 	if (req + 1 > req_end)
109 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
110 
111 	aidlen = 0;
112 	SDP_GET8(type, req);
113 	switch (type) {
114 	case SDP_DATA_SEQ8:
115 		if (req + 1 > req_end)
116 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
117 
118 		SDP_GET8(aidlen, req);
119 		break;
120 
121 	case SDP_DATA_SEQ16:
122 		if (req + 2 > req_end)
123 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
124 
125 		SDP_GET16(aidlen, req);
126 		break;
127 
128 	case SDP_DATA_SEQ32:
129 		if (req + 4 > req_end)
130 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
131 
132 		SDP_GET32(aidlen, req);
133 		break;
134 	}
135 	if (aidlen <= 0)
136 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
137 
138 	aidptr = req;
139 	req += aidlen;
140 
141 	/* Get ContinuationState */
142 	if (req + 1 > req_end)
143 		return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
144 
145 	SDP_GET8(cslen, req);
146 	if (cslen != 0) {
147 		if (cslen != 2 || req_end - req != 2)
148 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
149 
150 		SDP_GET16(cs, req);
151 	} else
152 		cs = 0;
153 
154 	/* Process the request. First, check continuation state */
155 	if (srv->fdidx[fd].rsp_cs != cs)
156 		return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE);
157 	if (srv->fdidx[fd].rsp_size > 0)
158 		return (0);
159 
160 	/*
161 	 * Service Search Attribute Response format
162 	 *
163 	 * value16		- 2 bytes  AttributeListByteCount (not incl.)
164 	 * seq8 len16		- 3 bytes
165 	 *	attr list	- 3+ bytes AttributeLists
166 	 *	[ attr list ]
167 	 */
168 
169 	ptr = rsp + 3;
170 
171 	while (ssplen > 0) {
172 		SDP_GET8(type, sspptr);
173 		ssplen --;
174 
175 		switch (type) {
176 		case SDP_DATA_UUID16:
177 			if (ssplen < 2)
178 				return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
179 
180 			SDP_GET16(uuid, sspptr);
181 			ssplen -= 2;
182 			break;
183 
184 		case SDP_DATA_UUID32: /* XXX FIXME */
185 		case SDP_DATA_UUID128: /* XXX FIXME */
186 		default:
187 			return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX);
188 			/* NOT REACHED */
189 		}
190 
191 		for (provider = provider_get_first();
192 		     provider != NULL;
193 		     provider = provider_get_next(provider)) {
194 			if (!provider_match_bdaddr(provider, &srv->req_sa.l2cap_bdaddr))
195 				continue;
196 
197 			if (provider->profile->uuid != uuid &&
198 			    SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP != uuid)
199 				continue;
200 
201 			cs = server_prepare_attr_list(provider,
202 				aidptr, aidptr + aidlen, ptr, rsp_end);
203 			if (cs < 0)
204 				return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES);
205 
206 			ptr += cs;
207 		}
208 	}
209 
210 	/* Set reply size (not counting PDU header and continuation state) */
211 	srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 2;
212 	if (srv->fdidx[fd].rsp_limit > rsp_limit)
213 		srv->fdidx[fd].rsp_limit = rsp_limit;
214 
215 	srv->fdidx[fd].rsp_size = ptr - rsp;
216 	srv->fdidx[fd].rsp_cs = 0;
217 
218 	/* Fix AttributeLists sequence header */
219 	ptr = rsp;
220 	SDP_PUT8(SDP_DATA_SEQ16, ptr);
221 	SDP_PUT16(srv->fdidx[fd].rsp_size - 3, ptr);
222 
223 	return (0);
224 }
225 
226