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