• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@qualcomm.com>
7  *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org>
8  *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@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  */
record_sort(const void * r1,const void * r2)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 
access_sort(const void * r1,const void * r2)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 
access_free(void * p)83 static void access_free(void *p)
84 {
85 	free(p);
86 }
87 
88 /*
89  * Reset the service repository by deleting its contents
90  */
sdp_svcdb_reset()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  */
sdp_svcdb_collect_all(int sock)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 
sdp_svcdb_collect(sdp_record_t * rec)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 
compare_indices(const void * i1,const void * i2)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 
sdp_svcdb_set_collectable(sdp_record_t * record,int sock)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  */
sdp_record_add(bdaddr_t * device,sdp_record_t * rec)169 void sdp_record_add(bdaddr_t *device, sdp_record_t *rec)
170 {
171 	sdp_access_t *dev;
172 
173 	debug("Adding rec : 0x%lx", (long) rec);
174 	debug("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 
record_locate(uint32_t handle)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 	debug("Could not find svcRec for : 0x%x", handle);
200 	return NULL;
201 }
202 
access_locate(uint32_t handle)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 	debug("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  */
sdp_record_find(uint32_t handle)221 sdp_record_t *sdp_record_find(uint32_t handle)
222 {
223 	sdp_list_t *p = record_locate(handle);
224 
225         if (!p) {
226 		debug("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  */
sdp_record_remove(uint32_t handle)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  */
sdp_get_record_list(void)266 sdp_list_t *sdp_get_record_list(void)
267 {
268 	return service_db;
269 }
270 
sdp_get_access_list(void)271 sdp_list_t *sdp_get_access_list(void)
272 {
273 	return access_db;
274 }
275 
sdp_check_access(uint32_t handle,bdaddr_t * device)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 
sdp_next_handle(void)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