5 * Copyright (C) 2012 BMW Car IT GmbH. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #define CONNMAN_API_SUBJECT_TO_CHANGE
31 #include <connman/plugin.h>
32 #include <connman/device.h>
33 #include <connman/network.h>
34 #include <connman/dbus.h>
36 #define DUNDEE_SERVICE "org.ofono.dundee"
37 #define DUNDEE_MANAGER_INTERFACE DUNDEE_SERVICE ".Manager"
39 #define DEVICE_ADDED "DeviceAdded"
40 #define DEVICE_REMOVED "DeviceRemoved"
42 #define GET_DEVICES "GetDevices"
46 static DBusConnection *connection;
48 static GHashTable *dundee_devices = NULL;
54 static void device_destroy(gpointer data)
56 struct dundee_data *info = data;
63 static int network_probe(struct connman_network *network)
65 DBG("network %p", network);
70 static void network_remove(struct connman_network *network)
72 DBG("network %p", network);
75 static int network_connect(struct connman_network *network)
77 DBG("network %p", network);
82 static int network_disconnect(struct connman_network *network)
84 DBG("network %p", network);
89 static struct connman_network_driver network_driver = {
91 .type = CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN,
92 .probe = network_probe,
93 .remove = network_remove,
94 .connect = network_connect,
95 .disconnect = network_disconnect,
98 static int dundee_probe(struct connman_device *device)
100 DBG("device %p", device);
105 static void dundee_remove(struct connman_device *device)
107 DBG("device %p", device);
110 static int dundee_enable(struct connman_device *device)
112 DBG("device %p", device);
117 static int dundee_disable(struct connman_device *device)
119 DBG("device %p", device);
124 static struct connman_device_driver dundee_driver = {
126 .type = CONNMAN_DEVICE_TYPE_BLUETOOTH,
127 .probe = dundee_probe,
128 .remove = dundee_remove,
129 .enable = dundee_enable,
130 .disable = dundee_disable,
133 static void add_device(const char *path, DBusMessageIter *properties)
135 struct dundee_data *info;
137 info = g_hash_table_lookup(dundee_devices, path);
141 info = g_try_new0(struct dundee_data, 1);
145 info->path = g_strdup(path);
147 g_hash_table_insert(dundee_devices, g_strdup(path), info);
150 static gboolean device_added(DBusConnection *connection, DBusMessage *message,
153 DBusMessageIter iter, properties;
155 const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING
156 DBUS_TYPE_ARRAY_AS_STRING
157 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
158 DBUS_TYPE_STRING_AS_STRING
159 DBUS_TYPE_VARIANT_AS_STRING
160 DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
162 if (dbus_message_has_signature(message, signature) == FALSE) {
163 connman_error("dundee signature does not match");
169 if (dbus_message_iter_init(message, &iter) == FALSE)
172 dbus_message_iter_get_basic(&iter, &path);
174 dbus_message_iter_next(&iter);
175 dbus_message_iter_recurse(&iter, &properties);
177 add_device(path, &properties);
182 static void remove_device(DBusConnection *connection, const char *path)
184 DBG("path %s", path);
186 g_hash_table_remove(dundee_devices, path);
189 static gboolean device_removed(DBusConnection *connection, DBusMessage *message,
193 const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
195 if (dbus_message_has_signature(message, signature) == FALSE) {
196 connman_error("dundee signature does not match");
200 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
202 remove_device(connection, path);
206 static void manager_get_devices_reply(DBusPendingCall *call, void *user_data)
210 DBusMessageIter array, dict;
211 const char *signature = DBUS_TYPE_ARRAY_AS_STRING
212 DBUS_STRUCT_BEGIN_CHAR_AS_STRING
213 DBUS_TYPE_OBJECT_PATH_AS_STRING
214 DBUS_TYPE_ARRAY_AS_STRING
215 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
216 DBUS_TYPE_STRING_AS_STRING
217 DBUS_TYPE_VARIANT_AS_STRING
218 DBUS_DICT_ENTRY_END_CHAR_AS_STRING
219 DBUS_STRUCT_END_CHAR_AS_STRING;
223 reply = dbus_pending_call_steal_reply(call);
225 if (dbus_message_has_signature(reply, signature) == FALSE) {
226 connman_error("dundee signature does not match");
230 dbus_error_init(&error);
232 if (dbus_set_error_from_message(&error, reply) == TRUE) {
233 connman_error("%s", error.message);
234 dbus_error_free(&error);
238 if (dbus_message_iter_init(reply, &array) == FALSE)
241 dbus_message_iter_recurse(&array, &dict);
243 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
244 DBusMessageIter value, properties;
247 dbus_message_iter_recurse(&dict, &value);
248 dbus_message_iter_get_basic(&value, &path);
250 dbus_message_iter_next(&value);
251 dbus_message_iter_recurse(&value, &properties);
253 add_device(path, &properties);
255 dbus_message_iter_next(&dict);
259 dbus_message_unref(reply);
261 dbus_pending_call_unref(call);
264 static int manager_get_devices(void)
266 DBusMessage *message;
267 DBusPendingCall *call;
271 message = dbus_message_new_method_call(DUNDEE_SERVICE, "/",
272 DUNDEE_MANAGER_INTERFACE, GET_DEVICES);
276 if (dbus_connection_send_with_reply(connection, message,
277 &call, TIMEOUT) == FALSE) {
278 connman_error("Failed to call GetDevices()");
279 dbus_message_unref(message);
284 connman_error("D-Bus connection not available");
285 dbus_message_unref(message);
289 dbus_pending_call_set_notify(call, manager_get_devices_reply,
292 dbus_message_unref(message);
297 static void dundee_connect(DBusConnection *connection, void *user_data)
299 DBG("connection %p", connection);
301 dundee_devices = g_hash_table_new_full(g_str_hash, g_str_equal,
302 g_free, device_destroy);
304 manager_get_devices();
307 static void dundee_disconnect(DBusConnection *connection, void *user_data)
309 DBG("connection %p", connection);
311 g_hash_table_destroy(dundee_devices);
312 dundee_devices = NULL;
316 static guint added_watch;
317 static guint removed_watch;
319 static int dundee_init(void)
323 connection = connman_dbus_get_connection();
324 if (connection == NULL)
327 watch = g_dbus_add_service_watch(connection, DUNDEE_SERVICE,
328 dundee_connect, dundee_disconnect, NULL, NULL);
330 added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
331 DUNDEE_MANAGER_INTERFACE,
332 DEVICE_ADDED, device_added,
335 removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
336 DUNDEE_MANAGER_INTERFACE,
337 DEVICE_REMOVED, device_removed,
340 if (watch == 0 || added_watch == 0 || removed_watch == 0) {
345 err = connman_network_driver_register(&network_driver);
349 err = connman_device_driver_register(&dundee_driver);
351 connman_network_driver_unregister(&network_driver);
358 g_dbus_remove_watch(connection, watch);
359 g_dbus_remove_watch(connection, added_watch);
360 g_dbus_remove_watch(connection, removed_watch);
362 dbus_connection_unref(connection);
367 static void dundee_exit(void)
369 g_dbus_remove_watch(connection, watch);
370 g_dbus_remove_watch(connection, added_watch);
371 g_dbus_remove_watch(connection, removed_watch);
373 connman_device_driver_unregister(&dundee_driver);
374 connman_network_driver_unregister(&network_driver);
376 dbus_connection_unref(connection);
379 CONNMAN_PLUGIN_DEFINE(dundee, "Dundee plugin", VERSION,
380 CONNMAN_PLUGIN_PRIORITY_DEFAULT, dundee_init, dundee_exit)