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