• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2006-2007  Nokia Corporation
6  *  Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include <bluetooth/bluetooth.h>
34 #include <bluetooth/hci.h>
35 #include <bluetooth/hci_lib.h>
36 #include <bluetooth/sdp.h>
37 #include <bluetooth/sdp_lib.h>
38 
39 #include <gdbus.h>
40 
41 #include "hcid.h"
42 #include "sdpd.h"
43 #include "sdp-xml.h"
44 #include "manager.h"
45 #include "adapter.h"
46 #include "dbus-hci.h"
47 #include "dbus-common.h"
48 #include "error.h"
49 #include "dbus-service.h"
50 #include "dbus-security.h"
51 #include "dbus-database.h"
52 
53 static GSList *records = NULL;
54 
55 struct record_data {
56 	uint32_t handle;
57 	char *sender;
58 	guint listener_id;
59 };
60 
find_record(uint32_t handle,const char * sender)61 static struct record_data *find_record(uint32_t handle, const char *sender)
62 {
63 	GSList *list;
64 
65 	for (list = records; list; list = list->next) {
66 		struct record_data *data = list->data;
67 		if (handle == data->handle && !strcmp(sender, data->sender))
68 			return data;
69 	}
70 
71 	return NULL;
72 }
73 
exit_callback(void * user_data)74 static void exit_callback(void *user_data)
75 {
76 	struct record_data *user_record = user_data;
77 
78 	debug("remove record");
79 
80 	records = g_slist_remove(records, user_record);
81 
82 	remove_record_from_server(user_record->handle);
83 
84 	g_free(user_record->sender);
85 	g_free(user_record);
86 }
87 
invalid_arguments(DBusMessage * msg)88 static inline DBusMessage *invalid_arguments(DBusMessage *msg)
89 {
90 	return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
91 					"Invalid arguments in method call");
92 }
93 
not_available(DBusMessage * msg)94 static inline DBusMessage *not_available(DBusMessage *msg)
95 {
96 	return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
97 							"Not Available");
98 }
99 
failed(DBusMessage * msg)100 static inline DBusMessage *failed(DBusMessage *msg)
101 {
102 	return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Failed");
103 }
104 
add_service_record(DBusConnection * conn,DBusMessage * msg,void * data)105 static DBusMessage *add_service_record(DBusConnection *conn,
106 						DBusMessage *msg, void *data)
107 {
108 	DBusMessageIter iter, array;
109 	const char *sender;
110 	struct record_data *user_record;
111 	sdp_record_t *sdp_record;
112 	const uint8_t *record;
113 	int scanned, len = -1;
114 
115 	dbus_message_iter_init(msg, &iter);
116 	dbus_message_iter_recurse(&iter, &array);
117 
118 	dbus_message_iter_get_fixed_array(&array, &record, &len);
119 	if (len <= 0)
120 		return invalid_arguments(msg);
121 
122 	sdp_record = sdp_extract_pdu_safe(record, len, &scanned);
123 	if (!sdp_record) {
124 		error("Parsing of service record failed");
125 		return failed(msg);
126 	}
127 
128 	if (scanned != len) {
129 		error("Size mismatch of service record");
130 		sdp_record_free(sdp_record);
131 		return failed(msg);
132 	}
133 
134 	if (add_record_to_server(BDADDR_ANY, sdp_record) < 0) {
135 		error("Failed to register service record");
136 		sdp_record_free(sdp_record);
137 		return failed(msg);
138 	}
139 
140 	user_record = g_new0(struct record_data, 1);
141 
142 	user_record->handle = sdp_record->handle;
143 
144 	sender = dbus_message_get_sender(msg);
145 
146 	user_record->sender = g_strdup(sender);
147 
148 	records = g_slist_append(records, user_record);
149 
150 	user_record->listener_id = g_dbus_add_disconnect_watch(conn, sender,
151 								exit_callback,
152 								user_record,
153 								NULL);
154 
155 	debug("listener_id %d", user_record->listener_id);
156 
157 	return g_dbus_create_reply(msg, DBUS_TYPE_UINT32, &user_record->handle,
158 							DBUS_TYPE_INVALID);
159 }
160 
add_xml_record(DBusConnection * conn,const char * sender,bdaddr_t * src,const char * record,dbus_uint32_t * handle)161 int add_xml_record(DBusConnection *conn, const char *sender, bdaddr_t *src,
162 				const char *record, dbus_uint32_t *handle)
163 {
164 	struct record_data *user_record;
165 	sdp_record_t *sdp_record;
166 
167 	sdp_record = sdp_xml_parse_record(record, strlen(record));
168 	if (!sdp_record) {
169 		error("Parsing of XML service record failed");
170 		return -EIO;
171 	}
172 
173 	if (add_record_to_server(src, sdp_record) < 0) {
174 		error("Failed to register service record");
175 		sdp_record_free(sdp_record);
176 		return -EIO;
177 	}
178 
179 	user_record = g_new0(struct record_data, 1);
180 
181 	user_record->handle = sdp_record->handle;
182 
183 	user_record->sender = g_strdup(sender);
184 
185 	records = g_slist_append(records, user_record);
186 
187 	user_record->listener_id = g_dbus_add_disconnect_watch(conn, sender,
188 					exit_callback, user_record, NULL);
189 
190 	debug("listener_id %d", user_record->listener_id);
191 
192 	*handle = user_record->handle;
193 
194 	return 0;
195 }
196 
add_service_record_from_xml(DBusConnection * conn,DBusMessage * msg,void * data)197 static DBusMessage *add_service_record_from_xml(DBusConnection *conn,
198 						DBusMessage *msg, void *data)
199 {
200 	const char *sender, *record;
201 	dbus_uint32_t handle;
202 	int err;
203 
204 	if (dbus_message_get_args(msg, NULL,
205 			DBUS_TYPE_STRING, &record, DBUS_TYPE_INVALID) == FALSE)
206 		return NULL;
207 
208 	sender = dbus_message_get_sender(msg);
209 
210 	err = add_xml_record(conn, sender, BDADDR_ANY, record, &handle);
211 	if (err < 0)
212 		return failed(msg);
213 
214 	return g_dbus_create_reply(msg, DBUS_TYPE_UINT32, &handle,
215 							DBUS_TYPE_INVALID);
216 }
217 
update_record(DBusConnection * conn,DBusMessage * msg,bdaddr_t * src,dbus_uint32_t handle,sdp_record_t * sdp_record)218 static DBusMessage *update_record(DBusConnection *conn, DBusMessage *msg,
219 		bdaddr_t *src, dbus_uint32_t handle, sdp_record_t *sdp_record)
220 {
221 	int err;
222 
223 	if (remove_record_from_server(handle) < 0) {
224 		sdp_record_free(sdp_record);
225 		return g_dbus_create_error(msg,
226 				ERROR_INTERFACE ".NotAvailable",
227 				"Not Available");
228 	}
229 
230 	sdp_record->handle = handle;
231 	err = add_record_to_server(src, sdp_record);
232 	if (err < 0) {
233 		sdp_record_free(sdp_record);
234 		error("Failed to update the service record");
235 		return g_dbus_create_error(msg,
236 				ERROR_INTERFACE ".Failed",
237 				strerror(EIO));
238 	}
239 
240 	return dbus_message_new_method_return(msg);
241 }
242 
update_service_record(DBusConnection * conn,DBusMessage * msg,void * data)243 static DBusMessage *update_service_record(DBusConnection *conn,
244 						DBusMessage *msg, void *data)
245 {
246 	struct record_data *user_record;
247 	DBusMessageIter iter, array;
248 	sdp_record_t *sdp_record;
249 	dbus_uint32_t handle;
250 	const uint8_t *bin_record;
251 	int scanned, size = -1;
252 
253 	dbus_message_iter_init(msg, &iter);
254 	dbus_message_iter_get_basic(&iter, &handle);
255 	dbus_message_iter_next(&iter);
256 	dbus_message_iter_recurse(&iter, &array);
257 
258 	dbus_message_iter_get_fixed_array(&array, &bin_record, &size);
259 	if (size <= 0)
260 		return invalid_arguments(msg);
261 
262 	user_record = find_record(handle, dbus_message_get_sender(msg));
263 	if (!user_record)
264 		return not_available(msg);
265 
266 	sdp_record = sdp_extract_pdu_safe(bin_record, size, &scanned);
267 	if (!sdp_record) {
268 		error("Parsing of service record failed");
269 		return invalid_arguments(msg);
270 	}
271 
272 	if (scanned != size) {
273 		error("Size mismatch of service record");
274 		sdp_record_free(sdp_record);
275 		return invalid_arguments(msg);
276 	}
277 
278 	return update_record(conn, msg, BDADDR_ANY, handle, sdp_record);
279 }
280 
update_xml_record(DBusConnection * conn,DBusMessage * msg,bdaddr_t * src)281 DBusMessage *update_xml_record(DBusConnection *conn,
282 				DBusMessage *msg, bdaddr_t *src)
283 {
284 	struct record_data *user_record;
285 	sdp_record_t *sdp_record;
286 	const char *record;
287 	dbus_uint32_t handle;
288 	int len;
289 
290 	if (dbus_message_get_args(msg, NULL,
291 				DBUS_TYPE_UINT32, &handle,
292 				DBUS_TYPE_STRING, &record,
293 				DBUS_TYPE_INVALID) == FALSE)
294 		return NULL;
295 
296 	len = (record ? strlen(record) : 0);
297 	if (len == 0)
298 		return invalid_arguments(msg);
299 
300 	user_record = find_record(handle, dbus_message_get_sender(msg));
301 	if (!user_record)
302 		return g_dbus_create_error(msg,
303 				ERROR_INTERFACE ".NotAvailable",
304 				"Not Available");
305 
306 	sdp_record = sdp_xml_parse_record(record, len);
307 	if (!sdp_record) {
308 		error("Parsing of XML service record failed");
309 		sdp_record_free(sdp_record);
310 		return g_dbus_create_error(msg,
311 				ERROR_INTERFACE ".Failed",
312 				strerror(EIO));
313 	}
314 
315 	return update_record(conn, msg, src, handle, sdp_record);
316 }
317 
update_service_record_from_xml(DBusConnection * conn,DBusMessage * msg,void * data)318 static DBusMessage *update_service_record_from_xml(DBusConnection *conn,
319 						DBusMessage *msg, void *data)
320 {
321 	return update_xml_record(conn, msg, BDADDR_ANY);
322 }
323 
remove_record(DBusConnection * conn,const char * sender,dbus_uint32_t handle)324 int remove_record(DBusConnection *conn, const char *sender,
325 						dbus_uint32_t handle)
326 {
327 	struct record_data *user_record;
328 
329 	debug("remove record 0x%x", handle);
330 
331 	user_record = find_record(handle, sender);
332 	if (!user_record)
333 		return -1;
334 
335 	debug("listner_id %d", user_record->listener_id);
336 
337 	g_dbus_remove_watch(conn, user_record->listener_id);
338 
339 	exit_callback(user_record);
340 
341 	return 0;
342 }
343 
remove_service_record(DBusConnection * conn,DBusMessage * msg,void * data)344 static DBusMessage *remove_service_record(DBusConnection *conn,
345 						DBusMessage *msg, void *data)
346 {
347 	dbus_uint32_t handle;
348 	const char *sender;
349 
350 	if (dbus_message_get_args(msg, NULL,
351 			DBUS_TYPE_UINT32, &handle, DBUS_TYPE_INVALID) == FALSE)
352 		return NULL;
353 
354 	sender = dbus_message_get_sender(msg);
355 
356 	if (remove_record(conn, sender, handle) < 0)
357 		return not_available(msg);
358 
359 	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
360 }
361 
362 static GDBusMethodTable database_methods[] = {
363 	{ "AddServiceRecord",		"ay",  "u",	add_service_record		},
364 	{ "AddServiceRecordFromXML",	"s",   "u",	add_service_record_from_xml	},
365 	{ "UpdateServiceRecord",	"uay", "",	update_service_record		},
366 	{ "UpdateServiceRecordFromXML",	"us",  "",	update_service_record_from_xml	},
367 	{ "RemoveServiceRecord",	"u",   "",	remove_service_record		},
368 	{ }
369 };
370 
database_init(DBusConnection * conn,const char * path)371 dbus_bool_t database_init(DBusConnection *conn, const char *path)
372 {
373 	return g_dbus_register_interface(conn, path, DATABASE_INTERFACE,
374 				database_methods, NULL, NULL, NULL, NULL);
375 }
376 
database_cleanup(DBusConnection * conn,const char * path)377 void database_cleanup(DBusConnection *conn, const char *path)
378 {
379 	g_dbus_unregister_interface(conn, path, DATABASE_INTERFACE);
380 }
381