mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-11-29 23:24:20 +08:00
d812870321
A sample OOB plugin that directly exposes OOB functionality over D-Bus.
236 lines
5.7 KiB
C
236 lines
5.7 KiB
C
/*
|
|
*
|
|
* BlueZ - Bluetooth protocol stack for Linux
|
|
*
|
|
* Copyright (C) 2011 ST-Ericsson SA
|
|
*
|
|
* Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <gdbus.h>
|
|
|
|
#include <bluetooth/bluetooth.h>
|
|
#include <bluetooth/hci.h>
|
|
#include <bluetooth/sdp.h>
|
|
|
|
#include "plugin.h"
|
|
#include "log.h"
|
|
#include "adapter.h"
|
|
#include "device.h"
|
|
#include "manager.h"
|
|
#include "dbus-common.h"
|
|
#include "event.h"
|
|
#include "error.h"
|
|
#include "oob.h"
|
|
|
|
#define REQUEST_TIMEOUT (60 * 1000) /* 60 seconds */
|
|
#define OOB_INTERFACE "org.bluez.Oob"
|
|
|
|
struct oob_request {
|
|
struct btd_adapter *adapter;
|
|
DBusMessage *msg;
|
|
};
|
|
|
|
static GSList *oob_requests = NULL;
|
|
static DBusConnection *connection = NULL;
|
|
|
|
static gint oob_request_cmp(gconstpointer a, gconstpointer b)
|
|
{
|
|
const struct oob_request *data = a;
|
|
const struct btd_adapter *adapter = b;
|
|
|
|
return data->adapter != adapter;
|
|
}
|
|
|
|
static struct oob_request *find_oob_request(struct btd_adapter *adapter)
|
|
{
|
|
GSList *match;
|
|
|
|
match = g_slist_find_custom(oob_requests, adapter, oob_request_cmp);
|
|
|
|
if (match)
|
|
return match->data;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash,
|
|
uint8_t *randomizer)
|
|
{
|
|
struct DBusMessage *reply;
|
|
struct oob_request *oob_request;
|
|
|
|
oob_request = find_oob_request(adapter);
|
|
if (!oob_request)
|
|
return;
|
|
|
|
if (hash && randomizer)
|
|
reply = g_dbus_create_reply(oob_request->msg,
|
|
DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, 16,
|
|
DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, 16,
|
|
DBUS_TYPE_INVALID);
|
|
else
|
|
reply = btd_error_failed(oob_request->msg,
|
|
"Failed to read local OOB data.");
|
|
|
|
oob_requests = g_slist_remove(oob_requests, oob_request);
|
|
dbus_message_unref(oob_request->msg);
|
|
g_free(oob_request);
|
|
|
|
if (!reply) {
|
|
error("Couldn't allocate D-Bus message");
|
|
return;
|
|
}
|
|
|
|
if (!g_dbus_send_message(connection, reply))
|
|
error("D-Bus send failed");
|
|
}
|
|
|
|
static DBusMessage *read_local_data(DBusConnection *conn, DBusMessage *msg,
|
|
void *data)
|
|
{
|
|
struct btd_adapter *adapter = data;
|
|
struct oob_request *oob_request;
|
|
|
|
if (find_oob_request(adapter))
|
|
return btd_error_in_progress(msg);
|
|
|
|
if (btd_adapter_read_local_oob_data(adapter))
|
|
return btd_error_failed(msg, "Request failed.");
|
|
|
|
oob_request = g_new(struct oob_request, 1);
|
|
oob_request->adapter = adapter;
|
|
oob_requests = g_slist_append(oob_requests, oob_request);
|
|
oob_request->msg = dbus_message_ref(msg);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static DBusMessage *add_remote_data(DBusConnection *conn, DBusMessage *msg,
|
|
void *data)
|
|
{
|
|
struct btd_adapter *adapter = data;
|
|
uint8_t *hash, *randomizer;
|
|
int32_t hlen, rlen;
|
|
const char *addr;
|
|
bdaddr_t bdaddr;
|
|
|
|
if (!dbus_message_get_args(msg, NULL,
|
|
DBUS_TYPE_STRING, &addr,
|
|
DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, &hlen,
|
|
DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, &rlen,
|
|
DBUS_TYPE_INVALID))
|
|
return btd_error_invalid_args(msg);
|
|
|
|
if (hlen != 16 || rlen != 16 || bachk(addr))
|
|
return btd_error_invalid_args(msg);
|
|
|
|
str2ba(addr, &bdaddr);
|
|
|
|
if (btd_adapter_add_remote_oob_data(adapter, &bdaddr, hash, randomizer))
|
|
return btd_error_failed(msg, "Request failed");
|
|
|
|
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
|
|
}
|
|
|
|
static DBusMessage *remove_remote_data(DBusConnection *conn, DBusMessage *msg,
|
|
void *data)
|
|
{
|
|
struct btd_adapter *adapter = data;
|
|
const char *addr;
|
|
bdaddr_t bdaddr;
|
|
|
|
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr,
|
|
DBUS_TYPE_INVALID))
|
|
return btd_error_invalid_args(msg);
|
|
|
|
if (bachk(addr))
|
|
return btd_error_invalid_args(msg);
|
|
|
|
str2ba(addr, &bdaddr);
|
|
|
|
if (btd_adapter_remove_remote_oob_data(adapter, &bdaddr))
|
|
return btd_error_failed(msg, "Request failed");
|
|
|
|
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
|
|
}
|
|
|
|
static GDBusMethodTable oob_methods[] = {
|
|
{"AddRemoteOobData", "sayay", "", add_remote_data},
|
|
{"RemoveRemoteOobData", "s", "", remove_remote_data},
|
|
{"ReadLocalOobData", "", "ayay", read_local_data,
|
|
G_DBUS_METHOD_FLAG_ASYNC},
|
|
{}
|
|
};
|
|
|
|
static int oob_probe(struct btd_adapter *adapter)
|
|
{
|
|
const char *path = adapter_get_path(adapter);
|
|
|
|
if (!g_dbus_register_interface(connection, path, OOB_INTERFACE,
|
|
oob_methods, NULL, NULL, adapter, NULL)) {
|
|
error("OOB interface init failed on path %s", path);
|
|
return -EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void oob_remove(struct btd_adapter *adapter)
|
|
{
|
|
read_local_data_complete(adapter, NULL, NULL);
|
|
|
|
g_dbus_unregister_interface(connection, adapter_get_path(adapter),
|
|
OOB_INTERFACE);
|
|
}
|
|
|
|
static struct btd_adapter_driver oob_driver = {
|
|
.name = "oob",
|
|
.probe = oob_probe,
|
|
.remove = oob_remove,
|
|
};
|
|
|
|
static int dbusoob_init(void)
|
|
{
|
|
DBG("Setup dbusoob plugin");
|
|
|
|
connection = get_dbus_connection();
|
|
|
|
oob_register_cb(read_local_data_complete);
|
|
|
|
return btd_register_adapter_driver(&oob_driver);
|
|
}
|
|
|
|
static void dbusoob_exit(void)
|
|
{
|
|
DBG("Cleanup dbusoob plugin");
|
|
|
|
manager_foreach_adapter((adapter_cb) oob_remove, NULL);
|
|
|
|
btd_unregister_adapter_driver(&oob_driver);
|
|
}
|
|
|
|
BLUETOOTH_PLUGIN_DEFINE(dbusoob, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
|
|
dbusoob_init, dbusoob_exit)
|