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