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