ofono: use Modem Online property
[framework/connectivity/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
29 #include <gdbus.h>
30 #include <string.h>
31
32 #define CONNMAN_API_SUBJECT_TO_CHANGE
33 #include <connman/plugin.h>
34 #include <connman/element.h>
35 #include <connman/device.h>
36 #include <connman/network.h>
37 #include <connman/dbus.h>
38 #include <connman/inet.h>
39 #include <connman/log.h>
40
41 #define OFONO_SERVICE                   "org.ofono"
42
43 #define OFONO_MANAGER_INTERFACE         OFONO_SERVICE ".Manager"
44 #define OFONO_MODEM_INTERFACE           OFONO_SERVICE ".Modem"
45 #define OFONO_GPRS_INTERFACE            OFONO_SERVICE ".DataConnectionManager"
46 #define OFONO_SIM_INTERFACE             OFONO_SERVICE ".SimManager"
47 #define OFONO_PRI_CONTEXT_INTERFACE     OFONO_SERVICE ".PrimaryDataContext"
48 #define OFONO_REGISTRATION_INTERFACE    OFONO_SERVICE ".NetworkRegistration"
49
50 #define PROPERTY_CHANGED                "PropertyChanged"
51 #define GET_PROPERTIES                  "GetProperties"
52 #define SET_PROPERTY                    "SetProperty"
53 #define CREATE_CONTEXT                  "CreateContext"
54
55 #define TIMEOUT 5000
56
57 #define CONTEXT_NAME "3G Connection"
58 #define CONTEXT_TYPE "internet"
59
60 static DBusConnection *connection;
61
62 static GHashTable *modem_hash = NULL;
63
64 struct modem_data {
65         char *path;
66         struct connman_device *device;
67         gboolean has_sim;
68         gboolean has_gprs;
69         gboolean available;
70         gboolean pending_online;
71         gboolean requested_online;
72         gboolean online;
73 };
74
75 static int modem_probe(struct connman_device *device)
76 {
77         DBG("device %p", device);
78
79         return 0;
80 }
81
82 static void modem_remove(struct connman_device *device)
83 {
84         DBG("device %p", device);
85 }
86
87 static int call_ofono(const char *path,
88                         const char *interface, const char *method,
89                         DBusPendingCallNotifyFunction notify, void *user_data,
90                         DBusFreeFunction free_function,
91                         int type, ...)
92 {
93         DBusMessage *message;
94         DBusPendingCall *call;
95         dbus_bool_t ok;
96         va_list va;
97
98         DBG("path %s %s.%s", path, interface, method);
99
100         if (path == NULL)
101                 return -EINVAL;
102
103         message = dbus_message_new_method_call(OFONO_SERVICE, path,
104                                         interface, method);
105         if (message == NULL)
106                 return -ENOMEM;
107
108         dbus_message_set_auto_start(message, FALSE);
109
110         va_start(va, type);
111         ok = dbus_message_append_args_valist(message, type, va);
112         va_end(va);
113
114         if (!ok)
115                 return -ENOMEM;
116
117         if (dbus_connection_send_with_reply(connection, message,
118                                                 &call, TIMEOUT) == FALSE) {
119                 connman_error("Failed to call %s.%s", interface, method);
120                 dbus_message_unref(message);
121                 return -EINVAL;
122         }
123
124         if (call == NULL) {
125                 connman_error("D-Bus connection not available");
126                 dbus_message_unref(message);
127                 return -EINVAL;
128         }
129
130         dbus_pending_call_set_notify(call, notify, user_data, free_function);
131
132         dbus_message_unref(message);
133
134         return -EINPROGRESS;
135 }
136
137 static void set_property_reply(DBusPendingCall *call, void *user_data)
138 {
139         DBusMessage *reply;
140         DBusError error;
141         char const *name = user_data;
142
143         DBG("");
144
145         dbus_error_init(&error);
146
147         reply = dbus_pending_call_steal_reply(call);
148
149         if (dbus_set_error_from_message(&error, reply)) {
150                 connman_error("SetProperty(%s) %s %s", name,
151                                 error.name, error.message);
152                 dbus_error_free(&error);
153         }
154
155         dbus_message_unref(reply);
156
157         dbus_pending_call_unref(call);
158 }
159
160 static int set_property(const char *path, const char *interface,
161                         const char *property, int type, void *value,
162                         DBusPendingCallNotifyFunction notify, void *user_data,
163                         DBusFreeFunction free_function)
164 {
165         DBusMessage *message;
166         DBusMessageIter iter;
167         DBusPendingCall *call;
168
169         DBG("path %s %s.%s", path, interface, property);
170
171         g_assert(notify == NULL ? free_function == NULL : 1);
172
173         if (path == NULL)
174                 return -EINVAL;
175
176         message = dbus_message_new_method_call(OFONO_SERVICE, path,
177                                         interface, SET_PROPERTY);
178         if (message == NULL)
179                 return -ENOMEM;
180
181         dbus_message_set_auto_start(message, FALSE);
182
183         dbus_message_iter_init_append(message, &iter);
184         connman_dbus_property_append_basic(&iter, property, type, value);
185
186         if (dbus_connection_send_with_reply(connection, message,
187                                                 &call, TIMEOUT) == FALSE) {
188                 connman_error("Failed to change \"%s\" property on %s",
189                                 property, interface);
190                 dbus_message_unref(message);
191                 return -EINVAL;
192         }
193
194         if (call == NULL) {
195                 connman_error("D-Bus connection not available");
196                 dbus_message_unref(message);
197                 return -EINVAL;
198         }
199
200         if (notify == NULL) {
201                 notify = set_property_reply;
202                 user_data = (void *)property;
203                 free_function = NULL;
204         }
205
206         dbus_pending_call_set_notify(call, notify, user_data, free_function);
207
208         dbus_message_unref(message);
209
210         return -EINPROGRESS;
211 }
212
213 static void update_modem_online(struct modem_data *modem,
214                                 connman_bool_t online)
215 {
216         DBG("modem %p path %s online %d", modem, modem->path, online);
217
218         modem->online = online;
219         modem->requested_online = online;
220         modem->pending_online = FALSE;
221
222         if (modem->device)
223                 connman_device_set_powered(modem->device, online);
224 }
225
226 static void set_online_reply(DBusPendingCall *call, void *user_data)
227 {
228         struct modem_data *modem;
229         DBusMessage *reply;
230         DBusError error;
231         gboolean result;
232
233         DBG("path %s", (char *)user_data);
234
235         if (modem_hash == NULL)
236                 return;
237
238         modem = g_hash_table_lookup(modem_hash, user_data);
239         if (modem == NULL)
240                 return;
241
242         reply = dbus_pending_call_steal_reply(call);
243
244         dbus_error_init(&error);
245
246         if (dbus_set_error_from_message(&error, reply)) {
247                 connman_error("SetProperty(Online): %s: %s",
248                                 error.name, error.message);
249                 dbus_error_free(&error);
250
251                 result = modem->online;
252         } else
253                 result = modem->requested_online;
254
255         if (modem->pending_online)
256                 update_modem_online(modem, result);
257
258         dbus_message_unref(reply);
259
260         dbus_pending_call_unref(call);
261 }
262
263 static int modem_change_online(char const *path, dbus_bool_t online)
264 {
265         return set_property(path, OFONO_MODEM_INTERFACE, "Online",
266                                 DBUS_TYPE_BOOLEAN, &online,
267                                 set_online_reply,
268                                 (void *)g_strdup(path), g_free);
269 }
270
271 static int modem_enable(struct connman_device *device)
272 {
273         const char *path = connman_device_get_string(device, "Path");
274
275         DBG("device %p, path, %s", device, path);
276
277         return modem_change_online(path, TRUE);
278 }
279
280 static int modem_disable(struct connman_device *device)
281 {
282         const char *path = connman_device_get_string(device, "Path");
283
284         DBG("device %p, path, %s", device, path);
285
286         return modem_change_online(path, FALSE);
287 }
288
289 static struct connman_device_driver modem_driver = {
290         .name           = "modem",
291         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
292         .probe          = modem_probe,
293         .remove         = modem_remove,
294         .enable         = modem_enable,
295         .disable        = modem_disable,
296 };
297
298 static void modem_remove_device(struct modem_data *modem)
299 {
300         DBG("modem %p path %s device %p", modem, modem->path, modem->device);
301
302         if (modem->device == NULL)
303                 return;
304
305         connman_device_remove_all_networks(modem->device);
306         connman_device_unregister(modem->device);
307         connman_device_unref(modem->device);
308
309         modem->device = NULL;
310 }
311
312 static void remove_modem(gpointer data)
313 {
314         struct modem_data *modem = data;
315
316         modem_remove_device(modem);
317
318         g_free(modem->path);
319
320         g_free(modem);
321 }
322
323 static char *get_ident(const char *path)
324 {
325         char *pos;
326
327         if (*path != '/')
328                 return NULL;
329
330         pos = strrchr(path, '/');
331         if (pos == NULL)
332                 return NULL;
333
334         return pos + 1;
335 }
336
337 static void create_service(struct connman_network *network)
338 {
339         const char *path;
340         char *group;
341
342         DBG("");
343
344         path = connman_network_get_string(network, "Path");
345
346         group = get_ident(path);
347
348         connman_network_set_group(network, group);
349 }
350
351 static void set_network_name_reply(DBusPendingCall *call, void *user_data)
352 {
353         struct connman_network *network = user_data;
354         DBusMessage *reply;
355         DBusMessageIter array, dict;
356
357         DBG("network %p", network);
358
359         reply = dbus_pending_call_steal_reply(call);
360
361         if (dbus_message_iter_init(reply, &array) == FALSE)
362                 goto done;
363
364         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
365                 goto done;
366
367         dbus_message_iter_recurse(&array, &dict);
368
369         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
370                 DBusMessageIter entry, value;
371                 const char *key;
372
373                 dbus_message_iter_recurse(&dict, &entry);
374                 dbus_message_iter_get_basic(&entry, &key);
375
376                 dbus_message_iter_next(&entry);
377                 dbus_message_iter_recurse(&entry, &value);
378
379                 /*
380                  * 'Operator' is deprecated since version 0.20, but
381                  * keep it here for backward compatibility reasons.
382                  */
383                 if (g_str_equal(key, "Operator") == TRUE ||
384                                 g_str_equal(key, "Name") == TRUE) {
385                         const char *name;
386
387                         dbus_message_iter_get_basic(&value, &name);
388                         connman_network_set_name(network, name);
389                         create_service(network);
390                 } else if (g_strcmp0(key, "Status") == 0) {
391                         const char *status;
392                         connman_bool_t roaming;
393
394                         dbus_message_iter_get_basic(&value, &status);
395                         if (g_strcmp0(status, "roaming") == 0)
396                                 roaming = TRUE;
397                         else if (g_strcmp0(status, "registered") == 0)
398                                 roaming = FALSE;
399                         else {
400                                 dbus_message_iter_next(&dict);
401                                 continue;
402                         }
403
404                         connman_network_set_roaming(network, roaming);
405                         connman_network_update(network);
406                 }
407
408                 dbus_message_iter_next(&dict);
409         }
410 done:
411         dbus_message_unref(reply);
412
413         dbus_pending_call_unref(call);
414 }
415
416 static void set_network_name(struct connman_network *network)
417 {
418         struct connman_device *device;
419         const char *path;
420
421         device = connman_network_get_device(network);
422
423         path = connman_device_get_string(device, "Path");
424         if (path == NULL)
425                 return;
426
427         DBG("path %s", path);
428
429         call_ofono(path, OFONO_REGISTRATION_INTERFACE, GET_PROPERTIES,
430                         set_network_name_reply, network, NULL,
431                         DBUS_TYPE_INVALID);
432 }
433
434 static void config_network_reply(DBusPendingCall *call, void *user_data)
435 {
436         struct connman_network *network = user_data;
437         DBusMessage *reply;
438         DBusMessageIter array, dict;
439         gboolean internet_type = FALSE;
440
441         DBG("network %p", network);
442
443         reply = dbus_pending_call_steal_reply(call);
444
445         if (dbus_message_iter_init(reply, &array) == FALSE)
446                 goto done;
447
448         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
449                 goto done;
450
451         dbus_message_iter_recurse(&array, &dict);
452
453         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
454                 DBusMessageIter entry, value;
455                 const char *key;
456
457                 dbus_message_iter_recurse(&dict, &entry);
458                 dbus_message_iter_get_basic(&entry, &key);
459
460                 dbus_message_iter_next(&entry);
461                 dbus_message_iter_recurse(&entry, &value);
462
463                 if (g_str_equal(key, "Type") == TRUE) {
464                         const char *type;
465
466                         dbus_message_iter_get_basic(&value, &type);
467                         if (g_strcmp0(type, "internet") == 0) {
468                                 internet_type = TRUE;
469
470                                 connman_network_set_protocol(network,
471                                                 CONNMAN_NETWORK_PROTOCOL_IP);
472                                 set_network_name(network);
473                         } else {
474                                 internet_type = FALSE;
475
476                                 connman_network_set_protocol(network,
477                                         CONNMAN_NETWORK_PROTOCOL_UNKNOWN);
478                         }
479                 }
480
481                 dbus_message_iter_next(&dict);
482         }
483
484 done:
485         dbus_message_unref(reply);
486
487         dbus_pending_call_unref(call);
488 }
489
490 static void config_network(struct connman_network *network, const char *path)
491 {
492         DBG("path %s", path);
493
494         call_ofono(path, OFONO_PRI_CONTEXT_INTERFACE, GET_PROPERTIES,
495                         config_network_reply, network, NULL,
496                         DBUS_TYPE_INVALID);
497 }
498
499 static gboolean registration_changed(DBusConnection *connection,
500                                         DBusMessage *message, void *user_data)
501 {
502         const char *path = dbus_message_get_path(message);
503         struct connman_network *network = user_data;
504         DBusMessageIter iter, value;
505         const char *key;
506
507         DBG("path %s", path);
508
509         if (dbus_message_iter_init(message, &iter) == FALSE)
510                 return TRUE;
511
512         dbus_message_iter_get_basic(&iter, &key);
513
514         DBG("key %s", key);
515
516         dbus_message_iter_next(&iter);
517         dbus_message_iter_recurse(&iter, &value);
518
519         if (g_strcmp0(key, "Name") == 0 ||
520                         g_strcmp0(key, "Operator") == 0) {
521                 const char *name;
522
523                 dbus_message_iter_get_basic(&value, &name);
524                 DBG("name %s", name);
525                 connman_network_set_name(network, name);
526                 create_service(network);
527         } else if (g_strcmp0(key, "Strength") == 0) {
528                 connman_uint8_t strength;
529
530                 dbus_message_iter_get_basic(&value, &strength);
531                 connman_network_set_strength(network, strength);
532                 connman_network_update(network);
533         } else if (g_strcmp0(key, "Status") == 0) {
534                 const char *status;
535                 connman_bool_t roaming;
536
537                 dbus_message_iter_get_basic(&value, &status);
538                 if (g_strcmp0(status, "roaming") == 0)
539                         roaming = TRUE;
540                 else if (g_strcmp0(status, "registered") == 0)
541                         roaming = FALSE;
542                 else
543                         return TRUE;
544
545                 connman_network_set_roaming(network, roaming);
546                 connman_network_update(network);
547         }
548
549         return TRUE;
550 }
551
552 static int network_probe(struct connman_network *network)
553 {
554         const char *path;
555         guint reg_watch;
556
557         reg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
558                                                 OFONO_REGISTRATION_INTERFACE,
559                                                 PROPERTY_CHANGED,
560                                                 registration_changed,
561                                                 network, NULL);
562         if (reg_watch == 0)
563                 return -EIO;
564
565         connman_network_set_data(network, GUINT_TO_POINTER(reg_watch));
566
567         path = connman_network_get_string(network, "Path");
568
569         DBG("network %p path %s", network, path);
570
571         config_network(network, path);
572
573         return 0;
574 }
575
576 static struct connman_network *pending_network;
577
578 static gboolean pending_network_is_available(struct connman_network *network)
579 {
580         /* Modem or network may be removed during waiting for active reply */
581         if (connman_network_get_device(network) == NULL) {
582                 DBG("Modem or network was removed");
583                 return FALSE;
584         }
585
586         return TRUE;
587 }
588
589 static void set_active_reply(DBusPendingCall *call, void *user_data)
590 {
591         DBusMessage *reply;
592         DBusError error;
593         struct connman_network *network = user_data;
594
595         DBG("network %p", network);
596
597         reply = dbus_pending_call_steal_reply(call);
598
599         if (pending_network_is_available(network) == FALSE)
600                 goto done;
601
602         dbus_error_init(&error);
603         if (dbus_set_error_from_message(&error, reply)) {
604                 if (connman_network_get_index(network) < 0)
605                         connman_network_set_error(network,
606                                 CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
607
608                 pending_network = NULL;
609
610                 connman_error("SetProperty(Active) %s %s",
611                                 error.name, error.message);
612
613                 dbus_error_free(&error);
614         } else
615                 pending_network = network;
616
617 done:
618         dbus_message_unref(reply);
619
620         dbus_pending_call_unref(call);
621 }
622
623 static int set_network_active(struct connman_network *network,
624                                                 dbus_bool_t active)
625 {
626         int error;
627
628         const char *path = connman_network_get_string(network, "Path");
629
630         DBG("network %p, path %s, active %d", network, path, active);
631
632         error = set_property(path, OFONO_PRI_CONTEXT_INTERFACE,
633                                 "Active", DBUS_TYPE_BOOLEAN, &active,
634                                 set_active_reply, network, NULL);
635         if (active == FALSE && error == -EINPROGRESS)
636                 error = 0;
637
638         return error;
639 }
640
641 static void set_apn(struct connman_network *network)
642 {
643         const char *apn, *path;
644
645         apn = connman_network_get_string(network, "Cellular.APN");
646         if (apn == NULL)
647                 return;
648
649         path = connman_network_get_string(network, "Path");
650         if (path == NULL)
651                 return;
652
653         DBG("path %s, apn %s", path, apn);
654
655         set_property(path, OFONO_PRI_CONTEXT_INTERFACE,
656                         "AccessPointName", DBUS_TYPE_STRING, &apn,
657                         NULL, NULL, NULL);
658 }
659
660 static int network_connect(struct connman_network *network)
661 {
662         if (connman_network_get_index(network) >= 0)
663                 return -EISCONN;
664
665         return set_network_active(network, TRUE);
666 }
667
668 static int network_disconnect(struct connman_network *network)
669 {
670         if (connman_network_get_index(network) < 0)
671                 return -ENOTCONN;
672
673         return set_network_active(network, FALSE);
674 }
675
676 static void network_remove(struct connman_network *network)
677 {
678         guint reg_watch;
679
680         DBG("network %p", network);
681
682         reg_watch = GPOINTER_TO_UINT(connman_network_get_data(network));
683         g_dbus_remove_watch(connection, reg_watch);
684 }
685
686 static int network_setup(struct connman_network *network, const char *key)
687 {
688         DBG("");
689
690         if (g_strcmp0(key, "Cellular.APN") == 0)
691                 set_apn(network);
692
693         return 0;
694 }
695
696 static struct connman_network_driver network_driver = {
697         .name           = "network",
698         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
699         .probe          = network_probe,
700         .remove         = network_remove,
701         .connect        = network_connect,
702         .disconnect     = network_disconnect,
703         .setup          = network_setup,
704 };
705
706 static void add_network(struct connman_device *device, const char *path)
707 {
708         struct connman_network *network;
709         char *ident;
710
711         DBG("device %p path %s", device, path);
712
713         ident = get_ident(path);
714
715         network = connman_device_get_network(device, ident);
716         if (network != NULL)
717                 return;
718
719         network = connman_network_create(ident, CONNMAN_NETWORK_TYPE_CELLULAR);
720         if (network == NULL)
721                 return;
722
723         if (connman_network_set_string(network, "Path", path) != 0)
724                 goto error;
725
726         connman_network_set_available(network, TRUE);
727         connman_network_set_index(network, -1);
728
729         if (connman_device_add_network(device, network) == 0)
730                 return;
731
732 error:
733         connman_network_unref(network);
734 }
735
736 static void add_networks(struct connman_device *device, DBusMessageIter *array)
737 {
738         DBusMessageIter entry;
739
740         DBG("");
741
742         dbus_message_iter_recurse(array, &entry);
743
744         while (dbus_message_iter_get_arg_type(&entry) ==
745                                         DBUS_TYPE_OBJECT_PATH) {
746                 const char *path;
747
748                 dbus_message_iter_get_basic(&entry, &path);
749
750                 add_network(device, path);
751
752                 dbus_message_iter_next(&entry);
753         }
754 }
755
756 static void create_context_reply(DBusPendingCall *call, void *user_data)
757 {
758         DBusMessage *reply;
759         DBusError error;
760
761         DBG("");
762
763         dbus_error_init(&error);
764
765         reply = dbus_pending_call_steal_reply(call);
766
767         if (dbus_set_error_from_message(&error, reply)) {
768                 connman_error("CreateContext() %s %s",
769                                 error.name, error.message);
770                 dbus_error_free(&error);
771         }
772
773         dbus_message_unref(reply);
774
775         dbus_pending_call_unref(call);
776 }
777
778 static void add_default_context(DBusMessageIter *array,
779                 const char *path, const char *name, const char *type)
780 {
781         DBusMessageIter entry;
782
783         if (path == NULL)
784                 return;
785
786         DBG("");
787
788         dbus_message_iter_recurse(array, &entry);
789
790         if (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_OBJECT_PATH)
791                 return;
792
793         DBG("path %s, name %s, type %s", path, name, type);
794
795         call_ofono(path, OFONO_GPRS_INTERFACE, CREATE_CONTEXT,
796                         create_context_reply, NULL, NULL,
797                         DBUS_TYPE_STRING, &name,
798                         DBUS_TYPE_STRING, &type,
799                         DBUS_TYPE_INVALID);
800 }
801
802 static void check_networks_reply(DBusPendingCall *call, void *user_data)
803 {
804         char *path = user_data;
805         struct modem_data *modem;
806         struct connman_device *device;
807         DBusMessage *reply;
808         DBusMessageIter array, dict, contexts;
809         dbus_bool_t attached;
810
811         DBG("path %s", path);
812
813         modem = g_hash_table_lookup(modem_hash, path);
814         if (modem == NULL || modem->device == NULL)
815                 return;
816
817         device = modem->device;
818
819         reply = dbus_pending_call_steal_reply(call);
820
821         if (dbus_message_iter_init(reply, &array) == FALSE)
822                 goto done;
823
824         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
825                 goto done;
826
827         dbus_message_iter_recurse(&array, &dict);
828
829         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
830                 DBusMessageIter entry, value;
831                 const char *key;
832
833                 dbus_message_iter_recurse(&dict, &entry);
834                 dbus_message_iter_get_basic(&entry, &key);
835
836                 dbus_message_iter_next(&entry);
837                 dbus_message_iter_recurse(&entry, &value);
838
839                 DBG("key %s", key);
840
841                 if (g_str_equal(key, "Attached") == TRUE) {
842                         dbus_message_iter_get_basic(&value, &attached);
843                         DBG("Attached %d", attached);
844                 } else if (g_str_equal(key, "PrimaryContexts") == TRUE) {
845                         const char *path;
846
847                         path = connman_device_get_string(device, "Path");
848                         contexts = value;
849                         add_default_context(&contexts, path,
850                                         CONTEXT_NAME, CONTEXT_TYPE);
851                 }
852
853                 dbus_message_iter_next(&dict);
854         }
855
856         if (attached == TRUE)
857                 add_networks(device, &contexts);
858
859 done:
860         dbus_message_unref(reply);
861
862         dbus_pending_call_unref(call);
863 }
864
865 static void check_networks(struct modem_data *modem)
866 {
867         char const *path = modem->path;
868
869         DBG("modem %p path %s", modem, path);
870
871         call_ofono(path, OFONO_GPRS_INTERFACE, GET_PROPERTIES,
872                         check_networks_reply, g_strdup(path), g_free,
873                         DBUS_TYPE_INVALID);
874 }
875
876 static void add_device(const char *path, const char *imsi)
877 {
878         struct modem_data *modem;
879         struct connman_device *device;
880
881         DBG("path %s imsi %s", path, imsi);
882
883         if (path == NULL)
884                 return;
885
886         if (imsi == NULL)
887                 return;
888
889         modem = g_hash_table_lookup(modem_hash, path);
890         if (modem == NULL)
891                 return;
892
893         if (modem->device) {
894                 if (g_str_equal(imsi, connman_device_get_ident(modem->device)))
895                         return;
896
897                 modem_remove_device(modem);
898         }
899
900         if (strlen(imsi) == 0)
901                 return;
902
903         device = connman_device_create(imsi, CONNMAN_DEVICE_TYPE_CELLULAR);
904         if (device == NULL)
905                 return;
906
907         connman_device_set_ident(device, imsi);
908
909         connman_device_set_mode(device, CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE);
910
911         connman_device_set_string(device, "Path", path);
912
913         if (connman_device_register(device) < 0) {
914                 connman_device_unref(device);
915                 return;
916         }
917
918         modem->device = device;
919
920         if (modem->has_gprs)
921                 check_networks(modem);
922 }
923
924 static void sim_properties_reply(DBusPendingCall *call, void *user_data)
925 {
926         const char *path = user_data;
927         const char *imsi;
928         DBusMessage *reply;
929         DBusMessageIter array, dict;
930
931         DBG("path %s", path);
932
933         reply = dbus_pending_call_steal_reply(call);
934
935         if (dbus_message_iter_init(reply, &array) == FALSE)
936                 goto done;
937
938         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
939                 goto done;
940
941         dbus_message_iter_recurse(&array, &dict);
942
943         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
944                 DBusMessageIter entry, value;
945                 const char *key;
946
947                 dbus_message_iter_recurse(&dict, &entry);
948                 dbus_message_iter_get_basic(&entry, &key);
949
950                 dbus_message_iter_next(&entry);
951                 dbus_message_iter_recurse(&entry, &value);
952
953                 if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
954                         dbus_message_iter_get_basic(&value, &imsi);
955                         add_device(path, imsi);
956                 }
957
958                 dbus_message_iter_next(&dict);
959         }
960
961 done:
962         dbus_message_unref(reply);
963
964         dbus_pending_call_unref(call);
965 }
966
967 static void get_imsi(const char *path)
968 {
969         DBG("path %s", path);
970
971         call_ofono(path, OFONO_SIM_INTERFACE, GET_PROPERTIES,
972                         sim_properties_reply, g_strdup(path), g_free,
973                         DBUS_TYPE_INVALID);
974 }
975
976 static int modem_change_powered(const char *path, dbus_bool_t powered)
977 {
978         DBG("path %s powered %d", path, powered);
979
980         return set_property(path, OFONO_MODEM_INTERFACE, "Powered",
981                                 DBUS_TYPE_BOOLEAN, &powered,
982                                 NULL, NULL, NULL);
983 }
984
985 static struct modem_data *add_modem(const char *path)
986 {
987         struct modem_data *modem;
988
989         DBG("path %s", path);
990
991         if (path == NULL)
992                 return NULL;
993
994         modem = g_hash_table_lookup(modem_hash, path);
995         if (modem != NULL) {
996                 modem->available = TRUE;
997
998                 return modem;
999         }
1000
1001         modem = g_try_new0(struct modem_data, 1);
1002         if (modem == NULL)
1003                 return NULL;
1004
1005         modem->path = g_strdup(path);
1006         modem->device = NULL;
1007         modem->available = TRUE;
1008
1009         g_hash_table_insert(modem_hash, g_strdup(path), modem);
1010
1011         return modem;
1012 }
1013
1014 static gboolean modem_has_interface(DBusMessageIter *array,
1015                                         char const *interface)
1016 {
1017         DBusMessageIter entry;
1018
1019         dbus_message_iter_recurse(array, &entry);
1020
1021         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
1022                 const char *element;
1023
1024                 dbus_message_iter_get_basic(&entry, &element);
1025
1026                 if (g_strcmp0(interface, element) == 0)
1027                         return TRUE;
1028
1029                 dbus_message_iter_next(&entry);
1030         }
1031
1032         return FALSE;
1033 }
1034
1035 static gboolean modem_has_sim(DBusMessageIter *array)
1036 {
1037         return modem_has_interface(array, OFONO_SIM_INTERFACE);
1038 }
1039
1040 static gboolean modem_has_gprs(DBusMessageIter *array)
1041 {
1042         return modem_has_interface(array, OFONO_GPRS_INTERFACE);
1043 }
1044
1045 static void modem_properties_reply(DBusPendingCall *call, void *user_data)
1046 {
1047         DBusMessage *reply;
1048         DBusError error;
1049         DBusMessageIter array, dict;
1050         const char *path = user_data;
1051         dbus_bool_t powered = FALSE;
1052         dbus_bool_t online = FALSE;
1053         dbus_bool_t has_online = FALSE;
1054         gboolean has_sim = FALSE;
1055         gboolean has_gprs = FALSE;
1056         struct modem_data *new_modem;
1057
1058         DBG("path %s", path);
1059
1060         reply = dbus_pending_call_steal_reply(call);
1061
1062         if (g_hash_table_lookup(modem_hash, path))
1063                 goto done;
1064
1065         dbus_error_init(&error);
1066
1067         if (dbus_set_error_from_message(&error, reply)) {
1068                 connman_error("Modem.GetProperties(%s) %s %s",
1069                                 path, error.name, error.message);
1070                 dbus_error_free(&error);
1071                 goto done;
1072         }
1073
1074         if (dbus_message_iter_init(reply, &array) == FALSE)
1075                 goto done;
1076
1077         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
1078                 goto done;
1079
1080         dbus_message_iter_recurse(&array, &dict);
1081
1082         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1083                 DBusMessageIter entry, value;
1084                 const char *key;
1085
1086                 dbus_message_iter_recurse(&dict, &entry);
1087                 dbus_message_iter_get_basic(&entry, &key);
1088
1089                 dbus_message_iter_next(&entry);
1090                 dbus_message_iter_recurse(&entry, &value);
1091
1092                 if (g_str_equal(key, "Powered") == TRUE)
1093                         dbus_message_iter_get_basic(&value, &powered);
1094                 else if (g_str_equal(key, "Online") == TRUE) {
1095                         has_online = TRUE;
1096                         dbus_message_iter_get_basic(&value, &online);
1097                 } else if (g_str_equal(key, "Interfaces") == TRUE) {
1098                         has_sim = modem_has_sim(&value);
1099                         has_gprs = modem_has_gprs(&value);
1100                 }
1101
1102                 dbus_message_iter_next(&dict);
1103         }
1104
1105         new_modem = add_modem(path);
1106         if (new_modem == NULL)
1107                 goto done;
1108
1109         if (!powered)
1110                 modem_change_powered(path, TRUE);
1111
1112         new_modem->has_sim = has_sim;
1113         new_modem->has_gprs = has_gprs;
1114
1115         update_modem_online(new_modem, online);
1116
1117         if (has_sim)
1118                 get_imsi(path);
1119
1120 done:
1121         dbus_message_unref(reply);
1122
1123         dbus_pending_call_unref(call);
1124 }
1125
1126 static void get_modem_properties(const char *path)
1127 {
1128         DBG("path %s", path);
1129
1130         call_ofono(path, OFONO_MODEM_INTERFACE, GET_PROPERTIES,
1131                         modem_properties_reply, g_strdup(path), g_free,
1132                         DBUS_TYPE_INVALID);
1133 }
1134
1135 static void mask_unavailable(gpointer key, gpointer value, gpointer user_data)
1136 {
1137         struct modem_data *modem = value;
1138
1139         modem->available = FALSE;
1140 }
1141
1142 static void modems_set_unavailable()
1143 {
1144         g_hash_table_foreach(modem_hash, mask_unavailable, NULL);
1145 }
1146
1147 static void cleanup_modem(gpointer key, gpointer value, gpointer user_data)
1148 {
1149         struct modem_data *modem = value;
1150
1151         if (modem->available == FALSE)
1152                 g_hash_table_remove(modem_hash, key);
1153 }
1154
1155 static void cleanup_modems()
1156 {
1157         g_hash_table_foreach(modem_hash, cleanup_modem, NULL);
1158 }
1159
1160 static void update_modems(DBusMessageIter *array)
1161 {
1162         DBusMessageIter entry;
1163
1164         DBG("");
1165
1166         dbus_message_iter_recurse(array, &entry);
1167
1168         modems_set_unavailable();
1169
1170         while (dbus_message_iter_get_arg_type(&entry) ==
1171                                         DBUS_TYPE_OBJECT_PATH) {
1172                 const char *path;
1173                 struct modem_data *modem;
1174
1175                 dbus_message_iter_get_basic(&entry, &path);
1176
1177                 modem = g_hash_table_lookup(modem_hash, path);
1178
1179                 if (modem)
1180                         modem->available = TRUE;
1181                 else
1182                         get_modem_properties(path);
1183
1184                 dbus_message_iter_next(&entry);
1185         }
1186
1187         cleanup_modems();
1188 }
1189
1190 static void manager_properties_reply(DBusPendingCall *call, void *user_data)
1191 {
1192         DBusMessage *reply;
1193         DBusError error;
1194         DBusMessageIter array, dict;
1195
1196         DBG("");
1197
1198         reply = dbus_pending_call_steal_reply(call);
1199
1200         dbus_error_init(&error);
1201
1202         if (dbus_set_error_from_message(&error, reply)) {
1203                 connman_error("ModemManager.GetProperties() %s %s",
1204                                 error.name, error.message);
1205                 dbus_error_free(&error);
1206                 goto done;
1207         }
1208
1209         if (dbus_message_iter_init(reply, &array) == FALSE)
1210                 goto done;
1211
1212         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
1213                 goto done;
1214
1215         dbus_message_iter_recurse(&array, &dict);
1216
1217         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1218                 DBusMessageIter entry, value;
1219                 const char *key;
1220
1221                 dbus_message_iter_recurse(&dict, &entry);
1222                 dbus_message_iter_get_basic(&entry, &key);
1223
1224                 dbus_message_iter_next(&entry);
1225                 dbus_message_iter_recurse(&entry, &value);
1226
1227                 if (g_str_equal(key, "Modems") == TRUE) {
1228                         update_modems(&value);
1229                         break;
1230                 }
1231
1232                 dbus_message_iter_next(&dict);
1233         }
1234
1235 done:
1236         dbus_message_unref(reply);
1237
1238         dbus_pending_call_unref(call);
1239 }
1240
1241 static void ofono_connect(DBusConnection *connection, void *user_data)
1242 {
1243         DBG("connection %p", connection);
1244
1245         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
1246                                                 g_free, remove_modem);
1247
1248         call_ofono("/", OFONO_MANAGER_INTERFACE, GET_PROPERTIES,
1249                         manager_properties_reply, NULL, NULL,
1250                         DBUS_TYPE_INVALID);
1251 }
1252
1253 static void ofono_disconnect(DBusConnection *connection, void *user_data)
1254 {
1255         DBG("connection %p", connection);
1256
1257         if (modem_hash == NULL)
1258                 return;
1259
1260         g_hash_table_destroy(modem_hash);
1261
1262         modem_hash = NULL;
1263 }
1264
1265 static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
1266                                 void *user_data)
1267 {
1268         const char *path = dbus_message_get_path(message);
1269         struct modem_data *modem;
1270         DBusMessageIter iter, value;
1271         const char *key;
1272
1273         DBG("path %s", path);
1274
1275         modem = g_hash_table_lookup(modem_hash, path);
1276         if (modem == NULL)
1277                 return TRUE;
1278
1279         if (dbus_message_iter_init(message, &iter) == FALSE)
1280                 return TRUE;
1281
1282         dbus_message_iter_get_basic(&iter, &key);
1283
1284         dbus_message_iter_next(&iter);
1285         dbus_message_iter_recurse(&iter, &value);
1286
1287         if (g_str_equal(key, "Powered") == TRUE) {
1288                 dbus_bool_t powered;
1289
1290                 dbus_message_iter_get_basic(&value, &powered);
1291                 if (powered == TRUE)
1292                         return TRUE;
1293
1294                 modem->has_sim = FALSE;
1295                 modem->has_gprs = FALSE;
1296
1297                 modem_remove_device(modem);
1298         } else if (g_str_equal(key, "Online") == TRUE) {
1299                 dbus_bool_t online;
1300
1301                 dbus_message_iter_get_basic(&value, &online);
1302
1303                 update_modem_online(modem, online);
1304         } else if (g_str_equal(key, "Interfaces") == TRUE) {
1305                 gboolean has_sim = modem_has_sim(&value);
1306                 gboolean has_gprs = modem_has_gprs(&value);
1307
1308                 modem->has_sim = has_sim;
1309                 modem->has_gprs = has_gprs;
1310
1311                 if (modem->device == NULL) {
1312                         if (has_sim)
1313                                 get_imsi(modem->path);
1314                 } else if (!has_sim) {
1315                         modem_remove_device(modem);
1316                 }
1317         }
1318
1319         return TRUE;
1320 }
1321
1322 static gboolean sim_changed(DBusConnection *connection, DBusMessage *message,
1323                                 void *user_data)
1324 {
1325         const char *path = dbus_message_get_path(message);
1326         struct modem_data *modem;
1327         DBusMessageIter iter, value;
1328         const char *key;
1329
1330         DBG("path %s", path);
1331
1332         modem = g_hash_table_lookup(modem_hash, path);
1333         if (modem == NULL)
1334                 return TRUE;
1335
1336         if (dbus_message_iter_init(message, &iter) == FALSE)
1337                 return TRUE;
1338
1339         dbus_message_iter_get_basic(&iter, &key);
1340
1341         dbus_message_iter_next(&iter);
1342         dbus_message_iter_recurse(&iter, &value);
1343
1344         if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
1345                 char *imsi;
1346
1347                 dbus_message_iter_get_basic(&value, &imsi);
1348
1349                 add_device(path, imsi);
1350         } else if (g_str_equal(key, "Present") == TRUE) {
1351                 dbus_bool_t present;
1352
1353                 dbus_message_iter_get_basic(&value, &present);
1354
1355                 if (present)
1356                         return TRUE;
1357
1358                 if (modem->device != NULL)
1359                         modem_remove_device(modem);
1360
1361                 modem->has_gprs = FALSE;
1362         }
1363
1364         return TRUE;
1365 }
1366
1367 static gboolean gprs_changed(DBusConnection *connection, DBusMessage *message,
1368                                 void *user_data)
1369 {
1370         const char *path = dbus_message_get_path(message);
1371         struct modem_data *modem;
1372         DBusMessageIter iter, value;
1373         const char *key;
1374
1375         DBG("path %s", path);
1376
1377         modem = g_hash_table_lookup(modem_hash, path);
1378         if (modem == NULL)
1379                 return TRUE;
1380
1381         if (dbus_message_iter_init(message, &iter) == FALSE)
1382                 return TRUE;
1383
1384         dbus_message_iter_get_basic(&iter, &key);
1385
1386         dbus_message_iter_next(&iter);
1387         dbus_message_iter_recurse(&iter, &value);
1388
1389         if (g_str_equal(key, "Attached") == TRUE) {
1390                 dbus_bool_t attached;
1391
1392                 dbus_message_iter_get_basic(&value, &attached);
1393
1394                 DBG("Attached %d", attached);
1395
1396                 if (attached == TRUE)
1397                         check_networks(modem);
1398                 else if (modem->device != NULL)
1399                         connman_device_remove_all_networks(modem->device);
1400
1401         } else if (g_str_equal(key, "PrimaryContexts") == TRUE) {
1402                 check_networks(modem);
1403         }
1404
1405         return TRUE;
1406 }
1407
1408 static gboolean manager_changed(DBusConnection *connection,
1409                                 DBusMessage *message, void *user_data)
1410 {
1411         const char *path = dbus_message_get_path(message);
1412         DBusMessageIter iter, value;
1413         const char *key;
1414
1415         DBG("path %s", path);
1416
1417         if (dbus_message_iter_init(message, &iter) == FALSE)
1418                 return TRUE;
1419
1420         dbus_message_iter_get_basic(&iter, &key);
1421
1422         dbus_message_iter_next(&iter);
1423         dbus_message_iter_recurse(&iter, &value);
1424
1425         if (g_str_equal(key, "Modems") == TRUE)
1426                 update_modems(&value);
1427
1428         return TRUE;
1429 }
1430
1431 static void get_dns(DBusMessageIter *array, struct connman_element *parent)
1432 {
1433         DBusMessageIter entry;
1434         gchar *nameserver = NULL, *nameserver_old = NULL;
1435
1436         DBG("");
1437
1438         dbus_message_iter_recurse(array, &entry);
1439
1440         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
1441                 const char *dns;
1442
1443                 dbus_message_iter_get_basic(&entry, &dns);
1444
1445                 DBG("dns %s", dns);
1446
1447                 if (nameserver == NULL) {
1448
1449                         nameserver = g_strdup(dns);
1450                 } else {
1451
1452                         nameserver_old = nameserver;
1453                         nameserver = g_strdup_printf("%s %s",
1454                                                 nameserver_old, dns);
1455                         g_free(nameserver_old);
1456                 }
1457
1458                 dbus_message_iter_next(&entry);
1459         }
1460
1461         parent->ipv4.nameserver = nameserver;
1462 }
1463
1464 static void update_settings(DBusMessageIter *array,
1465                                 struct connman_network *network)
1466 {
1467         struct connman_element *parent = connman_network_get_element(network);
1468         DBusMessageIter dict;
1469         const char *interface = NULL;
1470
1471         DBG("network %p", network);
1472
1473         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
1474                 return;
1475
1476         dbus_message_iter_recurse(array, &dict);
1477
1478         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1479                 DBusMessageIter entry, value;
1480                 const char *key;
1481
1482                 dbus_message_iter_recurse(&dict, &entry);
1483                 dbus_message_iter_get_basic(&entry, &key);
1484
1485                 DBG("key %s", key);
1486
1487                 dbus_message_iter_next(&entry);
1488                 dbus_message_iter_recurse(&entry, &value);
1489
1490                 if (g_str_equal(key, "Interface") == TRUE) {
1491                         int index;
1492
1493                         dbus_message_iter_get_basic(&value, &interface);
1494
1495                         DBG("interface %s", interface);
1496
1497                         index = connman_inet_ifindex(interface);
1498                         if (index >= 0) {
1499                                 connman_network_set_index(network, index);
1500                         } else {
1501                                 connman_error("Can not find interface %s",
1502                                                                 interface);
1503                                 break;
1504                         }
1505                 } else if (g_str_equal(key, "Method") == TRUE) {
1506                         const char *method;
1507
1508                         dbus_message_iter_get_basic(&value, &method);
1509                         if (g_strcmp0(method, "static") == 0) {
1510
1511                                 parent->ipv4.method =
1512                                         CONNMAN_IPCONFIG_METHOD_FIXED;
1513                         } else if (g_strcmp0(method, "dhcp") == 0) {
1514
1515                                 parent->ipv4.method =
1516                                         CONNMAN_IPCONFIG_METHOD_DHCP;
1517                                 break;
1518                         }
1519                 } else if (g_str_equal(key, "Address") == TRUE) {
1520                         const char *address;
1521
1522                         dbus_message_iter_get_basic(&value, &address);
1523
1524                         DBG("address %s", address);
1525
1526                         parent->ipv4.address = g_strdup(address);
1527                 } else if (g_str_equal(key, "Netmask") == TRUE) {
1528                         const char *netmask;
1529
1530                         dbus_message_iter_get_basic(&value, &netmask);
1531
1532                         DBG("netmask %s", netmask);
1533
1534                         parent->ipv4.netmask = g_strdup(netmask);
1535                 } else if (g_str_equal(key, "DomainNameServers") == TRUE) {
1536
1537                         get_dns(&value, parent);
1538                 } else if (g_str_equal(key, "Gateway") == TRUE) {
1539                         const char *gateway;
1540
1541                         dbus_message_iter_get_basic(&value, &gateway);
1542
1543                         DBG("gateway %s", gateway);
1544
1545                         parent->ipv4.gateway = g_strdup(gateway);
1546                 }
1547
1548                 dbus_message_iter_next(&dict);
1549         }
1550
1551         /* deactive, oFono send NULL inteface before deactive signal */
1552         if (interface == NULL)
1553                 connman_network_set_index(network, -1);
1554 }
1555
1556 static void cleanup_ipconfig(struct connman_network *network)
1557 {
1558         struct connman_element *parent = connman_network_get_element(network);
1559
1560         g_free(parent->ipv4.address);
1561         parent->ipv4.address = NULL;
1562
1563         g_free(parent->ipv4.netmask);
1564         parent->ipv4.netmask = NULL;
1565
1566         g_free(parent->ipv4.nameserver);
1567         parent->ipv4.nameserver = NULL;
1568
1569         g_free(parent->ipv4.gateway);
1570         parent->ipv4.gateway = NULL;
1571
1572         parent->ipv4.method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
1573 }
1574
1575
1576 static void set_connected(struct connman_network *network,
1577                                 connman_bool_t connected)
1578 {
1579         struct connman_element *parent = connman_network_get_element(network);
1580         enum connman_ipconfig_method method = parent->ipv4.method;
1581
1582         switch (method) {
1583         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1584         case CONNMAN_IPCONFIG_METHOD_OFF:
1585         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1586                 return;
1587
1588         case CONNMAN_IPCONFIG_METHOD_FIXED:
1589                 connman_network_set_method(network, method);
1590
1591                 if (connected == FALSE)
1592                         cleanup_ipconfig(network);
1593
1594                 connman_network_set_connected(network, connected);
1595                 break;
1596
1597         case CONNMAN_IPCONFIG_METHOD_DHCP:
1598                 connman_network_set_method(network, method);
1599
1600                 connman_network_set_connected(network, connected);
1601                 break;
1602         }
1603 }
1604
1605 static gboolean pri_context_changed(DBusConnection *connection,
1606                                         DBusMessage *message, void *user_data)
1607 {
1608         const char *path = dbus_message_get_path(message);
1609         const char *pending_path;
1610         DBusMessageIter iter, value;
1611         const char *key;
1612
1613         DBG("pending_network %p, path %s", pending_network, path);
1614
1615         if (pending_network == NULL)
1616                 return TRUE;
1617
1618         pending_path = connman_network_get_string(pending_network, "Path");
1619         if (g_strcmp0(pending_path, path) != 0)
1620                 return TRUE;
1621
1622         if (dbus_message_iter_init(message, &iter) == FALSE)
1623                 return TRUE;
1624
1625         dbus_message_iter_get_basic(&iter, &key);
1626
1627         dbus_message_iter_next(&iter);
1628         dbus_message_iter_recurse(&iter, &value);
1629
1630         if (g_str_equal(key, "Settings") == TRUE)
1631                 update_settings(&value, pending_network);
1632         else if (g_str_equal(key, "Active") == TRUE) {
1633                 dbus_bool_t active;
1634
1635                 dbus_message_iter_get_basic(&value, &active);
1636
1637                 set_connected(pending_network, active);
1638
1639                 pending_network = NULL;
1640         }
1641
1642         return TRUE;
1643 }
1644
1645 static guint watch;
1646 static guint sim_watch;
1647 static guint gprs_watch;
1648 static guint modem_watch;
1649 static guint manager_watch;
1650 static guint context_watch;
1651
1652 static int ofono_init(void)
1653 {
1654         int err;
1655
1656         connection = connman_dbus_get_connection();
1657         if (connection == NULL)
1658                 return -EIO;
1659
1660         watch = g_dbus_add_service_watch(connection, OFONO_SERVICE,
1661                         ofono_connect, ofono_disconnect, NULL, NULL);
1662
1663         gprs_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1664                                                 OFONO_GPRS_INTERFACE,
1665                                                 PROPERTY_CHANGED,
1666                                                 gprs_changed,
1667                                                 NULL, NULL);
1668
1669         modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1670                                                 OFONO_MODEM_INTERFACE,
1671                                                 PROPERTY_CHANGED,
1672                                                 modem_changed,
1673                                                 NULL, NULL);
1674
1675         sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1676                                                 OFONO_SIM_INTERFACE,
1677                                                 PROPERTY_CHANGED,
1678                                                 sim_changed,
1679                                                 NULL, NULL);
1680
1681         manager_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1682                                                 OFONO_MANAGER_INTERFACE,
1683                                                 PROPERTY_CHANGED,
1684                                                 manager_changed,
1685                                                 NULL, NULL);
1686
1687         context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1688                                                 OFONO_PRI_CONTEXT_INTERFACE,
1689                                                 PROPERTY_CHANGED,
1690                                                 pri_context_changed,
1691                                                 NULL, NULL);
1692
1693         if (watch == 0 || gprs_watch == 0 || modem_watch == 0 ||
1694                         sim_watch == 0 ||
1695                         manager_watch == 0 || context_watch == 0) {
1696                 err = -EIO;
1697                 goto remove;
1698         }
1699
1700         err = connman_network_driver_register(&network_driver);
1701         if (err < 0)
1702                 goto remove;
1703
1704         err = connman_device_driver_register(&modem_driver);
1705         if (err < 0) {
1706                 connman_network_driver_unregister(&network_driver);
1707                 goto remove;
1708         }
1709
1710         return 0;
1711
1712 remove:
1713         g_dbus_remove_watch(connection, watch);
1714         g_dbus_remove_watch(connection, sim_watch);
1715         g_dbus_remove_watch(connection, gprs_watch);
1716         g_dbus_remove_watch(connection, modem_watch);
1717         g_dbus_remove_watch(connection, manager_watch);
1718         g_dbus_remove_watch(connection, context_watch);
1719
1720         dbus_connection_unref(connection);
1721
1722         return err;
1723 }
1724
1725 static void ofono_exit(void)
1726 {
1727         g_dbus_remove_watch(connection, watch);
1728         g_dbus_remove_watch(connection, sim_watch);
1729         g_dbus_remove_watch(connection, gprs_watch);
1730         g_dbus_remove_watch(connection, modem_watch);
1731         g_dbus_remove_watch(connection, manager_watch);
1732         g_dbus_remove_watch(connection, context_watch);
1733
1734         ofono_disconnect(connection, NULL);
1735
1736         connman_device_driver_unregister(&modem_driver);
1737         connman_network_driver_unregister(&network_driver);
1738
1739         dbus_connection_unref(connection);
1740 }
1741
1742 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
1743                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)