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