Fix the bug : TIVI-204 Fail to connect to bluetooth network
[profile/ivi/bluez.git] / plugins / dbusoob.c
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
49 struct oob_request {
50         struct btd_adapter *adapter;
51         DBusMessage *msg;
52 };
53
54 static GSList *oob_requests = NULL;
55 static DBusConnection *connection = NULL;
56
57 static 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
65 static 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
77 static 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
109 static 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
129 static 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
156 static 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
178 static const GDBusMethodTable oob_methods[] = {
179         { GDBUS_METHOD("AddRemoteData",
180                         GDBUS_ARGS({ "address", "s" }, { "hash", "ay" },
181                                         { "randomizer", "ay" }), NULL,
182                         add_remote_data) },
183         { GDBUS_METHOD("RemoveRemoteData",
184                         GDBUS_ARGS({ "address", "s" }), NULL,
185                         remove_remote_data) },
186         { GDBUS_ASYNC_METHOD("ReadLocalData",
187                         NULL, GDBUS_ARGS({ "hash", "ay" },
188                                                 { "randomizer", "ay" }),
189                         read_local_data) },
190         { }
191 };
192
193 static int oob_probe(struct btd_adapter *adapter)
194 {
195         const char *path = adapter_get_path(adapter);
196
197         if (!g_dbus_register_interface(connection, path, OOB_INTERFACE,
198                                 oob_methods, NULL, NULL, adapter, NULL)) {
199                         error("OOB interface init failed on path %s", path);
200                         return -EIO;
201                 }
202
203         return 0;
204 }
205
206 static void oob_remove(struct btd_adapter *adapter)
207 {
208         read_local_data_complete(adapter, NULL, NULL);
209
210         g_dbus_unregister_interface(connection, adapter_get_path(adapter),
211                                                         OOB_INTERFACE);
212 }
213
214 static struct btd_adapter_driver oob_driver = {
215         .name   = "oob",
216         .probe  = oob_probe,
217         .remove = oob_remove,
218 };
219
220 static int dbusoob_init(void)
221 {
222         DBG("Setup dbusoob plugin");
223
224         connection = get_dbus_connection();
225
226         oob_register_cb(read_local_data_complete);
227
228         return btd_register_adapter_driver(&oob_driver);
229 }
230
231 static void dbusoob_exit(void)
232 {
233         DBG("Cleanup dbusoob plugin");
234
235         manager_foreach_adapter((adapter_cb) oob_remove, NULL);
236
237         btd_unregister_adapter_driver(&oob_driver);
238 }
239
240 BLUETOOTH_PLUGIN_DEFINE(dbusoob, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
241                                                 dbusoob_init, dbusoob_exit)