• 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-2010  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 "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  */
record_sort(const void * r1,const void * r2)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 
access_sort(const void * r1,const void * r2)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 
access_free(void * p)85 static void access_free(void *p)
86 {
87 	free(p);
88 }
89 
90 /*
91  * Reset the service repository by deleting its contents
92  */
sdp_svcdb_reset(void)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  */
sdp_svcdb_collect_all(int sock)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 
sdp_svcdb_collect(sdp_record_t * rec)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 
compare_indices(const void * i1,const void * i2)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 
sdp_svcdb_set_collectable(sdp_record_t * record,int sock)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  */
sdp_record_add(const bdaddr_t * device,sdp_record_t * rec)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 
record_locate(uint32_t handle)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 
access_locate(uint32_t handle)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  */
sdp_record_find(uint32_t handle)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  */
sdp_record_remove(uint32_t handle)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  */
sdp_get_record_list(void)285 sdp_list_t *sdp_get_record_list(void)
286 {
287 	return service_db;
288 }
289 
sdp_get_access_list(void)290 sdp_list_t *sdp_get_access_list(void)
291 {
292 	return access_db;
293 }
294 
sdp_check_access(uint32_t handle,bdaddr_t * device)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 
sdp_next_handle(void)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 
sdp_init_services_list(bdaddr_t * device)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