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-2010 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 "log.h" 43 #include "adapter.h" 44 45 static sdp_list_t *service_db; 46 static sdp_list_t *access_db; 47 48 typedef struct { 49 uint32_t handle; 50 bdaddr_t device; 51 } sdp_access_t; 52 53 /* 54 * Ordering function called when inserting a service record. 55 * The service repository is a linked list in sorted order 56 * and the service record handle is the sort key 57 */ 58 int record_sort(const void *r1, const void *r2) 59 { 60 const sdp_record_t *rec1 = (const sdp_record_t *) r1; 61 const sdp_record_t *rec2 = (const sdp_record_t *) r2; 62 63 if (!rec1 || !rec2) { 64 error("NULL RECORD LIST FATAL"); 65 return -1; 66 } 67 68 return rec1->handle - rec2->handle; 69 } 70 71 static int access_sort(const void *r1, const void *r2) 72 { 73 const sdp_access_t *rec1 = (const sdp_access_t *) r1; 74 const sdp_access_t *rec2 = (const sdp_access_t *) r2; 75 76 if (!rec1 || !rec2) { 77 error("NULL RECORD LIST FATAL"); 78 return -1; 79 } 80 81 return rec1->handle - rec2->handle; 82 } 83 84 static void access_free(void *p) 85 { 86 free(p); 87 } 88 89 /* 90 * Reset the service repository by deleting its contents 91 */ 92 void sdp_svcdb_reset() 93 { 94 sdp_list_free(service_db, (sdp_free_func_t) sdp_record_free); 95 sdp_list_free(access_db, access_free); 96 } 97 98 typedef struct _indexed { 99 int sock; 100 sdp_record_t *record; 101 } sdp_indexed_t; 102 103 static sdp_list_t *socket_index; 104 105 /* 106 * collect all services registered over this socket 107 */ 108 void sdp_svcdb_collect_all(int sock) 109 { 110 sdp_list_t *p, *q; 111 112 for (p = socket_index, q = 0; p; ) { 113 sdp_indexed_t *item = (sdp_indexed_t *) p->data; 114 if (item->sock == sock) { 115 sdp_list_t *next = p->next; 116 sdp_record_remove(item->record->handle); 117 sdp_record_free(item->record); 118 free(item); 119 if (q) 120 q->next = next; 121 else 122 socket_index = next; 123 free(p); 124 p = next; 125 } else if (item->sock > sock) 126 return; 127 else { 128 q = p; 129 p = p->next; 130 } 131 } 132 } 133 134 void sdp_svcdb_collect(sdp_record_t *rec) 135 { 136 sdp_list_t *p, *q; 137 138 for (p = socket_index, q = 0; p; q = p, p = p->next) { 139 sdp_indexed_t *item = (sdp_indexed_t *) p->data; 140 if (rec == item->record) { 141 free(item); 142 if (q) 143 q->next = p->next; 144 else 145 socket_index = p->next; 146 free(p); 147 return; 148 } 149 } 150 } 151 152 static int compare_indices(const void *i1, const void *i2) 153 { 154 const sdp_indexed_t *s1 = (const sdp_indexed_t *) i1; 155 const sdp_indexed_t *s2 = (const sdp_indexed_t *) i2; 156 return s1->sock - s2->sock; 157 } 158 159 void sdp_svcdb_set_collectable(sdp_record_t *record, int sock) 160 { 161 sdp_indexed_t *item = malloc(sizeof(sdp_indexed_t)); 162 item->sock = sock; 163 item->record = record; 164 socket_index = sdp_list_insert_sorted(socket_index, item, compare_indices); 165 } 166 167 /* 168 * Add a service record to the repository 169 */ 170 void sdp_record_add(const bdaddr_t *device, sdp_record_t *rec) 171 { 172 sdp_access_t *dev; 173 174 SDPDBG("Adding rec : 0x%lx", (long) rec); 175 SDPDBG("with handle : 0x%x", rec->handle); 176 177 service_db = sdp_list_insert_sorted(service_db, rec, record_sort); 178 179 dev = malloc(sizeof(*dev)); 180 if (!dev) 181 return; 182 183 bacpy(&dev->device, device); 184 dev->handle = rec->handle; 185 186 access_db = sdp_list_insert_sorted(access_db, dev, access_sort); 187 188 adapter_service_insert(device, rec); 189 } 190 191 static sdp_list_t *record_locate(uint32_t handle) 192 { 193 if (service_db) { 194 sdp_list_t *p; 195 sdp_record_t r; 196 197 r.handle = handle; 198 p = sdp_list_find(service_db, &r, record_sort); 199 return p; 200 } 201 202 SDPDBG("Could not find svcRec for : 0x%x", handle); 203 return NULL; 204 } 205 206 static sdp_list_t *access_locate(uint32_t handle) 207 { 208 if (access_db) { 209 sdp_list_t *p; 210 sdp_access_t a; 211 212 a.handle = handle; 213 p = sdp_list_find(access_db, &a, access_sort); 214 return p; 215 } 216 217 SDPDBG("Could not find access data for : 0x%x", handle); 218 return NULL; 219 } 220 221 /* 222 * Given a service record handle, find the record associated with it. 223 */ 224 sdp_record_t *sdp_record_find(uint32_t handle) 225 { 226 sdp_list_t *p = record_locate(handle); 227 228 if (!p) { 229 SDPDBG("Couldn't find record for : 0x%x", handle); 230 return 0; 231 } 232 233 return (sdp_record_t *) p->data; 234 } 235 236 /* 237 * Given a service record handle, remove its record from the repository 238 */ 239 int sdp_record_remove(uint32_t handle) 240 { 241 sdp_list_t *p = record_locate(handle); 242 sdp_record_t *r; 243 sdp_access_t *a; 244 245 if (!p) { 246 error("Remove : Couldn't find record for : 0x%x", handle); 247 return -1; 248 } 249 250 r = (sdp_record_t *) p->data; 251 if (r) 252 service_db = sdp_list_remove(service_db, r); 253 254 p = access_locate(handle); 255 if (p) { 256 a = (sdp_access_t *) p->data; 257 if (a) { 258 adapter_service_remove(&a->device, r); 259 access_db = sdp_list_remove(access_db, a); 260 access_free(a); 261 } 262 } 263 264 return 0; 265 } 266 267 /* 268 * Return a pointer to the linked list containing the records in sorted order 269 */ 270 sdp_list_t *sdp_get_record_list(void) 271 { 272 return service_db; 273 } 274 275 sdp_list_t *sdp_get_access_list(void) 276 { 277 return access_db; 278 } 279 280 int sdp_check_access(uint32_t handle, bdaddr_t *device) 281 { 282 sdp_list_t *p = access_locate(handle); 283 sdp_access_t *a; 284 285 if (!p) 286 return 1; 287 288 a = (sdp_access_t *) p->data; 289 if (!a) 290 return 1; 291 292 if (bacmp(&a->device, device) && 293 bacmp(&a->device, BDADDR_ANY) && 294 bacmp(device, BDADDR_ANY)) 295 return 0; 296 297 return 1; 298 } 299 300 uint32_t sdp_next_handle(void) 301 { 302 uint32_t handle = 0x10000; 303 304 while (sdp_record_find(handle)) 305 handle++; 306 307 return handle; 308 } 309