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