ofono: Attach device to core
[platform/upstream/connman.git] / plugins / ofono.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *  Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
7  *
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.
11  *
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.
16  *
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
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <errno.h>
28 #include <stdlib.h>
29
30 #include <gdbus.h>
31 #include <string.h>
32 #include <stdint.h>
33
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>
40
41 #define uninitialized_var(x) x = x
42
43 #define OFONO_SERVICE                   "org.ofono"
44
45 #define OFONO_MANAGER_INTERFACE         OFONO_SERVICE ".Manager"
46 #define OFONO_MODEM_INTERFACE           OFONO_SERVICE ".Modem"
47 #define OFONO_SIM_INTERFACE             OFONO_SERVICE ".SimManager"
48 #define OFONO_NETREG_INTERFACE          OFONO_SERVICE ".NetworkRegistration"
49 #define OFONO_CM_INTERFACE              OFONO_SERVICE ".ConnectionManager"
50 #define OFONO_CONTEXT_INTERFACE         OFONO_SERVICE ".ConnectionContext"
51
52 #define MODEM_ADDED                     "ModemAdded"
53 #define MODEM_REMOVED                   "ModemRemoved"
54 #define PROPERTY_CHANGED                "PropertyChanged"
55 #define CONTEXT_ADDED                   "ContextAdded"
56 #define CONTEXT_REMOVED                 "ContextRemoved"
57
58 #define GET_PROPERTIES                  "GetProperties"
59 #define SET_PROPERTY                    "SetProperty"
60 #define GET_MODEMS                      "GetModems"
61
62 #define TIMEOUT 40000
63
64 enum ofono_api {
65         OFONO_API_SIM =         0x1,
66         OFONO_API_NETREG =      0x2,
67         OFONO_API_CM =          0x4,
68 };
69
70 static DBusConnection *connection;
71
72 static GHashTable *modem_hash;
73
74 struct modem_data {
75         char *path;
76
77         struct connman_device *device;
78
79         /* Modem Interface */
80         char *serial;
81         connman_bool_t powered;
82         connman_bool_t online;
83         uint8_t interfaces;
84
85         connman_bool_t set_powered;
86         connman_bool_t set_online;
87
88         /* SimManager Interface */
89         char *imsi;
90
91         /* pending calls */
92         DBusPendingCall *call_set_property;
93         DBusPendingCall *call_get_properties;
94 };
95
96 typedef void (*set_property_cb)(struct modem_data *data,
97                                 connman_bool_t success);
98 typedef void (*get_properties_cb)(struct modem_data *data,
99                                 DBusMessageIter *dict);
100
101 struct property_info {
102         struct modem_data *modem;
103         const char *path;
104         const char *interface;
105         const char *property;
106         set_property_cb set_property_cb;
107         get_properties_cb get_properties_cb;
108 };
109
110 static void set_property_reply(DBusPendingCall *call, void *user_data)
111 {
112         struct property_info *info = user_data;
113         DBusMessage *reply;
114         DBusError error;
115         connman_bool_t success = TRUE;
116
117         DBG("%s path %s %s.%s", info->modem->path,
118                 info->path, info->interface, info->property);
119
120         info->modem->call_set_property = NULL;
121
122         dbus_error_init(&error);
123
124         reply = dbus_pending_call_steal_reply(call);
125
126         if (dbus_set_error_from_message(&error, reply)) {
127                 connman_error("Failed to change property: %s %s.%s: %s %s",
128                                 info->path, info->interface, info->property,
129                                 error.name, error.message);
130                 dbus_error_free(&error);
131                 success = FALSE;
132         }
133
134         if (info->set_property_cb != NULL)
135                 (*info->set_property_cb)(info->modem, success);
136
137         dbus_message_unref(reply);
138
139         dbus_pending_call_unref(call);
140 }
141
142 static int set_property(struct modem_data *modem,
143                         const char *path, const char *interface,
144                         const char *property, int type, void *value,
145                         set_property_cb notify)
146 {
147         DBusMessage *message;
148         DBusMessageIter iter;
149         struct property_info *info;
150
151         DBG("%s path %s %s.%s", modem->path, path, interface, property);
152
153         if (modem->call_set_property != NULL) {
154                 connman_error("Pending SetProperty");
155                 return -EBUSY;
156         }
157
158         message = dbus_message_new_method_call(OFONO_SERVICE, path,
159                                         interface, SET_PROPERTY);
160         if (message == NULL)
161                 return -ENOMEM;
162
163         dbus_message_iter_init_append(message, &iter);
164         connman_dbus_property_append_basic(&iter, property, type, value);
165
166         if (dbus_connection_send_with_reply(connection, message,
167                         &modem->call_set_property, TIMEOUT) == FALSE) {
168                 connman_error("Failed to change property: %s %s.%s",
169                                 path, interface, property);
170                 dbus_message_unref(message);
171                 return -EINVAL;
172         }
173
174         if (modem->call_set_property == NULL) {
175                 connman_error("D-Bus connection not available");
176                 dbus_message_unref(message);
177                 return -EINVAL;
178         }
179
180         info = g_try_new0(struct property_info, 1);
181         if (info == NULL) {
182                 dbus_message_unref(message);
183                 return -ENOMEM;
184         }
185
186         info->modem = modem;
187         info->path = path;
188         info->interface = interface;
189         info->property = property;
190         info->set_property_cb = notify;
191
192         dbus_pending_call_set_notify(modem->call_set_property,
193                                         set_property_reply, info, g_free);
194
195         dbus_message_unref(message);
196
197         return -EINPROGRESS;
198 }
199
200 static void get_properties_reply(DBusPendingCall *call, void *user_data)
201 {
202         struct property_info *info = user_data;
203         DBusMessageIter array, dict;
204         DBusMessage *reply;
205         DBusError error;
206
207         DBG("%s path %s %s", info->modem->path, info->path, info->interface);
208
209         info->modem->call_get_properties = NULL;
210
211         dbus_error_init(&error);
212
213         reply = dbus_pending_call_steal_reply(call);
214
215         if (dbus_set_error_from_message(&error, reply)) {
216                 connman_error("Failed to get properties: %s %s: %s %s",
217                                 info->path, info->interface,
218                                 error.name, error.message);
219                 dbus_error_free(&error);
220
221                 goto done;
222         }
223
224         if (dbus_message_iter_init(reply, &array) == FALSE)
225                 goto done;
226
227         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
228                 goto done;
229
230         dbus_message_iter_recurse(&array, &dict);
231
232         if (info->get_properties_cb != NULL)
233                 (*info->get_properties_cb)(info->modem, &dict);
234
235 done:
236
237         dbus_message_unref(reply);
238
239         dbus_pending_call_unref(call);
240 }
241
242 static int get_properties(const char *path, const char *interface,
243                                 get_properties_cb notify,
244                                 struct modem_data *modem)
245 {
246         DBusMessage *message;
247         struct property_info *info;
248
249         DBG("%s path %s %s", modem->path, path, interface);
250
251         if (modem->call_get_properties != NULL) {
252                 connman_error("Pending GetProperties");
253                 return -EBUSY;
254         }
255
256         message = dbus_message_new_method_call(OFONO_SERVICE, path,
257                                         interface, GET_PROPERTIES);
258         if (message == NULL)
259                 return -ENOMEM;
260
261         if (dbus_connection_send_with_reply(connection, message,
262                         &modem->call_get_properties, TIMEOUT) == FALSE) {
263                 connman_error("Failed to call %s.GetProperties()", interface);
264                 dbus_message_unref(message);
265                 return -EINVAL;
266         }
267
268         if (modem->call_get_properties == NULL) {
269                 connman_error("D-Bus connection not available");
270                 dbus_message_unref(message);
271                 return -EINVAL;
272         }
273
274         info = g_try_new0(struct property_info, 1);
275         if (info == NULL) {
276                 dbus_message_unref(message);
277                 return -ENOMEM;
278         }
279
280         info->modem = modem;
281         info->path = path;
282         info->interface = interface;
283         info->get_properties_cb = notify;
284
285         dbus_pending_call_set_notify(modem->call_get_properties,
286                                         get_properties_reply, info, g_free);
287
288         dbus_message_unref(message);
289
290         return -EINPROGRESS;
291 }
292
293 static void modem_set_online_reply(struct modem_data *modem,
294                                         connman_bool_t success)
295 {
296         DBG("%s", modem->path);
297
298         if (success == TRUE) {
299                 /*
300                  * Don't handle do anything on success here. oFono will send
301                  * the change via PropertyChanged singal.
302                  */
303                 return;
304         }
305
306         modem->set_online = FALSE;
307 }
308
309 static int modem_set_online(struct modem_data *modem)
310 {
311         DBG("%s", modem->path);
312
313         modem->set_online = TRUE;
314
315         return set_property(modem, modem->path,
316                                 OFONO_MODEM_INTERFACE,
317                                 "Online", DBUS_TYPE_BOOLEAN,
318                                 &modem->set_online,
319                                 modem_set_online_reply);
320 }
321
322 static int modem_set_powered(struct modem_data *modem)
323 {
324         DBG("%s", modem->path);
325
326         modem->set_powered = TRUE;
327
328         return set_property(modem, modem->path,
329                                 OFONO_MODEM_INTERFACE,
330                                 "Powered", DBUS_TYPE_BOOLEAN,
331                                 &modem->set_powered,
332                                 NULL);
333 }
334
335 static connman_bool_t has_interface(uint8_t interfaces,
336                                         enum ofono_api api)
337 {
338         if ((interfaces & api) == api)
339                 return TRUE;
340
341         return FALSE;
342 }
343
344 static uint8_t extract_interfaces(DBusMessageIter *array)
345 {
346         DBusMessageIter entry;
347         uint8_t interfaces = 0;
348
349         dbus_message_iter_recurse(array, &entry);
350
351         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
352                 const char *name;
353
354                 dbus_message_iter_get_basic(&entry, &name);
355
356                 if (g_str_equal(name, OFONO_SIM_INTERFACE) == TRUE)
357                         interfaces |= OFONO_API_SIM;
358                 else if (g_str_equal(name, OFONO_NETREG_INTERFACE) == TRUE)
359                         interfaces |= OFONO_API_NETREG;
360                 else if (g_str_equal(name, OFONO_CM_INTERFACE) == TRUE)
361                         interfaces |= OFONO_API_CM;
362
363                 dbus_message_iter_next(&entry);
364         }
365
366         return interfaces;
367 }
368
369 static connman_bool_t ready_to_create_device(struct modem_data *modem)
370 {
371         /*
372          * There are three different modem types which behave slightly
373          * different:
374          * - GSM modems will expose the SIM interface then the
375          *   CM interface.
376          * - DUN modems will expose first a unique serial number (BDADDR)
377          *   and then the CM interface.
378          * - CDMA modems will expose CM first and sometime later
379          *   a unique serial number.
380          *
381          * This functions tests if we have the necessary information gathered
382          * before we are able to create a device.
383          */
384
385         if (modem->device != NULL)
386                 return FALSE;
387
388         if (modem->imsi != NULL || modem->serial != NULL)
389                 return TRUE;
390
391         return FALSE;
392 }
393
394 static void create_device(struct modem_data *modem)
395 {
396         struct connman_device *device;
397         char *uninitialized_var(ident);
398
399         DBG("%s", modem->path);
400
401         if (modem->imsi != NULL)
402                 ident = modem->imsi;
403         else if (modem->serial != NULL)
404                 ident = modem->serial;
405
406         if (connman_dbus_validate_ident(ident) == FALSE)
407                 ident = connman_dbus_encode_string(ident);
408         else
409                 ident = g_strdup(ident);
410
411         device = connman_device_create(ident, CONNMAN_DEVICE_TYPE_CELLULAR);
412         if (device == NULL)
413                 goto out;
414
415         DBG("device %p", device);
416
417         connman_device_set_ident(device, ident);
418
419         connman_device_set_string(device, "Path", modem->path);
420
421         connman_device_set_data(device, modem);
422
423         if (connman_device_register(device) < 0) {
424                 connman_error("Failed to register cellular device");
425                 connman_device_unref(device);
426                 goto out;
427         }
428
429         modem->device = device;
430
431 out:
432         g_free(ident);
433 }
434
435 static void destroy_device(struct modem_data *modem)
436 {
437         DBG("%s", modem->path);
438
439         connman_device_set_powered(modem->device, FALSE);
440
441         connman_device_unregister(modem->device);
442         connman_device_unref(modem->device);
443
444         modem->device = NULL;
445 }
446
447 static gboolean context_changed(DBusConnection *connection,
448                                 DBusMessage *message,
449                                 void *user_data)
450 {
451         return TRUE;
452 }
453
454 static gboolean cm_context_added(DBusConnection *connection,
455                                         DBusMessage *message,
456                                         void *user_data)
457 {
458         return TRUE;
459 }
460
461 static gboolean cm_context_removed(DBusConnection *connection,
462                                         DBusMessage *message,
463                                         void *user_data)
464 {
465         return TRUE;
466 }
467
468 static gboolean netreg_changed(DBusConnection *connection, DBusMessage *message,
469                                 void *user_data)
470 {
471         return TRUE;
472 }
473
474 static gboolean cm_changed(DBusConnection *connection, DBusMessage *message,
475                                 void *user_data)
476 {
477         return TRUE;
478 }
479
480 static void update_sim_imsi(struct modem_data *modem,
481                                 const char *imsi)
482 {
483         DBG("%s imsi %s", modem->path, imsi);
484
485         if (g_strcmp0(modem->imsi, imsi) == 0)
486                 return;
487
488         g_free(modem->imsi);
489         modem->imsi = g_strdup(imsi);
490 }
491
492 static gboolean sim_changed(DBusConnection *connection, DBusMessage *message,
493                                 void *user_data)
494 {
495         const char *path = dbus_message_get_path(message);
496         struct modem_data *modem;
497         DBusMessageIter iter, value;
498         const char *key;
499
500         modem = g_hash_table_lookup(modem_hash, path);
501         if (modem == NULL)
502                 return TRUE;
503
504         if (dbus_message_iter_init(message, &iter) == FALSE)
505                 return TRUE;
506
507         dbus_message_iter_get_basic(&iter, &key);
508
509         dbus_message_iter_next(&iter);
510         dbus_message_iter_recurse(&iter, &value);
511
512         if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
513                 char *imsi;
514
515                 dbus_message_iter_get_basic(&value, &imsi);
516
517                 update_sim_imsi(modem, imsi);
518
519                 if (modem->online == FALSE) {
520                         modem_set_online(modem);
521                 } else if (has_interface(modem->interfaces,
522                                                 OFONO_API_CM) == TRUE) {
523                         if (ready_to_create_device(modem) == TRUE)
524                                 create_device(modem);
525                 }
526         }
527
528         return TRUE;
529 }
530
531 static void sim_properties_reply(struct modem_data *modem,
532                                         DBusMessageIter *dict)
533 {
534         DBG("%s", modem->path);
535
536         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
537                 DBusMessageIter entry, value;
538                 const char *key;
539
540                 dbus_message_iter_recurse(dict, &entry);
541                 dbus_message_iter_get_basic(&entry, &key);
542
543                 dbus_message_iter_next(&entry);
544                 dbus_message_iter_recurse(&entry, &value);
545
546                 if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
547                         char *imsi;
548
549                         dbus_message_iter_get_basic(&value, &imsi);
550
551                         update_sim_imsi(modem, imsi);
552
553                         if (modem->online == FALSE) {
554                                 modem_set_online(modem);
555                                 break;
556                         }
557
558                         if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
559                                 if (ready_to_create_device(modem) == TRUE)
560                                         create_device(modem);
561                         }
562                         return;
563                 }
564
565                 dbus_message_iter_next(dict);
566         }
567 }
568
569 static int sim_get_properties(struct modem_data *modem)
570 {
571         return get_properties(modem->path, OFONO_SIM_INTERFACE,
572                         sim_properties_reply, modem);
573 }
574
575 static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
576                                 void *user_data)
577 {
578         const char *path = dbus_message_get_path(message);
579         struct modem_data *modem;
580         DBusMessageIter iter, value;
581         const char *key;
582
583         modem = g_hash_table_lookup(modem_hash, path);
584         if (modem == NULL)
585                 return TRUE;
586
587         if (dbus_message_iter_init(message, &iter) == FALSE)
588                 return TRUE;
589
590         dbus_message_iter_get_basic(&iter, &key);
591
592         dbus_message_iter_next(&iter);
593         dbus_message_iter_recurse(&iter, &value);
594
595         if (g_str_equal(key, "Powered") == TRUE) {
596                 dbus_message_iter_get_basic(&value, &modem->powered);
597
598                 DBG("%s Powered %d", modem->path, modem->powered);
599
600                 if (modem->powered == FALSE)
601                         modem_set_powered(modem);
602         } else if (g_str_equal(key, "Online") == TRUE) {
603                 dbus_message_iter_get_basic(&value, &modem->online);
604
605                 DBG("%s Online %d", modem->path, modem->online);
606         } else if (g_str_equal(key, "Interfaces") == TRUE) {
607                 modem->interfaces = extract_interfaces(&value);
608
609                 DBG("%s Interfaces 0x%02x", modem->path,
610                         modem->interfaces);
611
612                 if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE) {
613                         if (modem->imsi == NULL &&
614                                         modem->set_powered == FALSE) {
615                                 /*
616                                  * Only use do GetProperties() when
617                                  * device has not been powered up.
618                                  */
619                                 sim_get_properties(modem);
620                                 return TRUE;
621                         }
622                 }
623
624                 if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
625                         if (ready_to_create_device(modem) == TRUE)
626                                 create_device(modem);
627                 } else {
628                         if (modem->device != NULL)
629                                 destroy_device(modem);
630                 }
631         } else if (g_str_equal(key, "Serial") == TRUE) {
632                 char *serial;
633
634                 dbus_message_iter_get_basic(&value, &serial);
635
636                 g_free(modem->serial);
637                 modem->serial = g_strdup(serial);
638
639                 DBG("%s Serial %s", modem->path, modem->serial);
640
641                 if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
642                         if (ready_to_create_device(modem) == TRUE)
643                                 create_device(modem);
644                 }
645         }
646
647         return TRUE;
648 }
649
650 static void add_modem(const char *path, DBusMessageIter *prop)
651 {
652         struct modem_data *modem;
653
654         DBG("%s", path);
655
656         modem = g_hash_table_lookup(modem_hash, path);
657         if (modem != NULL) {
658                 /*
659                  * When oFono powers up we ask for the modems and oFono is
660                  * reporting with modem_added signal the modems. Only
661                  * handle them once.
662                  */
663                 return;
664         }
665
666         modem = g_try_new0(struct modem_data, 1);
667         if (modem == NULL)
668                 return;
669
670         modem->path = g_strdup(path);
671
672         g_hash_table_insert(modem_hash, g_strdup(path), modem);
673
674         while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
675                 DBusMessageIter entry, value;
676                 const char *key;
677
678                 dbus_message_iter_recurse(prop, &entry);
679                 dbus_message_iter_get_basic(&entry, &key);
680
681                 dbus_message_iter_next(&entry);
682                 dbus_message_iter_recurse(&entry, &value);
683
684                 if (g_str_equal(key, "Powered") == TRUE) {
685                         dbus_message_iter_get_basic(&value, &modem->powered);
686
687                         DBG("%s Powered %d", modem->path, modem->powered);
688                 } else if (g_str_equal(key, "Online") == TRUE) {
689                         dbus_message_iter_get_basic(&value, &modem->online);
690
691                         DBG("%s Online %d", modem->path, modem->online);
692                 } else if (g_str_equal(key, "Interfaces") == TRUE) {
693                         modem->interfaces = extract_interfaces(&value);
694
695                         DBG("%s Interfaces 0x%02x", modem->path,
696                                 modem->interfaces);
697                 } else if (g_str_equal(key, "Serial") == TRUE) {
698                         char *serial;
699
700                         dbus_message_iter_get_basic(&value, &serial);
701                         modem->serial = g_strdup(serial);
702
703                         DBG("%s Serial %s", modem->path, modem->serial);
704                 }
705
706                 dbus_message_iter_next(prop);
707         }
708
709         if (modem->powered == FALSE) {
710                 modem_set_powered(modem);
711         } else if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE) {
712                 sim_get_properties(modem);
713         } else if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
714                 if (ready_to_create_device(modem) == TRUE)
715                         create_device(modem);
716         }
717 }
718
719 static void remove_modem(gpointer data)
720 {
721         struct modem_data *modem = data;
722
723         DBG("%s", modem->path);
724
725         if (modem->call_set_property != NULL)
726                 dbus_pending_call_cancel(modem->call_set_property);
727
728         if (modem->call_get_properties != NULL)
729                 dbus_pending_call_cancel(modem->call_get_properties);
730
731         if (modem->device != NULL)
732                 destroy_device(modem);
733
734         g_free(modem->serial);
735         g_free(modem->imsi);
736         g_free(modem->path);
737
738         g_free(modem);
739 }
740
741 static gboolean modem_added(DBusConnection *connection,
742                                 DBusMessage *message, void *user_data)
743 {
744         DBusMessageIter iter, properties;
745         const char *path;
746
747         DBG("");
748
749         if (dbus_message_iter_init(message, &iter) == FALSE)
750                 return TRUE;
751
752         dbus_message_iter_get_basic(&iter, &path);
753
754         dbus_message_iter_next(&iter);
755         dbus_message_iter_recurse(&iter, &properties);
756
757         add_modem(path, &properties);
758
759         return TRUE;
760 }
761
762 static gboolean modem_removed(DBusConnection *connection,
763                                 DBusMessage *message, void *user_data)
764 {
765         DBusMessageIter iter;
766         const char *path;
767
768         DBG("");
769
770         if (dbus_message_iter_init(message, &iter) == FALSE)
771                 return TRUE;
772
773         dbus_message_iter_get_basic(&iter, &path);
774
775         g_hash_table_remove(modem_hash, path);
776
777         return TRUE;
778 }
779
780 static void manager_get_modems_reply(DBusPendingCall *call, void *user_data)
781 {
782         DBusMessage *reply;
783         DBusError error;
784         DBusMessageIter array, dict;
785
786         DBG("");
787
788         reply = dbus_pending_call_steal_reply(call);
789
790         dbus_error_init(&error);
791
792         if (dbus_set_error_from_message(&error, reply) == TRUE) {
793                 connman_error("%s", error.message);
794                 dbus_error_free(&error);
795                 goto done;
796         }
797
798         if (dbus_message_iter_init(reply, &array) == FALSE)
799                 goto done;
800
801         dbus_message_iter_recurse(&array, &dict);
802
803         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
804                 DBusMessageIter value, properties;
805                 const char *path;
806
807                 dbus_message_iter_recurse(&dict, &value);
808                 dbus_message_iter_get_basic(&value, &path);
809
810                 dbus_message_iter_next(&value);
811                 dbus_message_iter_recurse(&value, &properties);
812
813                 add_modem(path, &properties);
814
815                 dbus_message_iter_next(&dict);
816         }
817
818 done:
819         dbus_message_unref(reply);
820
821         dbus_pending_call_unref(call);
822 }
823
824 static int manager_get_modems(void)
825 {
826         DBusMessage *message;
827         DBusPendingCall *call;
828
829         DBG("");
830
831         message = dbus_message_new_method_call(OFONO_SERVICE, "/",
832                                         OFONO_MANAGER_INTERFACE, GET_MODEMS);
833         if (message == NULL)
834                 return -ENOMEM;
835
836         if (dbus_connection_send_with_reply(connection, message,
837                                                &call, TIMEOUT) == FALSE) {
838                 connman_error("Failed to call GetModems()");
839                 dbus_message_unref(message);
840                 return -EINVAL;
841         }
842
843         if (call == NULL) {
844                 connman_error("D-Bus connection not available");
845                 dbus_message_unref(message);
846                 return -EINVAL;
847         }
848
849         dbus_pending_call_set_notify(call, manager_get_modems_reply,
850                                         NULL, NULL);
851
852         dbus_message_unref(message);
853
854         return -EINPROGRESS;
855 }
856
857 static void ofono_connect(DBusConnection *conn, void *user_data)
858 {
859         DBG("");
860
861         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
862                                                 g_free, remove_modem);
863         if (modem_hash == NULL)
864                 return;
865
866         manager_get_modems();
867 }
868
869 static void ofono_disconnect(DBusConnection *conn, void *user_data)
870 {
871         DBG("");
872
873         if (modem_hash == NULL)
874                 return;
875
876         g_hash_table_destroy(modem_hash);
877         modem_hash = NULL;
878 }
879
880 static int network_probe(struct connman_network *network)
881 {
882         DBG("network %p", network);
883
884         return 0;
885 }
886
887 static void network_remove(struct connman_network *network)
888 {
889         DBG("network %p", network);
890 }
891
892 static int network_connect(struct connman_network *network)
893 {
894         DBG("network %p", network);
895
896         return 0;
897 }
898
899 static int network_disconnect(struct connman_network *network)
900 {
901         DBG("network %p", network);
902
903         return 0;
904 }
905
906 static struct connman_network_driver network_driver = {
907         .name           = "network",
908         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
909         .probe          = network_probe,
910         .remove         = network_remove,
911         .connect        = network_connect,
912         .disconnect     = network_disconnect,
913 };
914
915 static int modem_probe(struct connman_device *device)
916 {
917         struct modem_data *modem = connman_device_get_data(device);
918
919         DBG("%s device %p", modem->path, device);
920
921         return 0;
922 }
923
924 static void modem_remove(struct connman_device *device)
925 {
926         struct modem_data *modem = connman_device_get_data(device);
927
928         DBG("%s device %p", modem->path, device);
929 }
930
931 static int modem_enable(struct connman_device *device)
932 {
933         struct modem_data *modem = connman_device_get_data(device);
934
935         DBG("%s device %p", modem->path, device);
936
937         return 0;
938 }
939
940 static int modem_disable(struct connman_device *device)
941 {
942         struct modem_data *modem = connman_device_get_data(device);
943
944         DBG("%s device %p", modem->path, device);
945
946         return 0;
947 }
948
949 static struct connman_device_driver modem_driver = {
950         .name           = "modem",
951         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
952         .probe          = modem_probe,
953         .remove         = modem_remove,
954         .enable         = modem_enable,
955         .disable        = modem_disable,
956 };
957
958 static guint watch;
959 static guint modem_added_watch;
960 static guint modem_removed_watch;
961 static guint modem_watch;
962 static guint cm_watch;
963 static guint sim_watch;
964 static guint context_added_watch;
965 static guint context_removed_watch;
966 static guint netreg_watch;
967 static guint context_watch;
968
969 static int ofono_init(void)
970 {
971         int err;
972
973         DBG("");
974
975         connection = connman_dbus_get_connection();
976         if (connection == NULL)
977                 return -EIO;
978
979         watch = g_dbus_add_service_watch(connection,
980                                         OFONO_SERVICE, ofono_connect,
981                                         ofono_disconnect, NULL, NULL);
982
983         modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
984                                                 OFONO_MANAGER_INTERFACE,
985                                                 MODEM_ADDED,
986                                                 modem_added,
987                                                 NULL, NULL);
988
989         modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
990                                                 OFONO_MANAGER_INTERFACE,
991                                                 MODEM_REMOVED,
992                                                 modem_removed,
993                                                 NULL, NULL);
994
995         modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
996                                                 OFONO_MODEM_INTERFACE,
997                                                 PROPERTY_CHANGED,
998                                                 modem_changed,
999                                                 NULL, NULL);
1000
1001         cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1002                                                 OFONO_CM_INTERFACE,
1003                                                 PROPERTY_CHANGED,
1004                                                 cm_changed,
1005                                                 NULL, NULL);
1006
1007         sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1008                                                 OFONO_SIM_INTERFACE,
1009                                                 PROPERTY_CHANGED,
1010                                                 sim_changed,
1011                                                 NULL, NULL);
1012
1013         context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1014                                                 OFONO_CM_INTERFACE,
1015                                                 CONTEXT_ADDED,
1016                                                 cm_context_added,
1017                                                 NULL, NULL);
1018
1019         context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1020                                                 OFONO_CM_INTERFACE,
1021                                                 CONTEXT_REMOVED,
1022                                                 cm_context_removed,
1023                                                 NULL, NULL);
1024
1025         context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1026                                                 OFONO_CONTEXT_INTERFACE,
1027                                                 PROPERTY_CHANGED,
1028                                                 context_changed,
1029                                                 NULL, NULL);
1030
1031         netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1032                                                 OFONO_NETREG_INTERFACE,
1033                                                 PROPERTY_CHANGED,
1034                                                 netreg_changed,
1035                                                 NULL, NULL);
1036
1037
1038         if (watch == 0 || modem_added_watch == 0 || modem_removed_watch == 0 ||
1039                         modem_watch == 0 || cm_watch == 0 || sim_watch == 0 ||
1040                         context_added_watch == 0 ||
1041                         context_removed_watch == 0 ||
1042                         context_watch == 0 || netreg_watch == 0) {
1043                 err = -EIO;
1044                 goto remove;
1045         }
1046
1047         err = connman_network_driver_register(&network_driver);
1048         if (err < 0)
1049                 goto remove;
1050
1051         err = connman_device_driver_register(&modem_driver);
1052         if (err < 0) {
1053                 connman_network_driver_unregister(&network_driver);
1054                 goto remove;
1055         }
1056
1057         return 0;
1058
1059 remove:
1060         g_dbus_remove_watch(connection, netreg_watch);
1061         g_dbus_remove_watch(connection, context_watch);
1062         g_dbus_remove_watch(connection, context_removed_watch);
1063         g_dbus_remove_watch(connection, context_added_watch);
1064         g_dbus_remove_watch(connection, sim_watch);
1065         g_dbus_remove_watch(connection, cm_watch);
1066         g_dbus_remove_watch(connection, modem_watch);
1067         g_dbus_remove_watch(connection, modem_removed_watch);
1068         g_dbus_remove_watch(connection, modem_added_watch);
1069         g_dbus_remove_watch(connection, watch);
1070         dbus_connection_unref(connection);
1071
1072         return err;
1073 }
1074
1075 static void ofono_exit(void)
1076 {
1077         DBG("");
1078
1079         if (modem_hash != NULL) {
1080                 g_hash_table_destroy(modem_hash);
1081                 modem_hash = NULL;
1082         }
1083
1084         connman_device_driver_unregister(&modem_driver);
1085         connman_network_driver_unregister(&network_driver);
1086
1087         g_dbus_remove_watch(connection, netreg_watch);
1088         g_dbus_remove_watch(connection, context_watch);
1089         g_dbus_remove_watch(connection, context_removed_watch);
1090         g_dbus_remove_watch(connection, context_added_watch);
1091         g_dbus_remove_watch(connection, sim_watch);
1092         g_dbus_remove_watch(connection, cm_watch);
1093         g_dbus_remove_watch(connection, modem_watch);
1094         g_dbus_remove_watch(connection, modem_added_watch);
1095         g_dbus_remove_watch(connection, modem_removed_watch);
1096         g_dbus_remove_watch(connection, watch);
1097
1098         dbus_connection_unref(connection);
1099 }
1100
1101 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
1102                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)