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