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