5 * Copyright (C) 2012 Intel Corporation
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
35 #include <bluetooth/bluetooth.h>
36 #include <bluetooth/rfcomm.h>
37 #include <bluetooth/sdp.h>
38 #include <bluetooth/sdp_lib.h>
41 #include "transport.h"
42 #include "bluetooth.h"
44 #define BT_BUS_NAME "org.bluez"
46 #define BT_ADAPTER_IFACE "org.bluez.Adapter"
47 #define BT_MANAGER_IFACE "org.bluez.Manager"
49 #define BT_RX_MTU 32767
50 #define BT_TX_MTU 32767
52 #define OBC_BT_ERROR obc_bt_error_quark()
54 struct bluetooth_session {
59 DBusConnection *conn; /* system bus connection */
62 GSList *pending_calls;
65 obc_transport_func func;
69 static GSList *sessions = NULL;
71 static GQuark obc_bt_error_quark(void)
73 return g_quark_from_static_string("obc-bluetooth-error-quark");
76 static int send_method_call(struct bluetooth_session *session,
78 const char *interface,
80 DBusPendingCallNotifyFunction cb,
84 DBusPendingCall *call;
87 msg = dbus_message_new_method_call(BT_BUS_NAME, path, interface,
90 error("Unable to allocate new D-Bus %s message", method);
96 if (!dbus_message_append_args_valist(msg, type, args)) {
97 dbus_message_unref(msg);
105 g_dbus_send_message(session->conn, msg);
109 if (!dbus_connection_send_with_reply(session->conn, msg, &call, -1)) {
110 error("Sending %s failed", method);
111 dbus_message_unref(msg);
115 dbus_pending_call_set_notify(call, cb, session, NULL);
117 session->pending_calls = g_slist_prepend(session->pending_calls, call);
119 dbus_message_unref(msg);
124 static void finalize_call(DBusPendingCall *call)
126 if (!dbus_pending_call_get_completed(call))
127 dbus_pending_call_cancel(call);
129 dbus_pending_call_unref(call);
132 static void session_destroy(struct bluetooth_session *session)
138 if (g_slist_find(sessions, session) == NULL)
141 sessions = g_slist_remove(sessions, session);
143 if (session->adapter)
144 send_method_call(session, session->adapter, BT_ADAPTER_IFACE,
145 "ReleaseSession", NULL,
148 l = session->pending_calls;
151 DBusPendingCall *call = l->data;
154 session->pending_calls = g_slist_remove(session->pending_calls, call);
158 if (session->io != NULL) {
159 g_io_channel_shutdown(session->io, TRUE, NULL);
160 g_io_channel_unref(session->io);
164 dbus_connection_unref(session->conn);
166 g_free(session->service);
167 g_free(session->adapter);
171 static void transport_callback(GIOChannel *io, GError *err, gpointer user_data)
173 struct bluetooth_session *session = user_data;
178 session->func(io, err, session->user_data);
181 session_destroy(session);
184 static GIOChannel *transport_connect(const bdaddr_t *src, const bdaddr_t *dst,
185 uint16_t port, BtIOConnect function,
191 DBG("port %u", port);
194 io = bt_io_connect(BT_IO_L2CAP, function, user_data,
196 BT_IO_OPT_SOURCE_BDADDR, src,
197 BT_IO_OPT_DEST_BDADDR, dst,
199 BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
200 BT_IO_OPT_OMTU, BT_TX_MTU,
201 BT_IO_OPT_IMTU, BT_RX_MTU,
202 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
205 io = bt_io_connect(BT_IO_RFCOMM, function, user_data,
207 BT_IO_OPT_SOURCE_BDADDR, src,
208 BT_IO_OPT_DEST_BDADDR, dst,
209 BT_IO_OPT_CHANNEL, port,
210 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
217 error("%s", err->message);
222 static void search_callback(uint8_t type, uint16_t status,
223 uint8_t *rsp, size_t size, void *user_data)
225 struct bluetooth_session *session = user_data;
226 unsigned int scanned, bytesleft = size;
232 if (status || type != SDP_SVC_SEARCH_ATTR_RSP)
235 scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen);
236 if (!scanned || !seqlen)
240 bytesleft -= scanned;
245 int recsize, ch = -1;
248 rec = sdp_extract_pdu(rsp, bytesleft, &recsize);
253 sdp_record_free(rec);
257 if (!sdp_get_access_protos(rec, &protos)) {
258 ch = sdp_get_proto_port(protos, RFCOMM_UUID);
259 sdp_list_foreach(protos,
260 (sdp_list_func_t) sdp_list_free, NULL);
261 sdp_list_free(protos, NULL);
265 data = sdp_data_get(rec, 0x0200);
266 /* PSM must be odd and lsb of upper byte must be 0 */
267 if (data != NULL && (data->val.uint16 & 0x0101) == 0x0001)
268 ch = data->val.uint16;
270 sdp_record_free(rec);
279 bytesleft -= recsize;
280 } while (scanned < size && bytesleft > 0);
285 session->port = port;
287 g_io_channel_set_close_on_unref(session->io, FALSE);
288 g_io_channel_unref(session->io);
290 session->io = transport_connect(&session->src, &session->dst, port,
291 transport_callback, session);
292 if (session->io != NULL) {
293 sdp_close(session->sdp);
299 if (session->io != NULL) {
300 g_io_channel_shutdown(session->io, TRUE, NULL);
301 g_io_channel_unref(session->io);
305 g_set_error(&gerr, OBC_BT_ERROR, -EIO,
306 "Unable to find service record");
308 session->func(session->io, gerr, session->user_data);
310 g_clear_error(&gerr);
312 session_destroy(session);
315 static gboolean process_callback(GIOChannel *io, GIOCondition cond,
318 struct bluetooth_session *session = user_data;
320 if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
323 if (sdp_process(session->sdp) < 0)
329 static int bt_string2uuid(uuid_t *uuid, const char *string)
331 uint32_t data0, data4;
332 uint16_t data1, data2, data3, data5;
334 if (sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
335 &data0, &data1, &data2, &data3, &data4, &data5) == 6) {
338 data0 = g_htonl(data0);
339 data1 = g_htons(data1);
340 data2 = g_htons(data2);
341 data3 = g_htons(data3);
342 data4 = g_htonl(data4);
343 data5 = g_htons(data5);
345 memcpy(&val[0], &data0, 4);
346 memcpy(&val[4], &data1, 2);
347 memcpy(&val[6], &data2, 2);
348 memcpy(&val[8], &data3, 2);
349 memcpy(&val[10], &data4, 4);
350 memcpy(&val[14], &data5, 2);
352 sdp_uuid128_create(uuid, val);
360 static gboolean service_callback(GIOChannel *io, GIOCondition cond,
363 struct bluetooth_session *session = user_data;
364 sdp_list_t *search, *attrid;
365 uint32_t range = 0x0000ffff;
369 if (cond & G_IO_NVAL)
375 if (sdp_set_notify(session->sdp, search_callback, session) < 0)
378 if (bt_string2uuid(&uuid, session->service) < 0)
381 search = sdp_list_append(NULL, &uuid);
382 attrid = sdp_list_append(NULL, &range);
384 if (sdp_service_search_attr_async(session->sdp,
385 search, SDP_ATTR_REQ_RANGE, attrid) < 0) {
386 sdp_list_free(attrid, NULL);
387 sdp_list_free(search, NULL);
391 sdp_list_free(attrid, NULL);
392 sdp_list_free(search, NULL);
394 g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
395 process_callback, session);
400 g_io_channel_shutdown(session->io, TRUE, NULL);
401 g_io_channel_unref(session->io);
404 g_set_error(&gerr, OBC_BT_ERROR, -EIO,
405 "Unable to find service record");
407 session->func(session->io, gerr, session->user_data);
408 g_clear_error(&gerr);
410 session_destroy(session);
414 static sdp_session_t *service_connect(const bdaddr_t *src, const bdaddr_t *dst,
415 GIOFunc function, gpointer user_data)
417 struct bluetooth_session *session = user_data;
421 sdp = sdp_connect(src, dst, SDP_NON_BLOCKING);
425 io = g_io_channel_unix_new(sdp_get_socket(sdp));
431 g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
432 function, user_data);
439 static int session_connect(struct bluetooth_session *session)
443 if (session->port > 0) {
444 session->io = transport_connect(&session->src, &session->dst,
448 err = (session->io == NULL) ? -EINVAL : 0;
450 session->sdp = service_connect(&session->src, &session->dst,
451 service_callback, session);
452 err = (session->sdp == NULL) ? -ENOMEM : 0;
458 static void adapter_reply(DBusPendingCall *call, void *user_data)
460 struct bluetooth_session *session = user_data;
465 reply = dbus_pending_call_steal_reply(call);
467 session->pending_calls = g_slist_remove(session->pending_calls, call);
470 dbus_error_init(&err);
471 if (dbus_set_error_from_message(&err, reply)) {
472 error("manager replied with an error: %s, %s",
473 err.name, err.message);
474 dbus_error_free(&err);
479 if (session_connect(session) == 0)
483 g_set_error(&gerr, OBC_BT_ERROR, -EINVAL,
484 "Unable to request session");
486 session->func(session->io, gerr, session->user_data);
487 g_clear_error(&gerr);
489 session_destroy(session);
492 dbus_message_unref(reply);
495 static int request_session(struct bluetooth_session *session, const char *adapter)
497 session->adapter = g_strdup(adapter);
498 return send_method_call(session, adapter, BT_ADAPTER_IFACE,
499 "RequestSession", adapter_reply,
503 static void manager_reply(DBusPendingCall *call, void *user_data)
505 struct bluetooth_session *session = user_data;
511 reply = dbus_pending_call_steal_reply(call);
513 session->pending_calls = g_slist_remove(session->pending_calls, call);
516 dbus_error_init(&err);
517 if (dbus_set_error_from_message(&err, reply)) {
518 error("manager replied with an error: %s, %s",
519 err.name, err.message);
520 dbus_error_free(&err);
525 if (!dbus_message_get_args(reply, NULL,
526 DBUS_TYPE_OBJECT_PATH, &adapter,
530 DBG("adapter path %s", adapter);
532 if (request_session(session, adapter) == 0)
536 g_set_error(&gerr, OBC_BT_ERROR, -EINVAL, "No adapter found");
538 session->func(session->io, gerr, session->user_data);
539 g_clear_error(&gerr);
541 session_destroy(session);
544 dbus_message_unref(reply);
547 static int find_adapter(struct bluetooth_session *session, const char *source)
549 if (source == NULL) {
550 bacpy(&session->src, BDADDR_ANY);
551 return send_method_call(session, BT_PATH, BT_MANAGER_IFACE,
552 "DefaultAdapter", manager_reply,
556 str2ba(source, &session->src);
557 return send_method_call(session, BT_PATH, BT_MANAGER_IFACE,
558 "FindAdapter", manager_reply,
559 DBUS_TYPE_STRING, &source,
563 static guint bluetooth_connect(const char *source, const char *destination,
564 const char *service, uint16_t port,
565 obc_transport_func func, void *user_data)
567 struct bluetooth_session *session;
572 if (destination == NULL)
575 session = g_try_malloc0(sizeof(*session));
580 session->func = func;
581 session->user_data = user_data;
583 session->conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
584 if (session->conn == NULL) {
589 session->service = g_strdup(service);
590 str2ba(destination, &session->dst);
592 if (find_adapter(session, source) < 0) {
597 sessions = g_slist_prepend(sessions, session);
602 static void bluetooth_disconnect(guint id)
608 for (l = sessions; l; l = l->next) {
609 struct bluetooth_session *session = l->data;
611 if (session->id == id) {
612 session_destroy(session);
618 static int bluetooth_getpacketopt(GIOChannel *io, int *tx_mtu, int *rx_mtu)
620 int sk = g_io_channel_unix_get_fd(io);
624 socklen_t len = sizeof(int);
628 if (getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
631 if (type != SOCK_SEQPACKET)
634 if (!bt_io_get(io, BT_IO_L2CAP, NULL, BT_IO_OPT_OMTU, &omtu,
635 BT_IO_OPT_IMTU, &imtu,
648 static struct obc_transport bluetooth = {
650 .connect = bluetooth_connect,
651 .getpacketopt = bluetooth_getpacketopt,
652 .disconnect = bluetooth_disconnect,
655 int bluetooth_init(void)
659 return obc_transport_register(&bluetooth);
662 void bluetooth_exit(void)
666 obc_transport_unregister(&bluetooth);