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