1 /* $NetBSD: record.c,v 1.1 2009/05/12 10:05:07 plunky Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Iain Hibbert. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: record.c,v 1.1 2009/05/12 10:05:07 plunky Exp $"); 34 35 #include <bluetooth.h> 36 #include <sdp.h> 37 #include <string.h> 38 39 #include "sdpd.h" 40 41 static bool sdpd_valid_record(sdp_data_t *); 42 43 /* 44 * These record manipulation requests are not part of the SDP 45 * specification, they are a private extension and valid only 46 * for privileged clients on the control socket. 47 */ 48 49 uint16_t 50 record_insert_request(server_t *srv, int fd) 51 { 52 sdp_data_t seq; 53 bdaddr_t bdaddr; 54 55 seq.next = srv->ibuf; 56 seq.end = srv->ibuf + srv->pdu.len; 57 58 if (!srv->fdidx[fd].control 59 || !srv->fdidx[fd].priv) 60 return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX; 61 62 srv->fdidx[fd].offset = 0; 63 db_unselect(srv, fd); 64 65 /* 66 * extract BluetoothDeviceAddress 67 */ 68 if (seq.next + sizeof(bdaddr_t) > seq.end) 69 return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX; 70 71 memcpy(&bdaddr, seq.next, sizeof(bdaddr_t)); 72 seq.next += sizeof(bdaddr_t); 73 74 /* 75 * extract ServiceRecord and add to database 76 */ 77 if (!sdp_get_seq(&seq, &seq) 78 || !sdpd_valid_record(&seq)) 79 return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX; 80 81 /* (ignores any additional data) */ 82 83 if (!db_create(srv, fd, &bdaddr, srv->handle, &seq)) 84 return SDP_ERROR_CODE_INSUFFICIENT_RESOURCES; 85 86 /* 87 * encode 'success' ErrorCode and ServiceRecordHandle and 88 * bump server handle 89 */ 90 be16enc(srv->obuf, 0x0000); 91 be32enc(srv->obuf + sizeof(uint16_t), srv->handle++); 92 93 /* 94 * fill in PDU header and we are done 95 */ 96 srv->pdu.pid = SDP_PDU_ERROR_RESPONSE; 97 srv->pdu.len = sizeof(uint16_t) + sizeof(uint32_t); 98 return 0; 99 } 100 101 uint16_t 102 record_update_request(server_t *srv, int fd) 103 { 104 record_t *rec; 105 sdp_data_t seq; 106 107 seq.next = srv->ibuf; 108 seq.end = srv->ibuf + srv->pdu.len; 109 110 if (!srv->fdidx[fd].control 111 || !srv->fdidx[fd].priv) 112 return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX; 113 114 srv->fdidx[fd].offset = 0; 115 db_unselect(srv, fd); 116 117 /* 118 * extract ServiceRecordHandle and select record 119 */ 120 if (seq.next + sizeof(uint32_t) > seq.end) 121 return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX; 122 123 db_select_handle(srv, fd, be32dec(seq.next)); 124 seq.next += sizeof(uint32_t); 125 126 rec = NULL; 127 db_next(srv, fd, &rec); 128 if (rec == NULL || rec->fd != fd) 129 return SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE; 130 131 db_unselect(srv, fd); 132 133 /* 134 * extract ServiceRecord and add to database 135 */ 136 if (!sdp_get_seq(&seq, &seq) 137 || !sdpd_valid_record(&seq)) 138 return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX; 139 140 /* (ignores any additional data) */ 141 142 if (!db_create(srv, fd, &rec->bdaddr, rec->handle, &seq)) 143 return SDP_ERROR_CODE_INSUFFICIENT_RESOURCES; 144 145 /* 146 * encode 'success' ErrorCode 147 */ 148 be16enc(srv->obuf, 0x0000); 149 150 /* 151 * fill in PDU header and we are done 152 */ 153 srv->pdu.pid = SDP_PDU_ERROR_RESPONSE; 154 srv->pdu.len = sizeof(uint16_t); 155 return 0; 156 } 157 158 uint16_t 159 record_remove_request(server_t *srv, int fd) 160 { 161 record_t *rec; 162 163 if (!srv->fdidx[fd].control 164 || !srv->fdidx[fd].priv) 165 return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX; 166 167 srv->fdidx[fd].offset = 0; 168 db_unselect(srv, fd); 169 170 /* 171 * extract ServiceRecordHandle 172 */ 173 if (srv->pdu.len != sizeof(uint32_t)) 174 return SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX; 175 176 db_select_handle(srv, fd, be32dec(srv->ibuf)); 177 178 rec = NULL; 179 db_next(srv, fd, &rec); 180 if (rec == NULL || rec->fd != fd) 181 return SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE; 182 183 /* 184 * expire the record 185 */ 186 rec->refcnt--; 187 rec->valid = false; 188 rec->fd = -1; 189 db_unselect(srv, fd); 190 191 /* 192 * encode 'success' ErrorCode 193 */ 194 be16enc(srv->obuf, 0x0000); 195 196 /* 197 * fill in PDU header and we are done 198 */ 199 srv->pdu.pid = SDP_PDU_ERROR_RESPONSE; 200 srv->pdu.len = sizeof(uint16_t); 201 return 0; 202 } 203 204 /* 205 * validate ServiceRecord data element list 206 * 207 * The record must contain a list of attribute/value pairs where the 208 * attributes are unsigned 16-bit integer values in ascending order. 209 */ 210 static bool 211 sdpd_valid_record(sdp_data_t *data) 212 { 213 sdp_data_t d, s; 214 uintmax_t a0, a; 215 216 s = *data; 217 if (!sdp_data_valid(&s)) 218 return false; 219 220 /* The first attribute must be ServiceRecordHandle */ 221 if (!sdp_get_data(&s, &d) 222 || sdp_data_type(&d) != SDP_DATA_UINT16 223 || !sdp_get_uint(&d, &a0) 224 || a0 != SDP_ATTR_SERVICE_RECORD_HANDLE 225 || !sdp_get_data(&s, &d) 226 || sdp_data_type(&d) != SDP_DATA_UINT32) 227 return false; 228 229 /* and remaining attribute IDs must be in ascending order */ 230 while (sdp_get_data(&s, &d) 231 && sdp_data_type(&d) == SDP_DATA_UINT16 232 && sdp_get_uint(&d, &a) 233 && a > a0 234 && sdp_get_data(&s, &d)) 235 a0 = a; 236 237 if (s.next != s.end) 238 return false; 239 240 return true; 241 } 242