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