• 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 
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  */
record_sort(const void * r1,const void * r2)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 
access_sort(const void * r1,const void * r2)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 
access_free(void * p)84 static void access_free(void *p)
85 {
86 	free(p);
87 }
88 
89 /*
90  * Reset the service repository by deleting its contents
91  */
sdp_svcdb_reset()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  */
sdp_svcdb_collect_all(int sock)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 
sdp_svcdb_collect(sdp_record_t * rec)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 
compare_indices(const void * i1,const void * i2)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 
sdp_svcdb_set_collectable(sdp_record_t * record,int sock)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  */
sdp_record_add(const bdaddr_t * device,sdp_record_t * rec)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 
record_locate(uint32_t handle)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 
access_locate(uint32_t handle)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  */
sdp_record_find(uint32_t handle)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  */
sdp_record_remove(uint32_t handle)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  */
sdp_get_record_list(void)270 sdp_list_t *sdp_get_record_list(void)
271 {
272 	return service_db;
273 }
274 
sdp_get_access_list(void)275 sdp_list_t *sdp_get_access_list(void)
276 {
277 	return access_db;
278 }
279 
sdp_check_access(uint32_t handle,bdaddr_t * device)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 
sdp_next_handle(void)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