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