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