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/inet.h>
35 #include <connman/dbus.h>
37 #define DUNDEE_SERVICE "org.ofono.dundee"
38 #define DUNDEE_MANAGER_INTERFACE DUNDEE_SERVICE ".Manager"
40 #define DEVICE_ADDED "DeviceAdded"
41 #define DEVICE_REMOVED "DeviceRemoved"
43 #define GET_DEVICES "GetDevices"
47 static DBusConnection *connection;
49 static GHashTable *dundee_devices = NULL;
55 connman_bool_t active;
60 enum connman_ipconfig_method method;
61 struct connman_ipaddress *address;
65 static void device_destroy(gpointer data)
67 struct dundee_data *info = data;
75 static int network_probe(struct connman_network *network)
77 DBG("network %p", network);
82 static void network_remove(struct connman_network *network)
84 DBG("network %p", network);
87 static int network_connect(struct connman_network *network)
89 DBG("network %p", network);
94 static int network_disconnect(struct connman_network *network)
96 DBG("network %p", network);
101 static struct connman_network_driver network_driver = {
103 .type = CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN,
104 .probe = network_probe,
105 .remove = network_remove,
106 .connect = network_connect,
107 .disconnect = network_disconnect,
110 static int dundee_probe(struct connman_device *device)
112 DBG("device %p", device);
117 static void dundee_remove(struct connman_device *device)
119 DBG("device %p", device);
122 static int dundee_enable(struct connman_device *device)
124 DBG("device %p", device);
129 static int dundee_disable(struct connman_device *device)
131 DBG("device %p", device);
136 static struct connman_device_driver dundee_driver = {
138 .type = CONNMAN_DEVICE_TYPE_BLUETOOTH,
139 .probe = dundee_probe,
140 .remove = dundee_remove,
141 .enable = dundee_enable,
142 .disable = dundee_disable,
145 static char *extract_nameservers(DBusMessageIter *array)
147 DBusMessageIter entry;
148 char *nameservers = NULL;
151 dbus_message_iter_recurse(array, &entry);
153 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
154 const char *nameserver;
156 dbus_message_iter_get_basic(&entry, &nameserver);
158 if (nameservers == NULL) {
159 nameservers = g_strdup(nameserver);
162 nameservers = g_strdup_printf("%s %s", tmp, nameserver);
166 dbus_message_iter_next(&entry);
172 static void extract_settings(DBusMessageIter *array,
173 struct dundee_data *info)
175 DBusMessageIter dict;
176 char *address = NULL, *gateway = NULL;
177 char *nameservers = NULL;
178 const char *interface = NULL;
181 if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
184 dbus_message_iter_recurse(array, &dict);
186 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
187 DBusMessageIter entry, value;
188 const char *key, *val;
190 dbus_message_iter_recurse(&dict, &entry);
191 dbus_message_iter_get_basic(&entry, &key);
193 dbus_message_iter_next(&entry);
194 dbus_message_iter_recurse(&entry, &value);
196 if (g_str_equal(key, "Interface") == TRUE) {
197 dbus_message_iter_get_basic(&value, &interface);
199 DBG("Interface %s", interface);
201 index = connman_inet_ifindex(interface);
203 DBG("index %d", index);
207 } else if (g_str_equal(key, "Address") == TRUE) {
208 dbus_message_iter_get_basic(&value, &val);
210 address = g_strdup(val);
212 DBG("Address %s", address);
213 } else if (g_str_equal(key, "DomainNameServers") == TRUE) {
214 nameservers = extract_nameservers(&value);
216 DBG("Nameservers %s", nameservers);
217 } else if (g_str_equal(key, "Gateway") == TRUE) {
218 dbus_message_iter_get_basic(&value, &val);
220 gateway = g_strdup(val);
222 DBG("Gateway %s", gateway);
225 dbus_message_iter_next(&dict);
231 info->address = connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4);
232 if (info->address == NULL)
236 connman_ipaddress_set_ipv4(info->address, address, NULL, gateway);
238 info->nameservers = nameservers;
241 if (info->nameservers != nameservers)
248 static void add_device(const char *path, DBusMessageIter *properties)
250 struct dundee_data *info;
252 info = g_hash_table_lookup(dundee_devices, path);
256 info = g_try_new0(struct dundee_data, 1);
260 info->path = g_strdup(path);
262 while (dbus_message_iter_get_arg_type(properties) ==
263 DBUS_TYPE_DICT_ENTRY) {
264 DBusMessageIter entry, value;
267 dbus_message_iter_recurse(properties, &entry);
268 dbus_message_iter_get_basic(&entry, &key);
270 dbus_message_iter_next(&entry);
271 dbus_message_iter_recurse(&entry, &value);
273 if (g_str_equal(key, "Active") == TRUE) {
274 dbus_message_iter_get_basic(&value, &info->active);
276 DBG("%s Active %d", info->path, info->active);
277 } else if (g_str_equal(key, "Settings") == TRUE) {
278 DBG("%s Settings", info->path);
280 extract_settings(&value, info);
281 } else if (g_str_equal(key, "Name") == TRUE) {
284 dbus_message_iter_get_basic(&value, &name);
286 info->name = g_strdup(name);
288 DBG("%s Name %s", info->path, info->name);
291 dbus_message_iter_next(properties);
294 g_hash_table_insert(dundee_devices, g_strdup(path), info);
297 static gboolean device_added(DBusConnection *connection, DBusMessage *message,
300 DBusMessageIter iter, properties;
302 const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING
303 DBUS_TYPE_ARRAY_AS_STRING
304 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
305 DBUS_TYPE_STRING_AS_STRING
306 DBUS_TYPE_VARIANT_AS_STRING
307 DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
309 if (dbus_message_has_signature(message, signature) == FALSE) {
310 connman_error("dundee signature does not match");
316 if (dbus_message_iter_init(message, &iter) == FALSE)
319 dbus_message_iter_get_basic(&iter, &path);
321 dbus_message_iter_next(&iter);
322 dbus_message_iter_recurse(&iter, &properties);
324 add_device(path, &properties);
329 static void remove_device(DBusConnection *connection, const char *path)
331 DBG("path %s", path);
333 g_hash_table_remove(dundee_devices, path);
336 static gboolean device_removed(DBusConnection *connection, DBusMessage *message,
340 const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
342 if (dbus_message_has_signature(message, signature) == FALSE) {
343 connman_error("dundee signature does not match");
347 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
349 remove_device(connection, path);
353 static void manager_get_devices_reply(DBusPendingCall *call, void *user_data)
357 DBusMessageIter array, dict;
358 const char *signature = DBUS_TYPE_ARRAY_AS_STRING
359 DBUS_STRUCT_BEGIN_CHAR_AS_STRING
360 DBUS_TYPE_OBJECT_PATH_AS_STRING
361 DBUS_TYPE_ARRAY_AS_STRING
362 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
363 DBUS_TYPE_STRING_AS_STRING
364 DBUS_TYPE_VARIANT_AS_STRING
365 DBUS_DICT_ENTRY_END_CHAR_AS_STRING
366 DBUS_STRUCT_END_CHAR_AS_STRING;
370 reply = dbus_pending_call_steal_reply(call);
372 if (dbus_message_has_signature(reply, signature) == FALSE) {
373 connman_error("dundee signature does not match");
377 dbus_error_init(&error);
379 if (dbus_set_error_from_message(&error, reply) == TRUE) {
380 connman_error("%s", error.message);
381 dbus_error_free(&error);
385 if (dbus_message_iter_init(reply, &array) == FALSE)
388 dbus_message_iter_recurse(&array, &dict);
390 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
391 DBusMessageIter value, properties;
394 dbus_message_iter_recurse(&dict, &value);
395 dbus_message_iter_get_basic(&value, &path);
397 dbus_message_iter_next(&value);
398 dbus_message_iter_recurse(&value, &properties);
400 add_device(path, &properties);
402 dbus_message_iter_next(&dict);
406 dbus_message_unref(reply);
408 dbus_pending_call_unref(call);
411 static int manager_get_devices(void)
413 DBusMessage *message;
414 DBusPendingCall *call;
418 message = dbus_message_new_method_call(DUNDEE_SERVICE, "/",
419 DUNDEE_MANAGER_INTERFACE, GET_DEVICES);
423 if (dbus_connection_send_with_reply(connection, message,
424 &call, TIMEOUT) == FALSE) {
425 connman_error("Failed to call GetDevices()");
426 dbus_message_unref(message);
431 connman_error("D-Bus connection not available");
432 dbus_message_unref(message);
436 dbus_pending_call_set_notify(call, manager_get_devices_reply,
439 dbus_message_unref(message);
444 static void dundee_connect(DBusConnection *connection, void *user_data)
446 DBG("connection %p", connection);
448 dundee_devices = g_hash_table_new_full(g_str_hash, g_str_equal,
449 g_free, device_destroy);
451 manager_get_devices();
454 static void dundee_disconnect(DBusConnection *connection, void *user_data)
456 DBG("connection %p", connection);
458 g_hash_table_destroy(dundee_devices);
459 dundee_devices = NULL;
463 static guint added_watch;
464 static guint removed_watch;
466 static int dundee_init(void)
470 connection = connman_dbus_get_connection();
471 if (connection == NULL)
474 watch = g_dbus_add_service_watch(connection, DUNDEE_SERVICE,
475 dundee_connect, dundee_disconnect, NULL, NULL);
477 added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
478 DUNDEE_MANAGER_INTERFACE,
479 DEVICE_ADDED, device_added,
482 removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
483 DUNDEE_MANAGER_INTERFACE,
484 DEVICE_REMOVED, device_removed,
487 if (watch == 0 || added_watch == 0 || removed_watch == 0) {
492 err = connman_network_driver_register(&network_driver);
496 err = connman_device_driver_register(&dundee_driver);
498 connman_network_driver_unregister(&network_driver);
505 g_dbus_remove_watch(connection, watch);
506 g_dbus_remove_watch(connection, added_watch);
507 g_dbus_remove_watch(connection, removed_watch);
509 dbus_connection_unref(connection);
514 static void dundee_exit(void)
516 g_dbus_remove_watch(connection, watch);
517 g_dbus_remove_watch(connection, added_watch);
518 g_dbus_remove_watch(connection, removed_watch);
520 connman_device_driver_unregister(&dundee_driver);
521 connman_network_driver_unregister(&network_driver);
523 dbus_connection_unref(connection);
526 CONNMAN_PLUGIN_DEFINE(dundee, "Dundee plugin", VERSION,
527 CONNMAN_PLUGIN_PRIORITY_DEFAULT, dundee_init, dundee_exit)