Home | History | Annotate | Download | only in src
      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