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