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