5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
6 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #define CONNMAN_API_SUBJECT_TO_CHANGE
35 #include <connman/plugin.h>
36 #include <connman/device.h>
37 #include <connman/network.h>
38 #include <connman/dbus.h>
39 #include <connman/log.h>
41 #define OFONO_SERVICE "org.ofono"
43 #define OFONO_MANAGER_INTERFACE OFONO_SERVICE ".Manager"
44 #define OFONO_MODEM_INTERFACE OFONO_SERVICE ".Modem"
45 #define OFONO_SIM_INTERFACE OFONO_SERVICE ".SimManager"
46 #define OFONO_NETREG_INTERFACE OFONO_SERVICE ".NetworkRegistration"
47 #define OFONO_CM_INTERFACE OFONO_SERVICE ".ConnectionManager"
48 #define OFONO_CONTEXT_INTERFACE OFONO_SERVICE ".ConnectionContext"
50 #define MODEM_ADDED "ModemAdded"
51 #define MODEM_REMOVED "ModemRemoved"
52 #define PROPERTY_CHANGED "PropertyChanged"
53 #define CONTEXT_ADDED "ContextAdded"
54 #define CONTEXT_REMOVED "ContextRemoved"
56 #define GET_PROPERTIES "GetProperties"
57 #define SET_PROPERTY "SetProperty"
58 #define GET_MODEMS "GetModems"
64 OFONO_API_NETREG = 0x2,
68 static DBusConnection *connection;
70 static GHashTable *modem_hash;
77 connman_bool_t powered;
78 connman_bool_t online;
81 connman_bool_t set_powered;
82 connman_bool_t set_online;
84 /* SimManager Interface */
88 DBusPendingCall *call_set_property;
89 DBusPendingCall *call_get_properties;
92 typedef void (*set_property_cb)(struct modem_data *data,
93 connman_bool_t success);
94 typedef void (*get_properties_cb)(struct modem_data *data,
95 DBusMessageIter *dict);
97 struct property_info {
98 struct modem_data *modem;
100 const char *interface;
101 const char *property;
102 set_property_cb set_property_cb;
103 get_properties_cb get_properties_cb;
106 static void set_property_reply(DBusPendingCall *call, void *user_data)
108 struct property_info *info = user_data;
111 connman_bool_t success = TRUE;
113 DBG("%s path %s %s.%s", info->modem->path,
114 info->path, info->interface, info->property);
116 info->modem->call_set_property = NULL;
118 dbus_error_init(&error);
120 reply = dbus_pending_call_steal_reply(call);
122 if (dbus_set_error_from_message(&error, reply)) {
123 connman_error("Failed to change property: %s %s.%s: %s %s",
124 info->path, info->interface, info->property,
125 error.name, error.message);
126 dbus_error_free(&error);
130 if (info->set_property_cb != NULL)
131 (*info->set_property_cb)(info->modem, success);
133 dbus_message_unref(reply);
135 dbus_pending_call_unref(call);
138 static int set_property(struct modem_data *modem,
139 const char *path, const char *interface,
140 const char *property, int type, void *value,
141 set_property_cb notify)
143 DBusMessage *message;
144 DBusMessageIter iter;
145 struct property_info *info;
147 DBG("%s path %s %s.%s", modem->path, path, interface, property);
149 if (modem->call_set_property != NULL) {
150 connman_error("Pending SetProperty");
154 message = dbus_message_new_method_call(OFONO_SERVICE, path,
155 interface, SET_PROPERTY);
159 dbus_message_iter_init_append(message, &iter);
160 connman_dbus_property_append_basic(&iter, property, type, value);
162 if (dbus_connection_send_with_reply(connection, message,
163 &modem->call_set_property, TIMEOUT) == FALSE) {
164 connman_error("Failed to change property: %s %s.%s",
165 path, interface, property);
166 dbus_message_unref(message);
170 if (modem->call_set_property == NULL) {
171 connman_error("D-Bus connection not available");
172 dbus_message_unref(message);
176 info = g_try_new0(struct property_info, 1);
178 dbus_message_unref(message);
184 info->interface = interface;
185 info->property = property;
186 info->set_property_cb = notify;
188 dbus_pending_call_set_notify(modem->call_set_property,
189 set_property_reply, info, g_free);
191 dbus_message_unref(message);
196 static void get_properties_reply(DBusPendingCall *call, void *user_data)
198 struct property_info *info = user_data;
199 DBusMessageIter array, dict;
203 DBG("%s path %s %s", info->modem->path, info->path, info->interface);
205 info->modem->call_get_properties = NULL;
207 dbus_error_init(&error);
209 reply = dbus_pending_call_steal_reply(call);
211 if (dbus_set_error_from_message(&error, reply)) {
212 connman_error("Failed to get properties: %s %s: %s %s",
213 info->path, info->interface,
214 error.name, error.message);
215 dbus_error_free(&error);
220 if (dbus_message_iter_init(reply, &array) == FALSE)
223 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
226 dbus_message_iter_recurse(&array, &dict);
228 if (info->get_properties_cb != NULL)
229 (*info->get_properties_cb)(info->modem, &dict);
233 dbus_message_unref(reply);
235 dbus_pending_call_unref(call);
238 static int get_properties(const char *path, const char *interface,
239 get_properties_cb notify,
240 struct modem_data *modem)
242 DBusMessage *message;
243 struct property_info *info;
245 DBG("%s path %s %s", modem->path, path, interface);
247 if (modem->call_get_properties != NULL) {
248 connman_error("Pending GetProperties");
252 message = dbus_message_new_method_call(OFONO_SERVICE, path,
253 interface, GET_PROPERTIES);
257 if (dbus_connection_send_with_reply(connection, message,
258 &modem->call_get_properties, TIMEOUT) == FALSE) {
259 connman_error("Failed to call %s.GetProperties()", interface);
260 dbus_message_unref(message);
264 if (modem->call_get_properties == NULL) {
265 connman_error("D-Bus connection not available");
266 dbus_message_unref(message);
270 info = g_try_new0(struct property_info, 1);
272 dbus_message_unref(message);
278 info->interface = interface;
279 info->get_properties_cb = notify;
281 dbus_pending_call_set_notify(modem->call_get_properties,
282 get_properties_reply, info, g_free);
284 dbus_message_unref(message);
289 static void modem_set_online_reply(struct modem_data *modem,
290 connman_bool_t success)
292 DBG("%s", modem->path);
294 if (success == TRUE) {
296 * Don't handle do anything on success here. oFono will send
297 * the change via PropertyChanged singal.
302 modem->set_online = FALSE;
305 static int modem_set_online(struct modem_data *modem)
307 DBG("%s", modem->path);
309 modem->set_online = TRUE;
311 return set_property(modem, modem->path,
312 OFONO_MODEM_INTERFACE,
313 "Online", DBUS_TYPE_BOOLEAN,
315 modem_set_online_reply);
318 static int modem_set_powered(struct modem_data *modem)
320 DBG("%s", modem->path);
322 modem->set_powered = TRUE;
324 return set_property(modem, modem->path,
325 OFONO_MODEM_INTERFACE,
326 "Powered", DBUS_TYPE_BOOLEAN,
331 static connman_bool_t has_interface(uint8_t interfaces,
334 if ((interfaces & api) == api)
340 static uint8_t extract_interfaces(DBusMessageIter *array)
342 DBusMessageIter entry;
343 uint8_t interfaces = 0;
345 dbus_message_iter_recurse(array, &entry);
347 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
350 dbus_message_iter_get_basic(&entry, &name);
352 if (g_str_equal(name, OFONO_SIM_INTERFACE) == TRUE)
353 interfaces |= OFONO_API_SIM;
354 else if (g_str_equal(name, OFONO_NETREG_INTERFACE) == TRUE)
355 interfaces |= OFONO_API_NETREG;
356 else if (g_str_equal(name, OFONO_CM_INTERFACE) == TRUE)
357 interfaces |= OFONO_API_CM;
359 dbus_message_iter_next(&entry);
365 static gboolean context_changed(DBusConnection *connection,
366 DBusMessage *message,
372 static gboolean cm_context_added(DBusConnection *connection,
373 DBusMessage *message,
379 static gboolean cm_context_removed(DBusConnection *connection,
380 DBusMessage *message,
386 static gboolean netreg_changed(DBusConnection *connection, DBusMessage *message,
392 static gboolean cm_changed(DBusConnection *connection, DBusMessage *message,
398 static void update_sim_imsi(struct modem_data *modem,
401 DBG("%s imsi %s", modem->path, imsi);
403 if (g_strcmp0(modem->imsi, imsi) == 0)
407 modem->imsi = g_strdup(imsi);
410 static gboolean sim_changed(DBusConnection *connection, DBusMessage *message,
413 const char *path = dbus_message_get_path(message);
414 struct modem_data *modem;
415 DBusMessageIter iter, value;
418 modem = g_hash_table_lookup(modem_hash, path);
422 if (dbus_message_iter_init(message, &iter) == FALSE)
425 dbus_message_iter_get_basic(&iter, &key);
427 dbus_message_iter_next(&iter);
428 dbus_message_iter_recurse(&iter, &value);
430 if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
433 dbus_message_iter_get_basic(&value, &imsi);
435 update_sim_imsi(modem, imsi);
437 if (modem->online == FALSE)
438 modem_set_online(modem);
444 static void sim_properties_reply(struct modem_data *modem,
445 DBusMessageIter *dict)
447 DBG("%s", modem->path);
449 while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
450 DBusMessageIter entry, value;
453 dbus_message_iter_recurse(dict, &entry);
454 dbus_message_iter_get_basic(&entry, &key);
456 dbus_message_iter_next(&entry);
457 dbus_message_iter_recurse(&entry, &value);
459 if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
462 dbus_message_iter_get_basic(&value, &imsi);
464 update_sim_imsi(modem, imsi);
466 if (modem->online == FALSE) {
467 modem_set_online(modem);
474 dbus_message_iter_next(dict);
478 static int sim_get_properties(struct modem_data *modem)
480 return get_properties(modem->path, OFONO_SIM_INTERFACE,
481 sim_properties_reply, modem);
484 static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
487 const char *path = dbus_message_get_path(message);
488 struct modem_data *modem;
489 DBusMessageIter iter, value;
492 modem = g_hash_table_lookup(modem_hash, path);
496 if (dbus_message_iter_init(message, &iter) == FALSE)
499 dbus_message_iter_get_basic(&iter, &key);
501 dbus_message_iter_next(&iter);
502 dbus_message_iter_recurse(&iter, &value);
504 if (g_str_equal(key, "Powered") == TRUE) {
505 dbus_message_iter_get_basic(&value, &modem->powered);
507 DBG("%s Powered %d", modem->path, modem->powered);
509 if (modem->powered == FALSE)
510 modem_set_powered(modem);
511 } else if (g_str_equal(key, "Online") == TRUE) {
512 dbus_message_iter_get_basic(&value, &modem->online);
514 DBG("%s Online %d", modem->path, modem->online);
515 } else if (g_str_equal(key, "Interfaces") == TRUE) {
516 modem->interfaces = extract_interfaces(&value);
518 DBG("%s Interfaces 0x%02x", modem->path,
521 if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE) {
522 if (modem->imsi == NULL &&
523 modem->set_powered == FALSE) {
525 * Only use do GetProperties() when
526 * device has not been powered up.
528 sim_get_properties(modem);
532 } else if (g_str_equal(key, "Serial") == TRUE) {
535 dbus_message_iter_get_basic(&value, &serial);
537 g_free(modem->serial);
538 modem->serial = g_strdup(serial);
540 DBG("%s Serial %s", modem->path, modem->serial);
546 static void add_modem(const char *path, DBusMessageIter *prop)
548 struct modem_data *modem;
552 modem = g_hash_table_lookup(modem_hash, path);
555 * When oFono powers up we ask for the modems and oFono is
556 * reporting with modem_added signal the modems. Only
562 modem = g_try_new0(struct modem_data, 1);
566 modem->path = g_strdup(path);
568 g_hash_table_insert(modem_hash, g_strdup(path), modem);
570 while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
571 DBusMessageIter entry, value;
574 dbus_message_iter_recurse(prop, &entry);
575 dbus_message_iter_get_basic(&entry, &key);
577 dbus_message_iter_next(&entry);
578 dbus_message_iter_recurse(&entry, &value);
580 if (g_str_equal(key, "Powered") == TRUE) {
581 dbus_message_iter_get_basic(&value, &modem->powered);
583 DBG("%s Powered %d", modem->path, modem->powered);
584 } else if (g_str_equal(key, "Online") == TRUE) {
585 dbus_message_iter_get_basic(&value, &modem->online);
587 DBG("%s Online %d", modem->path, modem->online);
588 } else if (g_str_equal(key, "Interfaces") == TRUE) {
589 modem->interfaces = extract_interfaces(&value);
591 DBG("%s Interfaces 0x%02x", modem->path,
593 } else if (g_str_equal(key, "Serial") == TRUE) {
596 dbus_message_iter_get_basic(&value, &serial);
597 modem->serial = g_strdup(serial);
599 DBG("%s Serial %s", modem->path, modem->serial);
602 dbus_message_iter_next(prop);
605 if (modem->powered == FALSE)
606 modem_set_powered(modem);
607 else if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE)
608 sim_get_properties(modem);
611 static void remove_modem(gpointer data)
613 struct modem_data *modem = data;
615 DBG("%s", modem->path);
617 if (modem->call_set_property != NULL)
618 dbus_pending_call_cancel(modem->call_set_property);
620 if (modem->call_get_properties != NULL)
621 dbus_pending_call_cancel(modem->call_get_properties);
623 g_free(modem->serial);
630 static gboolean modem_added(DBusConnection *connection,
631 DBusMessage *message, void *user_data)
633 DBusMessageIter iter, properties;
638 if (dbus_message_iter_init(message, &iter) == FALSE)
641 dbus_message_iter_get_basic(&iter, &path);
643 dbus_message_iter_next(&iter);
644 dbus_message_iter_recurse(&iter, &properties);
646 add_modem(path, &properties);
651 static gboolean modem_removed(DBusConnection *connection,
652 DBusMessage *message, void *user_data)
654 DBusMessageIter iter;
659 if (dbus_message_iter_init(message, &iter) == FALSE)
662 dbus_message_iter_get_basic(&iter, &path);
664 g_hash_table_remove(modem_hash, path);
669 static void manager_get_modems_reply(DBusPendingCall *call, void *user_data)
673 DBusMessageIter array, dict;
677 reply = dbus_pending_call_steal_reply(call);
679 dbus_error_init(&error);
681 if (dbus_set_error_from_message(&error, reply) == TRUE) {
682 connman_error("%s", error.message);
683 dbus_error_free(&error);
687 if (dbus_message_iter_init(reply, &array) == FALSE)
690 dbus_message_iter_recurse(&array, &dict);
692 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
693 DBusMessageIter value, properties;
696 dbus_message_iter_recurse(&dict, &value);
697 dbus_message_iter_get_basic(&value, &path);
699 dbus_message_iter_next(&value);
700 dbus_message_iter_recurse(&value, &properties);
702 add_modem(path, &properties);
704 dbus_message_iter_next(&dict);
708 dbus_message_unref(reply);
710 dbus_pending_call_unref(call);
713 static int manager_get_modems(void)
715 DBusMessage *message;
716 DBusPendingCall *call;
720 message = dbus_message_new_method_call(OFONO_SERVICE, "/",
721 OFONO_MANAGER_INTERFACE, GET_MODEMS);
725 if (dbus_connection_send_with_reply(connection, message,
726 &call, TIMEOUT) == FALSE) {
727 connman_error("Failed to call GetModems()");
728 dbus_message_unref(message);
733 connman_error("D-Bus connection not available");
734 dbus_message_unref(message);
738 dbus_pending_call_set_notify(call, manager_get_modems_reply,
741 dbus_message_unref(message);
746 static void ofono_connect(DBusConnection *conn, void *user_data)
750 modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
751 g_free, remove_modem);
752 if (modem_hash == NULL)
755 manager_get_modems();
758 static void ofono_disconnect(DBusConnection *conn, void *user_data)
762 if (modem_hash == NULL)
765 g_hash_table_destroy(modem_hash);
769 static int network_probe(struct connman_network *network)
771 DBG("network %p", network);
776 static void network_remove(struct connman_network *network)
778 DBG("network %p", network);
781 static int network_connect(struct connman_network *network)
783 DBG("network %p", network);
788 static int network_disconnect(struct connman_network *network)
790 DBG("network %p", network);
795 static struct connman_network_driver network_driver = {
797 .type = CONNMAN_NETWORK_TYPE_CELLULAR,
798 .probe = network_probe,
799 .remove = network_remove,
800 .connect = network_connect,
801 .disconnect = network_disconnect,
804 static int modem_probe(struct connman_device *device)
806 DBG("device %p", device);
811 static void modem_remove(struct connman_device *device)
813 DBG("device %p", device);
816 static int modem_enable(struct connman_device *device)
818 DBG("device %p", device);
823 static int modem_disable(struct connman_device *device)
825 DBG("device %p", device);
830 static struct connman_device_driver modem_driver = {
832 .type = CONNMAN_DEVICE_TYPE_CELLULAR,
833 .probe = modem_probe,
834 .remove = modem_remove,
835 .enable = modem_enable,
836 .disable = modem_disable,
840 static guint modem_added_watch;
841 static guint modem_removed_watch;
842 static guint modem_watch;
843 static guint cm_watch;
844 static guint sim_watch;
845 static guint context_added_watch;
846 static guint context_removed_watch;
847 static guint netreg_watch;
848 static guint context_watch;
850 static int ofono_init(void)
856 connection = connman_dbus_get_connection();
857 if (connection == NULL)
860 watch = g_dbus_add_service_watch(connection,
861 OFONO_SERVICE, ofono_connect,
862 ofono_disconnect, NULL, NULL);
864 modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
865 OFONO_MANAGER_INTERFACE,
870 modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
871 OFONO_MANAGER_INTERFACE,
876 modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
877 OFONO_MODEM_INTERFACE,
882 cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
888 sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
894 context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
900 context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
906 context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
907 OFONO_CONTEXT_INTERFACE,
912 netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
913 OFONO_NETREG_INTERFACE,
919 if (watch == 0 || modem_added_watch == 0 || modem_removed_watch == 0 ||
920 modem_watch == 0 || cm_watch == 0 || sim_watch == 0 ||
921 context_added_watch == 0 ||
922 context_removed_watch == 0 ||
923 context_watch == 0 || netreg_watch == 0) {
928 err = connman_network_driver_register(&network_driver);
932 err = connman_device_driver_register(&modem_driver);
934 connman_network_driver_unregister(&network_driver);
941 g_dbus_remove_watch(connection, netreg_watch);
942 g_dbus_remove_watch(connection, context_watch);
943 g_dbus_remove_watch(connection, context_removed_watch);
944 g_dbus_remove_watch(connection, context_added_watch);
945 g_dbus_remove_watch(connection, sim_watch);
946 g_dbus_remove_watch(connection, cm_watch);
947 g_dbus_remove_watch(connection, modem_watch);
948 g_dbus_remove_watch(connection, modem_removed_watch);
949 g_dbus_remove_watch(connection, modem_added_watch);
950 g_dbus_remove_watch(connection, watch);
951 dbus_connection_unref(connection);
956 static void ofono_exit(void)
960 if (modem_hash != NULL) {
961 g_hash_table_destroy(modem_hash);
965 connman_device_driver_unregister(&modem_driver);
966 connman_network_driver_unregister(&network_driver);
968 g_dbus_remove_watch(connection, netreg_watch);
969 g_dbus_remove_watch(connection, context_watch);
970 g_dbus_remove_watch(connection, context_removed_watch);
971 g_dbus_remove_watch(connection, context_added_watch);
972 g_dbus_remove_watch(connection, sim_watch);
973 g_dbus_remove_watch(connection, cm_watch);
974 g_dbus_remove_watch(connection, modem_watch);
975 g_dbus_remove_watch(connection, modem_added_watch);
976 g_dbus_remove_watch(connection, modem_removed_watch);
977 g_dbus_remove_watch(connection, watch);
979 dbus_connection_unref(connection);
982 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
983 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)