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
31 #define CONNMAN_API_SUBJECT_TO_CHANGE
32 #include <connman/plugin.h>
33 #include <connman/device.h>
34 #include <connman/network.h>
35 #include <connman/inet.h>
36 #include <connman/dbus.h>
38 #define DUNDEE_SERVICE "org.ofono.dundee"
39 #define DUNDEE_MANAGER_INTERFACE DUNDEE_SERVICE ".Manager"
40 #define DUNDEE_DEVICE_INTERFACE DUNDEE_SERVICE ".Device"
42 #define DEVICE_ADDED "DeviceAdded"
43 #define DEVICE_REMOVED "DeviceRemoved"
44 #define PROPERTY_CHANGED "PropertyChanged"
46 #define GET_PROPERTIES "GetProperties"
47 #define GET_DEVICES "GetDevices"
51 static DBusConnection *connection;
53 static GHashTable *dundee_devices = NULL;
59 struct connman_device *device;
61 connman_bool_t active;
66 enum connman_ipconfig_method method;
67 struct connman_ipaddress *address;
71 static char *get_ident(const char *path)
78 pos = strrchr(path, '/');
85 static void create_device(struct dundee_data *info)
87 struct connman_device *device;
90 DBG("%s", info->path);
92 ident = g_strdup(get_ident(info->path));
93 device = connman_device_create(ident, CONNMAN_DEVICE_TYPE_BLUETOOTH);
97 DBG("device %p", device);
99 connman_device_set_ident(device, ident);
101 connman_device_set_string(device, "Path", info->path);
103 connman_device_set_data(device, info);
105 if (connman_device_register(device) < 0) {
106 connman_error("Failed to register DUN device");
107 connman_device_unref(device);
111 info->device = device;
117 static void destroy_device(struct dundee_data *info)
119 connman_device_set_powered(info->device, FALSE);
121 connman_device_unregister(info->device);
122 connman_device_unref(info->device);
127 static void device_destroy(gpointer data)
129 struct dundee_data *info = data;
131 if (info->device != NULL)
132 destroy_device(info);
140 static int network_probe(struct connman_network *network)
142 DBG("network %p", network);
147 static void network_remove(struct connman_network *network)
149 DBG("network %p", network);
152 static int network_connect(struct connman_network *network)
154 DBG("network %p", network);
159 static int network_disconnect(struct connman_network *network)
161 DBG("network %p", network);
166 static struct connman_network_driver network_driver = {
168 .type = CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN,
169 .probe = network_probe,
170 .remove = network_remove,
171 .connect = network_connect,
172 .disconnect = network_disconnect,
175 static int dundee_probe(struct connman_device *device)
177 DBG("device %p", device);
182 static void dundee_remove(struct connman_device *device)
184 DBG("device %p", device);
187 static int dundee_enable(struct connman_device *device)
189 DBG("device %p", device);
194 static int dundee_disable(struct connman_device *device)
196 DBG("device %p", device);
201 static struct connman_device_driver dundee_driver = {
203 .type = CONNMAN_DEVICE_TYPE_BLUETOOTH,
204 .probe = dundee_probe,
205 .remove = dundee_remove,
206 .enable = dundee_enable,
207 .disable = dundee_disable,
210 static char *extract_nameservers(DBusMessageIter *array)
212 DBusMessageIter entry;
213 char *nameservers = NULL;
216 dbus_message_iter_recurse(array, &entry);
218 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
219 const char *nameserver;
221 dbus_message_iter_get_basic(&entry, &nameserver);
223 if (nameservers == NULL) {
224 nameservers = g_strdup(nameserver);
227 nameservers = g_strdup_printf("%s %s", tmp, nameserver);
231 dbus_message_iter_next(&entry);
237 static void extract_settings(DBusMessageIter *array,
238 struct dundee_data *info)
240 DBusMessageIter dict;
241 char *address = NULL, *gateway = NULL;
242 char *nameservers = NULL;
243 const char *interface = NULL;
246 if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
249 dbus_message_iter_recurse(array, &dict);
251 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
252 DBusMessageIter entry, value;
253 const char *key, *val;
255 dbus_message_iter_recurse(&dict, &entry);
256 dbus_message_iter_get_basic(&entry, &key);
258 dbus_message_iter_next(&entry);
259 dbus_message_iter_recurse(&entry, &value);
261 if (g_str_equal(key, "Interface") == TRUE) {
262 dbus_message_iter_get_basic(&value, &interface);
264 DBG("Interface %s", interface);
266 index = connman_inet_ifindex(interface);
268 DBG("index %d", index);
272 } else if (g_str_equal(key, "Address") == TRUE) {
273 dbus_message_iter_get_basic(&value, &val);
275 address = g_strdup(val);
277 DBG("Address %s", address);
278 } else if (g_str_equal(key, "DomainNameServers") == TRUE) {
279 nameservers = extract_nameservers(&value);
281 DBG("Nameservers %s", nameservers);
282 } else if (g_str_equal(key, "Gateway") == TRUE) {
283 dbus_message_iter_get_basic(&value, &val);
285 gateway = g_strdup(val);
287 DBG("Gateway %s", gateway);
290 dbus_message_iter_next(&dict);
296 info->address = connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4);
297 if (info->address == NULL)
301 connman_ipaddress_set_ipv4(info->address, address, NULL, gateway);
303 info->nameservers = nameservers;
306 if (info->nameservers != nameservers)
313 static gboolean device_changed(DBusConnection *connection,
314 DBusMessage *message,
317 const char *path = dbus_message_get_path(message);
318 struct dundee_data *info = NULL;
319 DBusMessageIter iter, value;
321 const char *signature = DBUS_TYPE_STRING_AS_STRING
322 DBUS_TYPE_VARIANT_AS_STRING;
324 if (dbus_message_has_signature(message, signature) == FALSE) {
325 connman_error("dundee signature does not match");
329 info = g_hash_table_lookup(dundee_devices, path);
333 if (dbus_message_iter_init(message, &iter) == FALSE)
336 dbus_message_iter_get_basic(&iter, &key);
338 dbus_message_iter_next(&iter);
339 dbus_message_iter_recurse(&iter, &value);
342 * Dundee guarantees the ordering of Settings and
343 * Active. Settings will always be send before Active = True.
344 * That means we don't have to order here.
346 if (g_str_equal(key, "Active") == TRUE) {
347 dbus_message_iter_get_basic(&value, &info->active);
349 DBG("%s Active %d", info->path, info->active);
350 } else if (g_str_equal(key, "Settings") == TRUE) {
351 DBG("%s Settings", info->path);
353 extract_settings(&value, info);
354 } else if (g_str_equal(key, "Name") == TRUE) {
357 dbus_message_iter_get_basic(&value, &name);
360 info->name = g_strdup(name);
362 DBG("%s Name %s", info->path, info->name);
368 static void add_device(const char *path, DBusMessageIter *properties)
370 struct dundee_data *info;
372 info = g_hash_table_lookup(dundee_devices, path);
376 info = g_try_new0(struct dundee_data, 1);
380 info->path = g_strdup(path);
382 while (dbus_message_iter_get_arg_type(properties) ==
383 DBUS_TYPE_DICT_ENTRY) {
384 DBusMessageIter entry, value;
387 dbus_message_iter_recurse(properties, &entry);
388 dbus_message_iter_get_basic(&entry, &key);
390 dbus_message_iter_next(&entry);
391 dbus_message_iter_recurse(&entry, &value);
393 if (g_str_equal(key, "Active") == TRUE) {
394 dbus_message_iter_get_basic(&value, &info->active);
396 DBG("%s Active %d", info->path, info->active);
397 } else if (g_str_equal(key, "Settings") == TRUE) {
398 DBG("%s Settings", info->path);
400 extract_settings(&value, info);
401 } else if (g_str_equal(key, "Name") == TRUE) {
404 dbus_message_iter_get_basic(&value, &name);
406 info->name = g_strdup(name);
408 DBG("%s Name %s", info->path, info->name);
411 dbus_message_iter_next(properties);
414 g_hash_table_insert(dundee_devices, g_strdup(path), info);
419 static gboolean device_added(DBusConnection *connection, DBusMessage *message,
422 DBusMessageIter iter, properties;
424 const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING
425 DBUS_TYPE_ARRAY_AS_STRING
426 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
427 DBUS_TYPE_STRING_AS_STRING
428 DBUS_TYPE_VARIANT_AS_STRING
429 DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
431 if (dbus_message_has_signature(message, signature) == FALSE) {
432 connman_error("dundee signature does not match");
438 if (dbus_message_iter_init(message, &iter) == FALSE)
441 dbus_message_iter_get_basic(&iter, &path);
443 dbus_message_iter_next(&iter);
444 dbus_message_iter_recurse(&iter, &properties);
446 add_device(path, &properties);
451 static void remove_device(DBusConnection *connection, const char *path)
453 DBG("path %s", path);
455 g_hash_table_remove(dundee_devices, path);
458 static gboolean device_removed(DBusConnection *connection, DBusMessage *message,
462 const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
464 if (dbus_message_has_signature(message, signature) == FALSE) {
465 connman_error("dundee signature does not match");
469 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
471 remove_device(connection, path);
475 static void manager_get_devices_reply(DBusPendingCall *call, void *user_data)
479 DBusMessageIter array, dict;
480 const char *signature = DBUS_TYPE_ARRAY_AS_STRING
481 DBUS_STRUCT_BEGIN_CHAR_AS_STRING
482 DBUS_TYPE_OBJECT_PATH_AS_STRING
483 DBUS_TYPE_ARRAY_AS_STRING
484 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
485 DBUS_TYPE_STRING_AS_STRING
486 DBUS_TYPE_VARIANT_AS_STRING
487 DBUS_DICT_ENTRY_END_CHAR_AS_STRING
488 DBUS_STRUCT_END_CHAR_AS_STRING;
492 reply = dbus_pending_call_steal_reply(call);
494 if (dbus_message_has_signature(reply, signature) == FALSE) {
495 connman_error("dundee signature does not match");
499 dbus_error_init(&error);
501 if (dbus_set_error_from_message(&error, reply) == TRUE) {
502 connman_error("%s", error.message);
503 dbus_error_free(&error);
507 if (dbus_message_iter_init(reply, &array) == FALSE)
510 dbus_message_iter_recurse(&array, &dict);
512 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
513 DBusMessageIter value, properties;
516 dbus_message_iter_recurse(&dict, &value);
517 dbus_message_iter_get_basic(&value, &path);
519 dbus_message_iter_next(&value);
520 dbus_message_iter_recurse(&value, &properties);
522 add_device(path, &properties);
524 dbus_message_iter_next(&dict);
528 dbus_message_unref(reply);
530 dbus_pending_call_unref(call);
533 static int manager_get_devices(void)
535 DBusMessage *message;
536 DBusPendingCall *call;
540 message = dbus_message_new_method_call(DUNDEE_SERVICE, "/",
541 DUNDEE_MANAGER_INTERFACE, GET_DEVICES);
545 if (dbus_connection_send_with_reply(connection, message,
546 &call, TIMEOUT) == FALSE) {
547 connman_error("Failed to call GetDevices()");
548 dbus_message_unref(message);
553 connman_error("D-Bus connection not available");
554 dbus_message_unref(message);
558 dbus_pending_call_set_notify(call, manager_get_devices_reply,
561 dbus_message_unref(message);
566 static void dundee_connect(DBusConnection *connection, void *user_data)
568 DBG("connection %p", connection);
570 dundee_devices = g_hash_table_new_full(g_str_hash, g_str_equal,
571 g_free, device_destroy);
573 manager_get_devices();
576 static void dundee_disconnect(DBusConnection *connection, void *user_data)
578 DBG("connection %p", connection);
580 g_hash_table_destroy(dundee_devices);
581 dundee_devices = NULL;
585 static guint added_watch;
586 static guint removed_watch;
587 static guint device_watch;
589 static int dundee_init(void)
593 connection = connman_dbus_get_connection();
594 if (connection == NULL)
597 watch = g_dbus_add_service_watch(connection, DUNDEE_SERVICE,
598 dundee_connect, dundee_disconnect, NULL, NULL);
600 added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
601 DUNDEE_MANAGER_INTERFACE,
602 DEVICE_ADDED, device_added,
605 removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
606 DUNDEE_MANAGER_INTERFACE,
607 DEVICE_REMOVED, device_removed,
610 device_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
611 DUNDEE_DEVICE_INTERFACE,
617 if (watch == 0 || added_watch == 0 || removed_watch == 0 ||
623 err = connman_network_driver_register(&network_driver);
627 err = connman_device_driver_register(&dundee_driver);
629 connman_network_driver_unregister(&network_driver);
636 g_dbus_remove_watch(connection, watch);
637 g_dbus_remove_watch(connection, added_watch);
638 g_dbus_remove_watch(connection, removed_watch);
639 g_dbus_remove_watch(connection, device_watch);
641 dbus_connection_unref(connection);
646 static void dundee_exit(void)
648 g_dbus_remove_watch(connection, watch);
649 g_dbus_remove_watch(connection, added_watch);
650 g_dbus_remove_watch(connection, removed_watch);
651 g_dbus_remove_watch(connection, device_watch);
653 connman_device_driver_unregister(&dundee_driver);
654 connman_network_driver_unregister(&network_driver);
656 dbus_connection_unref(connection);
659 CONNMAN_PLUGIN_DEFINE(dundee, "Dundee plugin", VERSION,
660 CONNMAN_PLUGIN_PRIORITY_DEFAULT, dundee_init, dundee_exit)