1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2011 ST-Ericsson SA 6 * 7 * Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson 8 * 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 * 24 */ 25 26#ifdef HAVE_CONFIG_H 27#include <config.h> 28#endif 29 30#include <errno.h> 31#include <gdbus.h> 32 33#include <bluetooth/bluetooth.h> 34#include <bluetooth/hci.h> 35#include <bluetooth/sdp.h> 36 37#include "plugin.h" 38#include "log.h" 39#include "adapter.h" 40#include "device.h" 41#include "manager.h" 42#include "dbus-common.h" 43#include "event.h" 44#include "error.h" 45#include "oob.h" 46 47#define OOB_INTERFACE "org.bluez.OutOfBand" 48 49struct oob_request { 50 struct btd_adapter *adapter; 51 DBusMessage *msg; 52}; 53 54static GSList *oob_requests = NULL; 55static DBusConnection *connection = NULL; 56 57static gint oob_request_cmp(gconstpointer a, gconstpointer b) 58{ 59 const struct oob_request *data = a; 60 const struct btd_adapter *adapter = b; 61 62 return data->adapter != adapter; 63} 64 65static struct oob_request *find_oob_request(struct btd_adapter *adapter) 66{ 67 GSList *match; 68 69 match = g_slist_find_custom(oob_requests, adapter, oob_request_cmp); 70 71 if (match) 72 return match->data; 73 74 return NULL; 75} 76 77static void read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash, 78 uint8_t *randomizer) 79{ 80 struct DBusMessage *reply; 81 struct oob_request *oob_request; 82 83 oob_request = find_oob_request(adapter); 84 if (!oob_request) 85 return; 86 87 if (hash && randomizer) 88 reply = g_dbus_create_reply(oob_request->msg, 89 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, 16, 90 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, 16, 91 DBUS_TYPE_INVALID); 92 else 93 reply = btd_error_failed(oob_request->msg, 94 "Failed to read local OOB data."); 95 96 oob_requests = g_slist_remove(oob_requests, oob_request); 97 dbus_message_unref(oob_request->msg); 98 g_free(oob_request); 99 100 if (!reply) { 101 error("Couldn't allocate D-Bus message"); 102 return; 103 } 104 105 if (!g_dbus_send_message(connection, reply)) 106 error("D-Bus send failed"); 107} 108 109static DBusMessage *read_local_data(DBusConnection *conn, DBusMessage *msg, 110 void *data) 111{ 112 struct btd_adapter *adapter = data; 113 struct oob_request *oob_request; 114 115 if (find_oob_request(adapter)) 116 return btd_error_in_progress(msg); 117 118 if (btd_adapter_read_local_oob_data(adapter)) 119 return btd_error_failed(msg, "Request failed."); 120 121 oob_request = g_new(struct oob_request, 1); 122 oob_request->adapter = adapter; 123 oob_requests = g_slist_append(oob_requests, oob_request); 124 oob_request->msg = dbus_message_ref(msg); 125 126 return NULL; 127} 128 129static DBusMessage *add_remote_data(DBusConnection *conn, DBusMessage *msg, 130 void *data) 131{ 132 struct btd_adapter *adapter = data; 133 uint8_t *hash, *randomizer; 134 int32_t hlen, rlen; 135 const char *addr; 136 bdaddr_t bdaddr; 137 138 if (!dbus_message_get_args(msg, NULL, 139 DBUS_TYPE_STRING, &addr, 140 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, &hlen, 141 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, &rlen, 142 DBUS_TYPE_INVALID)) 143 return btd_error_invalid_args(msg); 144 145 if (hlen != 16 || rlen != 16 || bachk(addr)) 146 return btd_error_invalid_args(msg); 147 148 str2ba(addr, &bdaddr); 149 150 if (btd_adapter_add_remote_oob_data(adapter, &bdaddr, hash, randomizer)) 151 return btd_error_failed(msg, "Request failed"); 152 153 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); 154} 155 156static DBusMessage *remove_remote_data(DBusConnection *conn, DBusMessage *msg, 157 void *data) 158{ 159 struct btd_adapter *adapter = data; 160 const char *addr; 161 bdaddr_t bdaddr; 162 163 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr, 164 DBUS_TYPE_INVALID)) 165 return btd_error_invalid_args(msg); 166 167 if (bachk(addr)) 168 return btd_error_invalid_args(msg); 169 170 str2ba(addr, &bdaddr); 171 172 if (btd_adapter_remove_remote_oob_data(adapter, &bdaddr)) 173 return btd_error_failed(msg, "Request failed"); 174 175 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); 176} 177 178static GDBusMethodTable oob_methods[] = { 179 {"AddRemoteData", "sayay", "", add_remote_data}, 180 {"RemoveRemoteData", "s", "", remove_remote_data}, 181 {"ReadLocalData", "", "ayay", read_local_data, 182 G_DBUS_METHOD_FLAG_ASYNC}, 183 {} 184}; 185 186static int oob_probe(struct btd_adapter *adapter) 187{ 188 const char *path = adapter_get_path(adapter); 189 190 if (!g_dbus_register_interface(connection, path, OOB_INTERFACE, 191 oob_methods, NULL, NULL, adapter, NULL)) { 192 error("OOB interface init failed on path %s", path); 193 return -EIO; 194 } 195 196 return 0; 197} 198 199static void oob_remove(struct btd_adapter *adapter) 200{ 201 read_local_data_complete(adapter, NULL, NULL); 202 203 g_dbus_unregister_interface(connection, adapter_get_path(adapter), 204 OOB_INTERFACE); 205} 206 207static struct btd_adapter_driver oob_driver = { 208 .name = "oob", 209 .probe = oob_probe, 210 .remove = oob_remove, 211}; 212 213static int dbusoob_init(void) 214{ 215 DBG("Setup dbusoob plugin"); 216 217 connection = get_dbus_connection(); 218 219 oob_register_cb(read_local_data_complete); 220 221 return btd_register_adapter_driver(&oob_driver); 222} 223 224static void dbusoob_exit(void) 225{ 226 DBG("Cleanup dbusoob plugin"); 227 228 manager_foreach_adapter((adapter_cb) oob_remove, NULL); 229 230 btd_unregister_adapter_driver(&oob_driver); 231} 232 233BLUETOOTH_PLUGIN_DEFINE(dbusoob, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, 234 dbusoob_init, dbusoob_exit) 235