ofono: Get SIM properties
[platform/upstream/connman.git] / plugins / ofono.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *  Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2 as
10  *  published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <errno.h>
28 #include <stdlib.h>
29
30 #include <gdbus.h>
31 #include <string.h>
32 #include <stdint.h>
33
34 #define CONNMAN_API_SUBJECT_TO_CHANGE
35 #include <connman/plugin.h>
36 #include <connman/device.h>
37 #include <connman/network.h>
38 #include <connman/dbus.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_SIM_INTERFACE             OFONO_SERVICE ".SimManager"
46 #define OFONO_NETREG_INTERFACE          OFONO_SERVICE ".NetworkRegistration"
47 #define OFONO_CM_INTERFACE              OFONO_SERVICE ".ConnectionManager"
48 #define OFONO_CONTEXT_INTERFACE         OFONO_SERVICE ".ConnectionContext"
49
50 #define MODEM_ADDED                     "ModemAdded"
51 #define MODEM_REMOVED                   "ModemRemoved"
52 #define PROPERTY_CHANGED                "PropertyChanged"
53 #define CONTEXT_ADDED                   "ContextAdded"
54 #define CONTEXT_REMOVED                 "ContextRemoved"
55
56 #define GET_PROPERTIES                  "GetProperties"
57 #define SET_PROPERTY                    "SetProperty"
58 #define GET_MODEMS                      "GetModems"
59
60 #define TIMEOUT 40000
61
62 enum ofono_api {
63         OFONO_API_SIM =         0x1,
64         OFONO_API_NETREG =      0x2,
65         OFONO_API_CM =          0x4,
66 };
67
68 static DBusConnection *connection;
69
70 static GHashTable *modem_hash;
71
72 struct modem_data {
73         char *path;
74
75         /* Modem Interface */
76         char *serial;
77         connman_bool_t powered;
78         connman_bool_t online;
79         uint8_t interfaces;
80
81         connman_bool_t set_powered;
82
83         /* SimManager Interface */
84         char *imsi;
85
86         /* pending calls */
87         DBusPendingCall *call_set_property;
88         DBusPendingCall *call_get_properties;
89 };
90
91 typedef void (*set_property_cb)(struct modem_data *data,
92                                 connman_bool_t success);
93 typedef void (*get_properties_cb)(struct modem_data *data,
94                                 DBusMessageIter *dict);
95
96 struct property_info {
97         struct modem_data *modem;
98         const char *path;
99         const char *interface;
100         const char *property;
101         set_property_cb set_property_cb;
102         get_properties_cb get_properties_cb;
103 };
104
105 static void set_property_reply(DBusPendingCall *call, void *user_data)
106 {
107         struct property_info *info = user_data;
108         DBusMessage *reply;
109         DBusError error;
110         connman_bool_t success = TRUE;
111
112         DBG("%s path %s %s.%s", info->modem->path,
113                 info->path, info->interface, info->property);
114
115         info->modem->call_set_property = NULL;
116
117         dbus_error_init(&error);
118
119         reply = dbus_pending_call_steal_reply(call);
120
121         if (dbus_set_error_from_message(&error, reply)) {
122                 connman_error("Failed to change property: %s %s.%s: %s %s",
123                                 info->path, info->interface, info->property,
124                                 error.name, error.message);
125                 dbus_error_free(&error);
126                 success = FALSE;
127         }
128
129         if (info->set_property_cb != NULL)
130                 (*info->set_property_cb)(info->modem, success);
131
132         dbus_message_unref(reply);
133
134         dbus_pending_call_unref(call);
135 }
136
137 static int set_property(struct modem_data *modem,
138                         const char *path, const char *interface,
139                         const char *property, int type, void *value,
140                         set_property_cb notify)
141 {
142         DBusMessage *message;
143         DBusMessageIter iter;
144         struct property_info *info;
145
146         DBG("%s path %s %s.%s", modem->path, path, interface, property);
147
148         if (modem->call_set_property != NULL) {
149                 connman_error("Pending SetProperty");
150                 return -EBUSY;
151         }
152
153         message = dbus_message_new_method_call(OFONO_SERVICE, path,
154                                         interface, SET_PROPERTY);
155         if (message == NULL)
156                 return -ENOMEM;
157
158         dbus_message_iter_init_append(message, &iter);
159         connman_dbus_property_append_basic(&iter, property, type, value);
160
161         if (dbus_connection_send_with_reply(connection, message,
162                         &modem->call_set_property, TIMEOUT) == FALSE) {
163                 connman_error("Failed to change property: %s %s.%s",
164                                 path, interface, property);
165                 dbus_message_unref(message);
166                 return -EINVAL;
167         }
168
169         if (modem->call_set_property == NULL) {
170                 connman_error("D-Bus connection not available");
171                 dbus_message_unref(message);
172                 return -EINVAL;
173         }
174
175         info = g_try_new0(struct property_info, 1);
176         if (info == NULL) {
177                 dbus_message_unref(message);
178                 return -ENOMEM;
179         }
180
181         info->modem = modem;
182         info->path = path;
183         info->interface = interface;
184         info->property = property;
185         info->set_property_cb = notify;
186
187         dbus_pending_call_set_notify(modem->call_set_property,
188                                         set_property_reply, info, g_free);
189
190         dbus_message_unref(message);
191
192         return -EINPROGRESS;
193 }
194
195 static void get_properties_reply(DBusPendingCall *call, void *user_data)
196 {
197         struct property_info *info = user_data;
198         DBusMessageIter array, dict;
199         DBusMessage *reply;
200         DBusError error;
201
202         DBG("%s path %s %s", info->modem->path, info->path, info->interface);
203
204         info->modem->call_get_properties = NULL;
205
206         dbus_error_init(&error);
207
208         reply = dbus_pending_call_steal_reply(call);
209
210         if (dbus_set_error_from_message(&error, reply)) {
211                 connman_error("Failed to get properties: %s %s: %s %s",
212                                 info->path, info->interface,
213                                 error.name, error.message);
214                 dbus_error_free(&error);
215
216                 goto done;
217         }
218
219         if (dbus_message_iter_init(reply, &array) == FALSE)
220                 goto done;
221
222         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
223                 goto done;
224
225         dbus_message_iter_recurse(&array, &dict);
226
227         if (info->get_properties_cb != NULL)
228                 (*info->get_properties_cb)(info->modem, &dict);
229
230 done:
231
232         dbus_message_unref(reply);
233
234         dbus_pending_call_unref(call);
235 }
236
237 static int get_properties(const char *path, const char *interface,
238                                 get_properties_cb notify,
239                                 struct modem_data *modem)
240 {
241         DBusMessage *message;
242         struct property_info *info;
243
244         DBG("%s path %s %s", modem->path, path, interface);
245
246         if (modem->call_get_properties != NULL) {
247                 connman_error("Pending GetProperties");
248                 return -EBUSY;
249         }
250
251         message = dbus_message_new_method_call(OFONO_SERVICE, path,
252                                         interface, GET_PROPERTIES);
253         if (message == NULL)
254                 return -ENOMEM;
255
256         if (dbus_connection_send_with_reply(connection, message,
257                         &modem->call_get_properties, TIMEOUT) == FALSE) {
258                 connman_error("Failed to call %s.GetProperties()", interface);
259                 dbus_message_unref(message);
260                 return -EINVAL;
261         }
262
263         if (modem->call_get_properties == NULL) {
264                 connman_error("D-Bus connection not available");
265                 dbus_message_unref(message);
266                 return -EINVAL;
267         }
268
269         info = g_try_new0(struct property_info, 1);
270         if (info == NULL) {
271                 dbus_message_unref(message);
272                 return -ENOMEM;
273         }
274
275         info->modem = modem;
276         info->path = path;
277         info->interface = interface;
278         info->get_properties_cb = notify;
279
280         dbus_pending_call_set_notify(modem->call_get_properties,
281                                         get_properties_reply, info, g_free);
282
283         dbus_message_unref(message);
284
285         return -EINPROGRESS;
286 }
287
288 static int modem_set_powered(struct modem_data *modem)
289 {
290         DBG("%s", modem->path);
291
292         modem->set_powered = TRUE;
293
294         return set_property(modem, modem->path,
295                                 OFONO_MODEM_INTERFACE,
296                                 "Powered", DBUS_TYPE_BOOLEAN,
297                                 &modem->set_powered,
298                                 NULL);
299 }
300
301 static connman_bool_t has_interface(uint8_t interfaces,
302                                         enum ofono_api api)
303 {
304         if ((interfaces & api) == api)
305                 return TRUE;
306
307         return FALSE;
308 }
309
310 static uint8_t extract_interfaces(DBusMessageIter *array)
311 {
312         DBusMessageIter entry;
313         uint8_t interfaces = 0;
314
315         dbus_message_iter_recurse(array, &entry);
316
317         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
318                 const char *name;
319
320                 dbus_message_iter_get_basic(&entry, &name);
321
322                 if (g_str_equal(name, OFONO_SIM_INTERFACE) == TRUE)
323                         interfaces |= OFONO_API_SIM;
324                 else if (g_str_equal(name, OFONO_NETREG_INTERFACE) == TRUE)
325                         interfaces |= OFONO_API_NETREG;
326                 else if (g_str_equal(name, OFONO_CM_INTERFACE) == TRUE)
327                         interfaces |= OFONO_API_CM;
328
329                 dbus_message_iter_next(&entry);
330         }
331
332         return interfaces;
333 }
334
335 static gboolean context_changed(DBusConnection *connection,
336                                 DBusMessage *message,
337                                 void *user_data)
338 {
339         return TRUE;
340 }
341
342 static gboolean cm_context_added(DBusConnection *connection,
343                                         DBusMessage *message,
344                                         void *user_data)
345 {
346         return TRUE;
347 }
348
349 static gboolean cm_context_removed(DBusConnection *connection,
350                                         DBusMessage *message,
351                                         void *user_data)
352 {
353         return TRUE;
354 }
355
356 static gboolean netreg_changed(DBusConnection *connection, DBusMessage *message,
357                                 void *user_data)
358 {
359         return TRUE;
360 }
361
362 static gboolean cm_changed(DBusConnection *connection, DBusMessage *message,
363                                 void *user_data)
364 {
365         return TRUE;
366 }
367
368 static void update_sim_imsi(struct modem_data *modem,
369                                 const char *imsi)
370 {
371         DBG("%s imsi %s", modem->path, imsi);
372
373         if (g_strcmp0(modem->imsi, imsi) == 0)
374                 return;
375
376         g_free(modem->imsi);
377         modem->imsi = g_strdup(imsi);
378 }
379
380 static gboolean sim_changed(DBusConnection *connection, DBusMessage *message,
381                                 void *user_data)
382 {
383         const char *path = dbus_message_get_path(message);
384         struct modem_data *modem;
385         DBusMessageIter iter, value;
386         const char *key;
387
388         modem = g_hash_table_lookup(modem_hash, path);
389         if (modem == NULL)
390                 return TRUE;
391
392         if (dbus_message_iter_init(message, &iter) == FALSE)
393                 return TRUE;
394
395         dbus_message_iter_get_basic(&iter, &key);
396
397         dbus_message_iter_next(&iter);
398         dbus_message_iter_recurse(&iter, &value);
399
400         if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
401                 char *imsi;
402
403                 dbus_message_iter_get_basic(&value, &imsi);
404
405                 update_sim_imsi(modem, imsi);
406         }
407
408         return TRUE;
409 }
410
411 static void sim_properties_reply(struct modem_data *modem,
412                                         DBusMessageIter *dict)
413 {
414         DBG("%s", modem->path);
415
416         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
417                 DBusMessageIter entry, value;
418                 const char *key;
419
420                 dbus_message_iter_recurse(dict, &entry);
421                 dbus_message_iter_get_basic(&entry, &key);
422
423                 dbus_message_iter_next(&entry);
424                 dbus_message_iter_recurse(&entry, &value);
425
426                 if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
427                         char *imsi;
428
429                         dbus_message_iter_get_basic(&value, &imsi);
430
431                         update_sim_imsi(modem, imsi);
432
433                         return;
434                 }
435
436                 dbus_message_iter_next(dict);
437         }
438 }
439
440 static int sim_get_properties(struct modem_data *modem)
441 {
442         return get_properties(modem->path, OFONO_SIM_INTERFACE,
443                         sim_properties_reply, modem);
444 }
445
446 static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
447                                 void *user_data)
448 {
449         const char *path = dbus_message_get_path(message);
450         struct modem_data *modem;
451         DBusMessageIter iter, value;
452         const char *key;
453
454         modem = g_hash_table_lookup(modem_hash, path);
455         if (modem == NULL)
456                 return TRUE;
457
458         if (dbus_message_iter_init(message, &iter) == FALSE)
459                 return TRUE;
460
461         dbus_message_iter_get_basic(&iter, &key);
462
463         dbus_message_iter_next(&iter);
464         dbus_message_iter_recurse(&iter, &value);
465
466         if (g_str_equal(key, "Powered") == TRUE) {
467                 dbus_message_iter_get_basic(&value, &modem->powered);
468
469                 DBG("%s Powered %d", modem->path, modem->powered);
470
471                 if (modem->powered == FALSE)
472                         modem_set_powered(modem);
473         } else if (g_str_equal(key, "Online") == TRUE) {
474                 dbus_message_iter_get_basic(&value, &modem->online);
475
476                 DBG("%s Online %d", modem->path, modem->online);
477         } else if (g_str_equal(key, "Interfaces") == TRUE) {
478                 modem->interfaces = extract_interfaces(&value);
479
480                 DBG("%s Interfaces 0x%02x", modem->path,
481                         modem->interfaces);
482
483                 if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE) {
484                         if (modem->imsi == NULL &&
485                                         modem->set_powered == FALSE) {
486                                 /*
487                                  * Only use do GetProperties() when
488                                  * device has not been powered up.
489                                  */
490                                 sim_get_properties(modem);
491                                 return TRUE;
492                         }
493                 }
494         } else if (g_str_equal(key, "Serial") == TRUE) {
495                 char *serial;
496
497                 dbus_message_iter_get_basic(&value, &serial);
498
499                 g_free(modem->serial);
500                 modem->serial = g_strdup(serial);
501
502                 DBG("%s Serial %s", modem->path, modem->serial);
503         }
504
505         return TRUE;
506 }
507
508 static void add_modem(const char *path, DBusMessageIter *prop)
509 {
510         struct modem_data *modem;
511
512         DBG("%s", path);
513
514         modem = g_hash_table_lookup(modem_hash, path);
515         if (modem != NULL) {
516                 /*
517                  * When oFono powers up we ask for the modems and oFono is
518                  * reporting with modem_added signal the modems. Only
519                  * handle them once.
520                  */
521                 return;
522         }
523
524         modem = g_try_new0(struct modem_data, 1);
525         if (modem == NULL)
526                 return;
527
528         modem->path = g_strdup(path);
529
530         g_hash_table_insert(modem_hash, g_strdup(path), modem);
531
532         while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
533                 DBusMessageIter entry, value;
534                 const char *key;
535
536                 dbus_message_iter_recurse(prop, &entry);
537                 dbus_message_iter_get_basic(&entry, &key);
538
539                 dbus_message_iter_next(&entry);
540                 dbus_message_iter_recurse(&entry, &value);
541
542                 if (g_str_equal(key, "Powered") == TRUE) {
543                         dbus_message_iter_get_basic(&value, &modem->powered);
544
545                         DBG("%s Powered %d", modem->path, modem->powered);
546                 } else if (g_str_equal(key, "Online") == TRUE) {
547                         dbus_message_iter_get_basic(&value, &modem->online);
548
549                         DBG("%s Online %d", modem->path, modem->online);
550                 } else if (g_str_equal(key, "Interfaces") == TRUE) {
551                         modem->interfaces = extract_interfaces(&value);
552
553                         DBG("%s Interfaces 0x%02x", modem->path,
554                                 modem->interfaces);
555                 } else if (g_str_equal(key, "Serial") == TRUE) {
556                         char *serial;
557
558                         dbus_message_iter_get_basic(&value, &serial);
559                         modem->serial = g_strdup(serial);
560
561                         DBG("%s Serial %s", modem->path, modem->serial);
562                 }
563
564                 dbus_message_iter_next(prop);
565         }
566
567         if (modem->powered == FALSE)
568                 modem_set_powered(modem);
569         else if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE)
570                 sim_get_properties(modem);
571 }
572
573 static void remove_modem(gpointer data)
574 {
575         struct modem_data *modem = data;
576
577         DBG("%s", modem->path);
578
579         if (modem->call_set_property != NULL)
580                 dbus_pending_call_cancel(modem->call_set_property);
581
582         if (modem->call_get_properties != NULL)
583                 dbus_pending_call_cancel(modem->call_get_properties);
584
585         g_free(modem->serial);
586         g_free(modem->imsi);
587         g_free(modem->path);
588
589         g_free(modem);
590 }
591
592 static gboolean modem_added(DBusConnection *connection,
593                                 DBusMessage *message, void *user_data)
594 {
595         DBusMessageIter iter, properties;
596         const char *path;
597
598         DBG("");
599
600         if (dbus_message_iter_init(message, &iter) == FALSE)
601                 return TRUE;
602
603         dbus_message_iter_get_basic(&iter, &path);
604
605         dbus_message_iter_next(&iter);
606         dbus_message_iter_recurse(&iter, &properties);
607
608         add_modem(path, &properties);
609
610         return TRUE;
611 }
612
613 static gboolean modem_removed(DBusConnection *connection,
614                                 DBusMessage *message, void *user_data)
615 {
616         DBusMessageIter iter;
617         const char *path;
618
619         DBG("");
620
621         if (dbus_message_iter_init(message, &iter) == FALSE)
622                 return TRUE;
623
624         dbus_message_iter_get_basic(&iter, &path);
625
626         g_hash_table_remove(modem_hash, path);
627
628         return TRUE;
629 }
630
631 static void manager_get_modems_reply(DBusPendingCall *call, void *user_data)
632 {
633         DBusMessage *reply;
634         DBusError error;
635         DBusMessageIter array, dict;
636
637         DBG("");
638
639         reply = dbus_pending_call_steal_reply(call);
640
641         dbus_error_init(&error);
642
643         if (dbus_set_error_from_message(&error, reply) == TRUE) {
644                 connman_error("%s", error.message);
645                 dbus_error_free(&error);
646                 goto done;
647         }
648
649         if (dbus_message_iter_init(reply, &array) == FALSE)
650                 goto done;
651
652         dbus_message_iter_recurse(&array, &dict);
653
654         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
655                 DBusMessageIter value, properties;
656                 const char *path;
657
658                 dbus_message_iter_recurse(&dict, &value);
659                 dbus_message_iter_get_basic(&value, &path);
660
661                 dbus_message_iter_next(&value);
662                 dbus_message_iter_recurse(&value, &properties);
663
664                 add_modem(path, &properties);
665
666                 dbus_message_iter_next(&dict);
667         }
668
669 done:
670         dbus_message_unref(reply);
671
672         dbus_pending_call_unref(call);
673 }
674
675 static int manager_get_modems(void)
676 {
677         DBusMessage *message;
678         DBusPendingCall *call;
679
680         DBG("");
681
682         message = dbus_message_new_method_call(OFONO_SERVICE, "/",
683                                         OFONO_MANAGER_INTERFACE, GET_MODEMS);
684         if (message == NULL)
685                 return -ENOMEM;
686
687         if (dbus_connection_send_with_reply(connection, message,
688                                                &call, TIMEOUT) == FALSE) {
689                 connman_error("Failed to call GetModems()");
690                 dbus_message_unref(message);
691                 return -EINVAL;
692         }
693
694         if (call == NULL) {
695                 connman_error("D-Bus connection not available");
696                 dbus_message_unref(message);
697                 return -EINVAL;
698         }
699
700         dbus_pending_call_set_notify(call, manager_get_modems_reply,
701                                         NULL, NULL);
702
703         dbus_message_unref(message);
704
705         return -EINPROGRESS;
706 }
707
708 static void ofono_connect(DBusConnection *conn, void *user_data)
709 {
710         DBG("");
711
712         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
713                                                 g_free, remove_modem);
714         if (modem_hash == NULL)
715                 return;
716
717         manager_get_modems();
718 }
719
720 static void ofono_disconnect(DBusConnection *conn, void *user_data)
721 {
722         DBG("");
723
724         if (modem_hash == NULL)
725                 return;
726
727         g_hash_table_destroy(modem_hash);
728         modem_hash = NULL;
729 }
730
731 static int network_probe(struct connman_network *network)
732 {
733         DBG("network %p", network);
734
735         return 0;
736 }
737
738 static void network_remove(struct connman_network *network)
739 {
740         DBG("network %p", network);
741 }
742
743 static int network_connect(struct connman_network *network)
744 {
745         DBG("network %p", network);
746
747         return 0;
748 }
749
750 static int network_disconnect(struct connman_network *network)
751 {
752         DBG("network %p", network);
753
754         return 0;
755 }
756
757 static struct connman_network_driver network_driver = {
758         .name           = "network",
759         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
760         .probe          = network_probe,
761         .remove         = network_remove,
762         .connect        = network_connect,
763         .disconnect     = network_disconnect,
764 };
765
766 static int modem_probe(struct connman_device *device)
767 {
768         DBG("device %p", device);
769
770         return 0;
771 }
772
773 static void modem_remove(struct connman_device *device)
774 {
775         DBG("device %p", device);
776 }
777
778 static int modem_enable(struct connman_device *device)
779 {
780         DBG("device %p", device);
781
782         return 0;
783 }
784
785 static int modem_disable(struct connman_device *device)
786 {
787         DBG("device %p", device);
788
789         return 0;
790 }
791
792 static struct connman_device_driver modem_driver = {
793         .name           = "modem",
794         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
795         .probe          = modem_probe,
796         .remove         = modem_remove,
797         .enable         = modem_enable,
798         .disable        = modem_disable,
799 };
800
801 static guint watch;
802 static guint modem_added_watch;
803 static guint modem_removed_watch;
804 static guint modem_watch;
805 static guint cm_watch;
806 static guint sim_watch;
807 static guint context_added_watch;
808 static guint context_removed_watch;
809 static guint netreg_watch;
810 static guint context_watch;
811
812 static int ofono_init(void)
813 {
814         int err;
815
816         DBG("");
817
818         connection = connman_dbus_get_connection();
819         if (connection == NULL)
820                 return -EIO;
821
822         watch = g_dbus_add_service_watch(connection,
823                                         OFONO_SERVICE, ofono_connect,
824                                         ofono_disconnect, NULL, NULL);
825
826         modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
827                                                 OFONO_MANAGER_INTERFACE,
828                                                 MODEM_ADDED,
829                                                 modem_added,
830                                                 NULL, NULL);
831
832         modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
833                                                 OFONO_MANAGER_INTERFACE,
834                                                 MODEM_REMOVED,
835                                                 modem_removed,
836                                                 NULL, NULL);
837
838         modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
839                                                 OFONO_MODEM_INTERFACE,
840                                                 PROPERTY_CHANGED,
841                                                 modem_changed,
842                                                 NULL, NULL);
843
844         cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
845                                                 OFONO_CM_INTERFACE,
846                                                 PROPERTY_CHANGED,
847                                                 cm_changed,
848                                                 NULL, NULL);
849
850         sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
851                                                 OFONO_SIM_INTERFACE,
852                                                 PROPERTY_CHANGED,
853                                                 sim_changed,
854                                                 NULL, NULL);
855
856         context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
857                                                 OFONO_CM_INTERFACE,
858                                                 CONTEXT_ADDED,
859                                                 cm_context_added,
860                                                 NULL, NULL);
861
862         context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
863                                                 OFONO_CM_INTERFACE,
864                                                 CONTEXT_REMOVED,
865                                                 cm_context_removed,
866                                                 NULL, NULL);
867
868         context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
869                                                 OFONO_CONTEXT_INTERFACE,
870                                                 PROPERTY_CHANGED,
871                                                 context_changed,
872                                                 NULL, NULL);
873
874         netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
875                                                 OFONO_NETREG_INTERFACE,
876                                                 PROPERTY_CHANGED,
877                                                 netreg_changed,
878                                                 NULL, NULL);
879
880
881         if (watch == 0 || modem_added_watch == 0 || modem_removed_watch == 0 ||
882                         modem_watch == 0 || cm_watch == 0 || sim_watch == 0 ||
883                         context_added_watch == 0 ||
884                         context_removed_watch == 0 ||
885                         context_watch == 0 || netreg_watch == 0) {
886                 err = -EIO;
887                 goto remove;
888         }
889
890         err = connman_network_driver_register(&network_driver);
891         if (err < 0)
892                 goto remove;
893
894         err = connman_device_driver_register(&modem_driver);
895         if (err < 0) {
896                 connman_network_driver_unregister(&network_driver);
897                 goto remove;
898         }
899
900         return 0;
901
902 remove:
903         g_dbus_remove_watch(connection, netreg_watch);
904         g_dbus_remove_watch(connection, context_watch);
905         g_dbus_remove_watch(connection, context_removed_watch);
906         g_dbus_remove_watch(connection, context_added_watch);
907         g_dbus_remove_watch(connection, sim_watch);
908         g_dbus_remove_watch(connection, cm_watch);
909         g_dbus_remove_watch(connection, modem_watch);
910         g_dbus_remove_watch(connection, modem_removed_watch);
911         g_dbus_remove_watch(connection, modem_added_watch);
912         g_dbus_remove_watch(connection, watch);
913         dbus_connection_unref(connection);
914
915         return err;
916 }
917
918 static void ofono_exit(void)
919 {
920         DBG("");
921
922         if (modem_hash != NULL) {
923                 g_hash_table_destroy(modem_hash);
924                 modem_hash = NULL;
925         }
926
927         connman_device_driver_unregister(&modem_driver);
928         connman_network_driver_unregister(&network_driver);
929
930         g_dbus_remove_watch(connection, netreg_watch);
931         g_dbus_remove_watch(connection, context_watch);
932         g_dbus_remove_watch(connection, context_removed_watch);
933         g_dbus_remove_watch(connection, context_added_watch);
934         g_dbus_remove_watch(connection, sim_watch);
935         g_dbus_remove_watch(connection, cm_watch);
936         g_dbus_remove_watch(connection, modem_watch);
937         g_dbus_remove_watch(connection, modem_added_watch);
938         g_dbus_remove_watch(connection, modem_removed_watch);
939         g_dbus_remove_watch(connection, watch);
940
941         dbus_connection_unref(connection);
942 }
943
944 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
945                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)