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