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 
     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