1 /*- 2 * sar.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: sar.c,v 1.2 2004/01/08 23:46:51 max Exp $ 31 */ 32 33 #include <sys/queue.h> 34 #include <sys/uio.h> 35 #include <netinet/in.h> 36 #include <arpa/inet.h> 37 #include <assert.h> 38 #define L2CAP_SOCKET_CHECKED 39 #include <bluetooth.h> 40 #include <errno.h> 41 #include <sdp.h> 42 #include <stdio.h> /* for NULL */ 43 #include "profile.h" 44 #include "provider.h" 45 #include "server.h" 46 47 /* 48 * Prepare SDP attr/value pair. Check if profile implements the attribute 49 * and if so call the attribute value function. 50 * 51 * uint16 value16 - 3 bytes (attribute) 52 * value - N bytes (value) 53 */ 54 55 static int32_t 56 server_prepare_attr_value_pair( 57 provider_p const provider, uint16_t attr, 58 uint8_t *buf, uint8_t const * const eob) 59 { 60 profile_attr_create_p cf = profile_get_attr(provider->profile, attr); 61 int32_t len; 62 63 if (cf == NULL) 64 return (0); /* no attribute */ 65 66 if (buf + 3 > eob) 67 return (-1); 68 69 SDP_PUT8(SDP_DATA_UINT16, buf); 70 SDP_PUT16(attr, buf); 71 72 len = cf(buf, eob, (uint8_t const *) provider, sizeof(*provider)); 73 if (len < 0) 74 return (-1); 75 76 return (3 + len); 77 } 78 79 /* 80 * seq16 value16 - 3 bytes 81 * attr value - 3+ bytes 82 * [ attr value ] 83 */ 84 85 int32_t 86 server_prepare_attr_list(provider_p const provider, 87 uint8_t const *req, uint8_t const * const req_end, 88 uint8_t *rsp, uint8_t const * const rsp_end) 89 { 90 uint8_t *ptr = rsp + 3; 91 int32_t type, hi, lo, len; 92 93 if (ptr > rsp_end) 94 return (-1); 95 96 while (req < req_end) { 97 SDP_GET8(type, req); 98 99 switch (type) { 100 case SDP_DATA_UINT16: 101 if (req + 2 > req_end) 102 return (-1); 103 104 SDP_GET16(lo, req); 105 hi = lo; 106 break; 107 108 case SDP_DATA_UINT32: 109 if (req + 4 > req_end) 110 return (-1); 111 112 SDP_GET16(lo, req); 113 SDP_GET16(hi, req); 114 break; 115 116 default: 117 return (-1); 118 /* NOT REACHED */ 119 } 120 121 for (; lo <= hi; lo ++) { 122 len = server_prepare_attr_value_pair(provider, lo, ptr, rsp_end); 123 if (len < 0) 124 return (-1); 125 126 ptr += len; 127 } 128 } 129 130 len = ptr - rsp; /* we put this much bytes in rsp */ 131 132 /* Fix SEQ16 header for the rsp */ 133 SDP_PUT8(SDP_DATA_SEQ16, rsp); 134 SDP_PUT16(len - 3, rsp); 135 136 return (len); 137 } 138 139 /* 140 * Prepare SDP Service Attribute Response 141 */ 142 143 int32_t 144 server_prepare_service_attribute_response(server_p srv, int32_t fd) 145 { 146 uint8_t const *req = srv->req + sizeof(sdp_pdu_t); 147 uint8_t const *req_end = req + ((sdp_pdu_p)(srv->req))->len; 148 uint8_t *rsp = srv->fdidx[fd].rsp; 149 uint8_t const *rsp_end = rsp + NG_L2CAP_MTU_MAXIMUM; 150 151 uint8_t *ptr = NULL; 152 provider_t *provider = NULL; 153 uint32_t handle; 154 int32_t type, rsp_limit, aidlen, cslen, cs; 155 156 /* 157 * Minimal Service Attribute Request request 158 * 159 * value32 - 4 bytes ServiceRecordHandle 160 * value16 - 2 bytes MaximumAttributeByteCount 161 * seq8 len8 - 2 bytes 162 * uint16 value16 - 3 bytes AttributeIDList 163 * value8 - 1 byte ContinuationState 164 */ 165 166 if (req_end - req < 12) 167 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 168 169 /* Get ServiceRecordHandle and MaximumAttributeByteCount */ 170 SDP_GET32(handle, req); 171 SDP_GET16(rsp_limit, req); 172 if (rsp_limit <= 0) 173 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 174 175 /* Get size of AttributeIDList */ 176 aidlen = 0; 177 SDP_GET8(type, req); 178 switch (type) { 179 case SDP_DATA_SEQ8: 180 SDP_GET8(aidlen, req); 181 break; 182 183 case SDP_DATA_SEQ16: 184 SDP_GET16(aidlen, req); 185 break; 186 187 case SDP_DATA_SEQ32: 188 SDP_GET32(aidlen, req); 189 break; 190 } 191 if (aidlen <= 0) 192 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 193 194 ptr = (uint8_t *) req + aidlen; 195 196 /* Get ContinuationState */ 197 if (ptr + 1 > req_end) 198 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 199 200 SDP_GET8(cslen, ptr); 201 if (cslen != 0) { 202 if (cslen != 2 || req_end - ptr != 2) 203 return (SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX); 204 205 SDP_GET16(cs, ptr); 206 } else 207 cs = 0; 208 209 /* Process the request. First, check continuation state */ 210 if (srv->fdidx[fd].rsp_cs != cs) 211 return (SDP_ERROR_CODE_INVALID_CONTINUATION_STATE); 212 if (srv->fdidx[fd].rsp_size > 0) 213 return (0); 214 215 /* Lookup record handle */ 216 if ((provider = provider_by_handle(handle)) == NULL) 217 return (SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE); 218 219 /* 220 * Service Attribute Response format 221 * 222 * value16 - 2 bytes AttributeListByteCount (not incl.) 223 * seq8 len16 - 3 bytes 224 * attr value - 3+ bytes AttributeList 225 * [ attr value ] 226 */ 227 228 cs = server_prepare_attr_list(provider, req, req+aidlen, rsp, rsp_end); 229 if (cs < 0) 230 return (SDP_ERROR_CODE_INSUFFICIENT_RESOURCES); 231 232 /* Set reply size (not counting PDU header and continuation state) */ 233 srv->fdidx[fd].rsp_limit = srv->fdidx[fd].omtu - sizeof(sdp_pdu_t) - 2; 234 if (srv->fdidx[fd].rsp_limit > rsp_limit) 235 srv->fdidx[fd].rsp_limit = rsp_limit; 236 237 srv->fdidx[fd].rsp_size = cs; 238 srv->fdidx[fd].rsp_cs = 0; 239 240 return (0); 241 } 242 243 /* 244 * Send SDP Service [Search] Attribute Response 245 */ 246 247 int32_t 248 server_send_service_attribute_response(server_p srv, int32_t fd) 249 { 250 uint8_t *rsp = srv->fdidx[fd].rsp + srv->fdidx[fd].rsp_cs; 251 uint8_t *rsp_end = srv->fdidx[fd].rsp + srv->fdidx[fd].rsp_size; 252 253 struct iovec iov[4]; 254 sdp_pdu_t pdu; 255 uint16_t bcount; 256 uint8_t cs[3]; 257 int32_t size; 258 259 /* First update continuation state (assume we will send all data) */ 260 size = rsp_end - rsp; 261 srv->fdidx[fd].rsp_cs += size; 262 263 if (size + 1 > srv->fdidx[fd].rsp_limit) { 264 /* 265 * We need to split out response. Add 3 more bytes for the 266 * continuation state and move rsp_end and rsp_cs backwards. 267 */ 268 269 while ((rsp_end - rsp) + 3 > srv->fdidx[fd].rsp_limit) { 270 rsp_end --; 271 srv->fdidx[fd].rsp_cs --; 272 } 273 274 cs[0] = 2; 275 cs[1] = srv->fdidx[fd].rsp_cs >> 8; 276 cs[2] = srv->fdidx[fd].rsp_cs & 0xff; 277 } else 278 cs[0] = 0; 279 280 assert(rsp_end >= rsp); 281 282 bcount = rsp_end - rsp; 283 284 if (((sdp_pdu_p)(srv->req))->pid == SDP_PDU_SERVICE_ATTRIBUTE_REQUEST) 285 pdu.pid = SDP_PDU_SERVICE_ATTRIBUTE_RESPONSE; 286 else 287 pdu.pid = SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_RESPONSE; 288 289 pdu.tid = ((sdp_pdu_p)(srv->req))->tid; 290 pdu.len = htons(sizeof(bcount) + bcount + 1 + cs[0]); 291 292 bcount = htons(bcount); 293 294 iov[0].iov_base = &pdu; 295 iov[0].iov_len = sizeof(pdu); 296 297 iov[1].iov_base = &bcount; 298 iov[1].iov_len = sizeof(bcount); 299 300 iov[2].iov_base = rsp; 301 iov[2].iov_len = rsp_end - rsp; 302 303 iov[3].iov_base = cs; 304 iov[3].iov_len = 1 + cs[0]; 305 306 do { 307 size = writev(fd, (struct iovec const *) &iov, sizeof(iov)/sizeof(iov[0])); 308 } while (size < 0 && errno == EINTR); 309 310 /* Check if we have sent (or failed to sent) last response chunk */ 311 if (srv->fdidx[fd].rsp_cs == srv->fdidx[fd].rsp_size) { 312 srv->fdidx[fd].rsp_cs = 0; 313 srv->fdidx[fd].rsp_size = 0; 314 srv->fdidx[fd].rsp_limit = 0; 315 } 316 317 return ((size < 0)? errno : 0); 318 } 319 320