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