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