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;
60 struct connman_network *network;
62 connman_bool_t active;
67 enum connman_ipconfig_method method;
68 struct connman_ipaddress *address;
72 static char *get_ident(const char *path)
79 pos = strrchr(path, '/');
86 static void create_device(struct dundee_data *info)
88 struct connman_device *device;
91 DBG("%s", info->path);
93 ident = g_strdup(get_ident(info->path));
94 device = connman_device_create(ident, CONNMAN_DEVICE_TYPE_BLUETOOTH);
98 DBG("device %p", device);
100 connman_device_set_ident(device, ident);
102 connman_device_set_string(device, "Path", info->path);
104 connman_device_set_data(device, info);
106 if (connman_device_register(device) < 0) {
107 connman_error("Failed to register DUN device");
108 connman_device_unref(device);
112 info->device = device;
118 static void destroy_device(struct dundee_data *info)
120 connman_device_set_powered(info->device, FALSE);
122 if (info->network != NULL) {
123 connman_device_remove_network(info->device, info->network);
124 connman_network_unref(info->network);
125 info->network = NULL;
128 connman_device_unregister(info->device);
129 connman_device_unref(info->device);
134 static void device_destroy(gpointer data)
136 struct dundee_data *info = data;
138 if (info->device != NULL)
139 destroy_device(info);
147 static void create_network(struct dundee_data *info)
149 struct connman_network *network;
152 DBG("%s", info->path);
154 network = connman_network_create(info->path,
155 CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN);
159 DBG("network %p", network);
161 connman_network_set_data(network, info);
163 connman_network_set_string(network, "Path",
166 connman_network_set_name(network, info->name);
168 group = get_ident(info->path);
169 connman_network_set_group(network, group);
171 connman_network_set_available(network, TRUE);
173 if (connman_device_add_network(info->device, network) < 0) {
174 connman_network_unref(network);
178 info->network = network;
181 static void set_connected(struct dundee_data *info)
183 DBG("%s", info->path);
185 connman_inet_ifup(info->index);
187 connman_network_set_index(info->network, info->index);
188 connman_network_set_ipv4_method(info->network,
189 CONNMAN_IPCONFIG_METHOD_FIXED);
190 connman_network_set_ipaddress(info->network, info->address);
191 connman_network_set_nameservers(info->network, info->nameservers);
193 connman_network_set_connected(info->network, TRUE);
196 static void set_disconnected(struct dundee_data *info)
198 DBG("%s", info->path);
200 connman_network_set_connected(info->network, FALSE);
201 connman_inet_ifdown(info->index);
204 static int network_probe(struct connman_network *network)
206 DBG("network %p", network);
211 static void network_remove(struct connman_network *network)
213 DBG("network %p", network);
216 static int network_connect(struct connman_network *network)
218 DBG("network %p", network);
223 static int network_disconnect(struct connman_network *network)
225 DBG("network %p", network);
230 static struct connman_network_driver network_driver = {
232 .type = CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN,
233 .probe = network_probe,
234 .remove = network_remove,
235 .connect = network_connect,
236 .disconnect = network_disconnect,
239 static int dundee_probe(struct connman_device *device)
241 DBG("device %p", device);
246 static void dundee_remove(struct connman_device *device)
248 DBG("device %p", device);
251 static int dundee_enable(struct connman_device *device)
253 DBG("device %p", device);
258 static int dundee_disable(struct connman_device *device)
260 DBG("device %p", device);
265 static struct connman_device_driver dundee_driver = {
267 .type = CONNMAN_DEVICE_TYPE_BLUETOOTH,
268 .probe = dundee_probe,
269 .remove = dundee_remove,
270 .enable = dundee_enable,
271 .disable = dundee_disable,
274 static char *extract_nameservers(DBusMessageIter *array)
276 DBusMessageIter entry;
277 char *nameservers = NULL;
280 dbus_message_iter_recurse(array, &entry);
282 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
283 const char *nameserver;
285 dbus_message_iter_get_basic(&entry, &nameserver);
287 if (nameservers == NULL) {
288 nameservers = g_strdup(nameserver);
291 nameservers = g_strdup_printf("%s %s", tmp, nameserver);
295 dbus_message_iter_next(&entry);
301 static void extract_settings(DBusMessageIter *array,
302 struct dundee_data *info)
304 DBusMessageIter dict;
305 char *address = NULL, *gateway = NULL;
306 char *nameservers = NULL;
307 const char *interface = NULL;
310 if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
313 dbus_message_iter_recurse(array, &dict);
315 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
316 DBusMessageIter entry, value;
317 const char *key, *val;
319 dbus_message_iter_recurse(&dict, &entry);
320 dbus_message_iter_get_basic(&entry, &key);
322 dbus_message_iter_next(&entry);
323 dbus_message_iter_recurse(&entry, &value);
325 if (g_str_equal(key, "Interface") == TRUE) {
326 dbus_message_iter_get_basic(&value, &interface);
328 DBG("Interface %s", interface);
330 index = connman_inet_ifindex(interface);
332 DBG("index %d", index);
336 } else if (g_str_equal(key, "Address") == TRUE) {
337 dbus_message_iter_get_basic(&value, &val);
339 address = g_strdup(val);
341 DBG("Address %s", address);
342 } else if (g_str_equal(key, "DomainNameServers") == TRUE) {
343 nameservers = extract_nameservers(&value);
345 DBG("Nameservers %s", nameservers);
346 } else if (g_str_equal(key, "Gateway") == TRUE) {
347 dbus_message_iter_get_basic(&value, &val);
349 gateway = g_strdup(val);
351 DBG("Gateway %s", gateway);
354 dbus_message_iter_next(&dict);
360 info->address = connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4);
361 if (info->address == NULL)
365 connman_ipaddress_set_ipv4(info->address, address, NULL, gateway);
367 info->nameservers = nameservers;
370 if (info->nameservers != nameservers)
377 static gboolean device_changed(DBusConnection *connection,
378 DBusMessage *message,
381 const char *path = dbus_message_get_path(message);
382 struct dundee_data *info = NULL;
383 DBusMessageIter iter, value;
385 const char *signature = DBUS_TYPE_STRING_AS_STRING
386 DBUS_TYPE_VARIANT_AS_STRING;
388 if (dbus_message_has_signature(message, signature) == FALSE) {
389 connman_error("dundee signature does not match");
393 info = g_hash_table_lookup(dundee_devices, path);
397 if (dbus_message_iter_init(message, &iter) == FALSE)
400 dbus_message_iter_get_basic(&iter, &key);
402 dbus_message_iter_next(&iter);
403 dbus_message_iter_recurse(&iter, &value);
406 * Dundee guarantees the ordering of Settings and
407 * Active. Settings will always be send before Active = True.
408 * That means we don't have to order here.
410 if (g_str_equal(key, "Active") == TRUE) {
411 dbus_message_iter_get_basic(&value, &info->active);
413 DBG("%s Active %d", info->path, info->active);
415 if (info->active == TRUE)
418 set_disconnected(info);
419 } else if (g_str_equal(key, "Settings") == TRUE) {
420 DBG("%s Settings", info->path);
422 extract_settings(&value, info);
423 } else if (g_str_equal(key, "Name") == TRUE) {
426 dbus_message_iter_get_basic(&value, &name);
429 info->name = g_strdup(name);
431 DBG("%s Name %s", info->path, info->name);
433 connman_network_set_name(info->network, info->name);
434 connman_network_update(info->network);
440 static void add_device(const char *path, DBusMessageIter *properties)
442 struct dundee_data *info;
444 info = g_hash_table_lookup(dundee_devices, path);
448 info = g_try_new0(struct dundee_data, 1);
452 info->path = g_strdup(path);
454 while (dbus_message_iter_get_arg_type(properties) ==
455 DBUS_TYPE_DICT_ENTRY) {
456 DBusMessageIter entry, value;
459 dbus_message_iter_recurse(properties, &entry);
460 dbus_message_iter_get_basic(&entry, &key);
462 dbus_message_iter_next(&entry);
463 dbus_message_iter_recurse(&entry, &value);
465 if (g_str_equal(key, "Active") == TRUE) {
466 dbus_message_iter_get_basic(&value, &info->active);
468 DBG("%s Active %d", info->path, info->active);
469 } else if (g_str_equal(key, "Settings") == TRUE) {
470 DBG("%s Settings", info->path);
472 extract_settings(&value, info);
473 } else if (g_str_equal(key, "Name") == TRUE) {
476 dbus_message_iter_get_basic(&value, &name);
478 info->name = g_strdup(name);
480 DBG("%s Name %s", info->path, info->name);
483 dbus_message_iter_next(properties);
486 g_hash_table_insert(dundee_devices, g_strdup(path), info);
489 create_network(info);
491 if (info->active == TRUE)
495 static gboolean device_added(DBusConnection *connection, DBusMessage *message,
498 DBusMessageIter iter, properties;
500 const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING
501 DBUS_TYPE_ARRAY_AS_STRING
502 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
503 DBUS_TYPE_STRING_AS_STRING
504 DBUS_TYPE_VARIANT_AS_STRING
505 DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
507 if (dbus_message_has_signature(message, signature) == FALSE) {
508 connman_error("dundee signature does not match");
514 if (dbus_message_iter_init(message, &iter) == FALSE)
517 dbus_message_iter_get_basic(&iter, &path);
519 dbus_message_iter_next(&iter);
520 dbus_message_iter_recurse(&iter, &properties);
522 add_device(path, &properties);
527 static void remove_device(DBusConnection *connection, const char *path)
529 DBG("path %s", path);
531 g_hash_table_remove(dundee_devices, path);
534 static gboolean device_removed(DBusConnection *connection, DBusMessage *message,
538 const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
540 if (dbus_message_has_signature(message, signature) == FALSE) {
541 connman_error("dundee signature does not match");
545 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
547 remove_device(connection, path);
551 static void manager_get_devices_reply(DBusPendingCall *call, void *user_data)
555 DBusMessageIter array, dict;
556 const char *signature = DBUS_TYPE_ARRAY_AS_STRING
557 DBUS_STRUCT_BEGIN_CHAR_AS_STRING
558 DBUS_TYPE_OBJECT_PATH_AS_STRING
559 DBUS_TYPE_ARRAY_AS_STRING
560 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
561 DBUS_TYPE_STRING_AS_STRING
562 DBUS_TYPE_VARIANT_AS_STRING
563 DBUS_DICT_ENTRY_END_CHAR_AS_STRING
564 DBUS_STRUCT_END_CHAR_AS_STRING;
568 reply = dbus_pending_call_steal_reply(call);
570 if (dbus_message_has_signature(reply, signature) == FALSE) {
571 connman_error("dundee signature does not match");
575 dbus_error_init(&error);
577 if (dbus_set_error_from_message(&error, reply) == TRUE) {
578 connman_error("%s", error.message);
579 dbus_error_free(&error);
583 if (dbus_message_iter_init(reply, &array) == FALSE)
586 dbus_message_iter_recurse(&array, &dict);
588 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
589 DBusMessageIter value, properties;
592 dbus_message_iter_recurse(&dict, &value);
593 dbus_message_iter_get_basic(&value, &path);
595 dbus_message_iter_next(&value);
596 dbus_message_iter_recurse(&value, &properties);
598 add_device(path, &properties);
600 dbus_message_iter_next(&dict);
604 dbus_message_unref(reply);
606 dbus_pending_call_unref(call);
609 static int manager_get_devices(void)
611 DBusMessage *message;
612 DBusPendingCall *call;
616 message = dbus_message_new_method_call(DUNDEE_SERVICE, "/",
617 DUNDEE_MANAGER_INTERFACE, GET_DEVICES);
621 if (dbus_connection_send_with_reply(connection, message,
622 &call, TIMEOUT) == FALSE) {
623 connman_error("Failed to call GetDevices()");
624 dbus_message_unref(message);
629 connman_error("D-Bus connection not available");
630 dbus_message_unref(message);
634 dbus_pending_call_set_notify(call, manager_get_devices_reply,
637 dbus_message_unref(message);
642 static void dundee_connect(DBusConnection *connection, void *user_data)
644 DBG("connection %p", connection);
646 dundee_devices = g_hash_table_new_full(g_str_hash, g_str_equal,
647 g_free, device_destroy);
649 manager_get_devices();
652 static void dundee_disconnect(DBusConnection *connection, void *user_data)
654 DBG("connection %p", connection);
656 g_hash_table_destroy(dundee_devices);
657 dundee_devices = NULL;
661 static guint added_watch;
662 static guint removed_watch;
663 static guint device_watch;
665 static int dundee_init(void)
669 connection = connman_dbus_get_connection();
670 if (connection == NULL)
673 watch = g_dbus_add_service_watch(connection, DUNDEE_SERVICE,
674 dundee_connect, dundee_disconnect, NULL, NULL);
676 added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
677 DUNDEE_MANAGER_INTERFACE,
678 DEVICE_ADDED, device_added,
681 removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
682 DUNDEE_MANAGER_INTERFACE,
683 DEVICE_REMOVED, device_removed,
686 device_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
687 DUNDEE_DEVICE_INTERFACE,
693 if (watch == 0 || added_watch == 0 || removed_watch == 0 ||
699 err = connman_network_driver_register(&network_driver);
703 err = connman_device_driver_register(&dundee_driver);
705 connman_network_driver_unregister(&network_driver);
712 g_dbus_remove_watch(connection, watch);
713 g_dbus_remove_watch(connection, added_watch);
714 g_dbus_remove_watch(connection, removed_watch);
715 g_dbus_remove_watch(connection, device_watch);
717 dbus_connection_unref(connection);
722 static void dundee_exit(void)
724 g_dbus_remove_watch(connection, watch);
725 g_dbus_remove_watch(connection, added_watch);
726 g_dbus_remove_watch(connection, removed_watch);
727 g_dbus_remove_watch(connection, device_watch);
729 connman_device_driver_unregister(&dundee_driver);
730 connman_network_driver_unregister(&network_driver);
732 dbus_connection_unref(connection);
735 CONNMAN_PLUGIN_DEFINE(dundee, "Dundee plugin", VERSION,
736 CONNMAN_PLUGIN_PRIORITY_DEFAULT, dundee_init, dundee_exit)