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