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