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