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