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