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