1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2001-2002 Nokia Corporation 6 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk (at) qualcomm.com> 7 * Copyright (C) 2002-2009 Marcel Holtmann <marcel (at) holtmann.org> 8 * Copyright (C) 2002-2003 Stephen Crane <steve.crane (at) rococosoft.com> 9 * 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 * 25 */ 26 27 #ifdef HAVE_CONFIG_H 28 #include <config.h> 29 #endif 30 31 #include <stdio.h> 32 #include <errno.h> 33 #include <stdlib.h> 34 #include <sys/socket.h> 35 36 #include <bluetooth/bluetooth.h> 37 #include <bluetooth/l2cap.h> 38 #include <bluetooth/sdp.h> 39 #include <bluetooth/sdp_lib.h> 40 41 #include "sdpd.h" 42 #include "logging.h" 43 44 static sdp_list_t *service_db; 45 static sdp_list_t *access_db; 46 47 typedef struct { 48 uint32_t handle; 49 bdaddr_t device; 50 } sdp_access_t; 51 52 /* 53 * Ordering function called when inserting a service record. 54 * The service repository is a linked list in sorted order 55 * and the service record handle is the sort key 56 */ 57 static int record_sort(const void *r1, const void *r2) 58 { 59 const sdp_record_t *rec1 = (const sdp_record_t *) r1; 60 const sdp_record_t *rec2 = (const sdp_record_t *) r2; 61 62 if (!rec1 || !rec2) { 63 error("NULL RECORD LIST FATAL"); 64 return -1; 65 } 66 67 return rec1->handle - rec2->handle; 68 } 69 70 static int access_sort(const void *r1, const void *r2) 71 { 72 const sdp_access_t *rec1 = (const sdp_access_t *) r1; 73 const sdp_access_t *rec2 = (const sdp_access_t *) r2; 74 75 if (!rec1 || !rec2) { 76 error("NULL RECORD LIST FATAL"); 77 return -1; 78 } 79 80 return rec1->handle - rec2->handle; 81 } 82 83 static void access_free(void *p) 84 { 85 free(p); 86 } 87 88 /* 89 * Reset the service repository by deleting its contents 90 */ 91 void sdp_svcdb_reset() 92 { 93 sdp_list_free(service_db, (sdp_free_func_t) sdp_record_free); 94 sdp_list_free(access_db, access_free); 95 } 96 97 typedef struct _indexed { 98 int sock; 99 sdp_record_t *record; 100 } sdp_indexed_t; 101 102 static sdp_list_t *socket_index; 103 104 /* 105 * collect all services registered over this socket 106 */ 107 void sdp_svcdb_collect_all(int sock) 108 { 109 sdp_list_t *p, *q; 110 111 for (p = socket_index, q = 0; p; ) { 112 sdp_indexed_t *item = (sdp_indexed_t *) p->data; 113 if (item->sock == sock) { 114 sdp_list_t *next = p->next; 115 sdp_record_remove(item->record->handle); 116 sdp_record_free(item->record); 117 free(item); 118 if (q) 119 q->next = next; 120 else 121 socket_index = next; 122 free(p); 123 p = next; 124 } else if (item->sock > sock) 125 return; 126 else { 127 q = p; 128 p = p->next; 129 } 130 } 131 } 132 133 void sdp_svcdb_collect(sdp_record_t *rec) 134 { 135 sdp_list_t *p, *q; 136 137 for (p = socket_index, q = 0; p; q = p, p = p->next) { 138 sdp_indexed_t *item = (sdp_indexed_t *) p->data; 139 if (rec == item->record) { 140 free(item); 141 if (q) 142 q->next = p->next; 143 else 144 socket_index = p->next; 145 free(p); 146 return; 147 } 148 } 149 } 150 151 static int compare_indices(const void *i1, const void *i2) 152 { 153 const sdp_indexed_t *s1 = (const sdp_indexed_t *) i1; 154 const sdp_indexed_t *s2 = (const sdp_indexed_t *) i2; 155 return s1->sock - s2->sock; 156 } 157 158 void sdp_svcdb_set_collectable(sdp_record_t *record, int sock) 159 { 160 sdp_indexed_t *item = malloc(sizeof(sdp_indexed_t)); 161 item->sock = sock; 162 item->record = record; 163 socket_index = sdp_list_insert_sorted(socket_index, item, compare_indices); 164 } 165 166 /* 167 * Add a service record to the repository 168 */ 169 void sdp_record_add(const bdaddr_t *device, sdp_record_t *rec) 170 { 171 sdp_access_t *dev; 172 173 SDPDBG("Adding rec : 0x%lx", (long) rec); 174 SDPDBG("with handle : 0x%x", rec->handle); 175 176 service_db = sdp_list_insert_sorted(service_db, rec, record_sort); 177 178 dev = malloc(sizeof(*dev)); 179 if (!dev) 180 return; 181 182 bacpy(&dev->device, device); 183 dev->handle = rec->handle; 184 185 access_db = sdp_list_insert_sorted(access_db, dev, access_sort); 186 } 187 188 static sdp_list_t *record_locate(uint32_t handle) 189 { 190 if (service_db) { 191 sdp_list_t *p; 192 sdp_record_t r; 193 194 r.handle = handle; 195 p = sdp_list_find(service_db, &r, record_sort); 196 return p; 197 } 198 199 SDPDBG("Could not find svcRec for : 0x%x", handle); 200 return NULL; 201 } 202 203 static sdp_list_t *access_locate(uint32_t handle) 204 { 205 if (access_db) { 206 sdp_list_t *p; 207 sdp_access_t a; 208 209 a.handle = handle; 210 p = sdp_list_find(access_db, &a, access_sort); 211 return p; 212 } 213 214 SDPDBG("Could not find access data for : 0x%x", handle); 215 return NULL; 216 } 217 218 /* 219 * Given a service record handle, find the record associated with it. 220 */ 221 sdp_record_t *sdp_record_find(uint32_t handle) 222 { 223 sdp_list_t *p = record_locate(handle); 224 225 if (!p) { 226 SDPDBG("Couldn't find record for : 0x%x", handle); 227 return 0; 228 } 229 230 return (sdp_record_t *) p->data; 231 } 232 233 /* 234 * Given a service record handle, remove its record from the repository 235 */ 236 int sdp_record_remove(uint32_t handle) 237 { 238 sdp_list_t *p = record_locate(handle); 239 sdp_record_t *r; 240 sdp_access_t *a; 241 242 if (!p) { 243 error("Remove : Couldn't find record for : 0x%x", handle); 244 return -1; 245 } 246 247 r = (sdp_record_t *) p->data; 248 if (r) 249 service_db = sdp_list_remove(service_db, r); 250 251 p = access_locate(handle); 252 if (p) { 253 a = (sdp_access_t *) p->data; 254 if (a) { 255 access_db = sdp_list_remove(access_db, a); 256 access_free(a); 257 } 258 } 259 260 return 0; 261 } 262 263 /* 264 * Return a pointer to the linked list containing the records in sorted order 265 */ 266 sdp_list_t *sdp_get_record_list(void) 267 { 268 return service_db; 269 } 270 271 sdp_list_t *sdp_get_access_list(void) 272 { 273 return access_db; 274 } 275 276 int sdp_check_access(uint32_t handle, bdaddr_t *device) 277 { 278 sdp_list_t *p = access_locate(handle); 279 sdp_access_t *a; 280 281 if (!p) 282 return 1; 283 284 a = (sdp_access_t *) p->data; 285 if (!a) 286 return 1; 287 288 if (bacmp(&a->device, device) && 289 bacmp(&a->device, BDADDR_ANY) && 290 bacmp(device, BDADDR_ANY)) 291 return 0; 292 293 return 1; 294 } 295 296 uint32_t sdp_next_handle(void) 297 { 298 uint32_t handle = 0x10000; 299 300 while (sdp_record_find(handle)) 301 handle++; 302 303 return handle; 304 } 305