ofono: Keep track of all modems
[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
33 #define CONNMAN_API_SUBJECT_TO_CHANGE
34 #include <connman/plugin.h>
35 #include <connman/device.h>
36 #include <connman/network.h>
37 #include <connman/dbus.h>
38 #include <connman/log.h>
39
40 #define OFONO_SERVICE                   "org.ofono"
41
42 #define OFONO_MANAGER_INTERFACE         OFONO_SERVICE ".Manager"
43 #define OFONO_MODEM_INTERFACE           OFONO_SERVICE ".Modem"
44 #define OFONO_SIM_INTERFACE             OFONO_SERVICE ".SimManager"
45 #define OFONO_NETREG_INTERFACE          OFONO_SERVICE ".NetworkRegistration"
46 #define OFONO_CM_INTERFACE              OFONO_SERVICE ".ConnectionManager"
47 #define OFONO_CONTEXT_INTERFACE         OFONO_SERVICE ".ConnectionContext"
48
49 #define MODEM_ADDED                     "ModemAdded"
50 #define MODEM_REMOVED                   "ModemRemoved"
51 #define PROPERTY_CHANGED                "PropertyChanged"
52 #define CONTEXT_ADDED                   "ContextAdded"
53 #define CONTEXT_REMOVED                 "ContextRemoved"
54
55 #define GET_MODEMS                      "GetModems"
56
57 #define TIMEOUT 40000
58
59 static DBusConnection *connection;
60
61 static GHashTable *modem_hash;
62
63 struct modem_data {
64         char *path;
65 };
66
67 static gboolean context_changed(DBusConnection *connection,
68                                 DBusMessage *message,
69                                 void *user_data)
70 {
71         return TRUE;
72 }
73
74 static gboolean cm_context_added(DBusConnection *connection,
75                                         DBusMessage *message,
76                                         void *user_data)
77 {
78         return TRUE;
79 }
80
81 static gboolean cm_context_removed(DBusConnection *connection,
82                                         DBusMessage *message,
83                                         void *user_data)
84 {
85         return TRUE;
86 }
87
88 static gboolean netreg_changed(DBusConnection *connection, DBusMessage *message,
89                                 void *user_data)
90 {
91         return TRUE;
92 }
93
94 static gboolean cm_changed(DBusConnection *connection, DBusMessage *message,
95                                 void *user_data)
96 {
97         return TRUE;
98 }
99
100 static gboolean sim_changed(DBusConnection *connection, DBusMessage *message,
101                                 void *user_data)
102 {
103         return TRUE;
104 }
105
106 static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
107                                 void *user_data)
108 {
109         return TRUE;
110 }
111
112 static void add_modem(const char *path, DBusMessageIter *prop)
113 {
114         struct modem_data *modem;
115
116         DBG("%s", path);
117
118         modem = g_hash_table_lookup(modem_hash, path);
119         if (modem != NULL) {
120                 /*
121                  * When oFono powers up we ask for the modems and oFono is
122                  * reporting with modem_added signal the modems. Only
123                  * handle them once.
124                  */
125                 return;
126         }
127
128         modem = g_try_new0(struct modem_data, 1);
129         if (modem == NULL)
130                 return;
131
132         modem->path = g_strdup(path);
133
134         g_hash_table_insert(modem_hash, g_strdup(path), modem);
135 }
136
137 static void remove_modem(gpointer data)
138 {
139         struct modem_data *modem = data;
140
141         DBG("%s", modem->path);
142
143         g_free(modem->path);
144
145         g_free(modem);
146 }
147
148 static gboolean modem_added(DBusConnection *connection,
149                                 DBusMessage *message, void *user_data)
150 {
151         DBusMessageIter iter, properties;
152         const char *path;
153
154         DBG("");
155
156         if (dbus_message_iter_init(message, &iter) == FALSE)
157                 return TRUE;
158
159         dbus_message_iter_get_basic(&iter, &path);
160
161         dbus_message_iter_next(&iter);
162         dbus_message_iter_recurse(&iter, &properties);
163
164         add_modem(path, &properties);
165
166         return TRUE;
167 }
168
169 static gboolean modem_removed(DBusConnection *connection,
170                                 DBusMessage *message, void *user_data)
171 {
172         DBusMessageIter iter;
173         const char *path;
174
175         DBG("");
176
177         if (dbus_message_iter_init(message, &iter) == FALSE)
178                 return TRUE;
179
180         dbus_message_iter_get_basic(&iter, &path);
181
182         g_hash_table_remove(modem_hash, path);
183
184         return TRUE;
185 }
186
187 static void manager_get_modems_reply(DBusPendingCall *call, void *user_data)
188 {
189         DBusMessage *reply;
190         DBusError error;
191         DBusMessageIter array, dict;
192
193         DBG("");
194
195         reply = dbus_pending_call_steal_reply(call);
196
197         dbus_error_init(&error);
198
199         if (dbus_set_error_from_message(&error, reply) == TRUE) {
200                 connman_error("%s", error.message);
201                 dbus_error_free(&error);
202                 goto done;
203         }
204
205         if (dbus_message_iter_init(reply, &array) == FALSE)
206                 goto done;
207
208         dbus_message_iter_recurse(&array, &dict);
209
210         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
211                 DBusMessageIter value, properties;
212                 const char *path;
213
214                 dbus_message_iter_recurse(&dict, &value);
215                 dbus_message_iter_get_basic(&value, &path);
216
217                 dbus_message_iter_next(&value);
218                 dbus_message_iter_recurse(&value, &properties);
219
220                 add_modem(path, &properties);
221
222                 dbus_message_iter_next(&dict);
223         }
224
225 done:
226         dbus_message_unref(reply);
227
228         dbus_pending_call_unref(call);
229 }
230
231 static int manager_get_modems(void)
232 {
233         DBusMessage *message;
234         DBusPendingCall *call;
235
236         DBG("");
237
238         message = dbus_message_new_method_call(OFONO_SERVICE, "/",
239                                         OFONO_MANAGER_INTERFACE, GET_MODEMS);
240         if (message == NULL)
241                 return -ENOMEM;
242
243         if (dbus_connection_send_with_reply(connection, message,
244                                                &call, TIMEOUT) == FALSE) {
245                 connman_error("Failed to call GetModems()");
246                 dbus_message_unref(message);
247                 return -EINVAL;
248         }
249
250         if (call == NULL) {
251                 connman_error("D-Bus connection not available");
252                 dbus_message_unref(message);
253                 return -EINVAL;
254         }
255
256         dbus_pending_call_set_notify(call, manager_get_modems_reply,
257                                         NULL, NULL);
258
259         dbus_message_unref(message);
260
261         return -EINPROGRESS;
262 }
263
264 static void ofono_connect(DBusConnection *conn, void *user_data)
265 {
266         DBG("");
267
268         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
269                                                 g_free, remove_modem);
270         if (modem_hash == NULL)
271                 return;
272
273         manager_get_modems();
274 }
275
276 static void ofono_disconnect(DBusConnection *conn, void *user_data)
277 {
278         DBG("");
279
280         if (modem_hash == NULL)
281                 return;
282
283         g_hash_table_destroy(modem_hash);
284         modem_hash = NULL;
285 }
286
287 static int network_probe(struct connman_network *network)
288 {
289         DBG("network %p", network);
290
291         return 0;
292 }
293
294 static void network_remove(struct connman_network *network)
295 {
296         DBG("network %p", network);
297 }
298
299 static int network_connect(struct connman_network *network)
300 {
301         DBG("network %p", network);
302
303         return 0;
304 }
305
306 static int network_disconnect(struct connman_network *network)
307 {
308         DBG("network %p", network);
309
310         return 0;
311 }
312
313 static struct connman_network_driver network_driver = {
314         .name           = "network",
315         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
316         .probe          = network_probe,
317         .remove         = network_remove,
318         .connect        = network_connect,
319         .disconnect     = network_disconnect,
320 };
321
322 static int modem_probe(struct connman_device *device)
323 {
324         DBG("device %p", device);
325
326         return 0;
327 }
328
329 static void modem_remove(struct connman_device *device)
330 {
331         DBG("device %p", device);
332 }
333
334 static int modem_enable(struct connman_device *device)
335 {
336         DBG("device %p", device);
337
338         return 0;
339 }
340
341 static int modem_disable(struct connman_device *device)
342 {
343         DBG("device %p", device);
344
345         return 0;
346 }
347
348 static struct connman_device_driver modem_driver = {
349         .name           = "modem",
350         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
351         .probe          = modem_probe,
352         .remove         = modem_remove,
353         .enable         = modem_enable,
354         .disable        = modem_disable,
355 };
356
357 static guint watch;
358 static guint modem_added_watch;
359 static guint modem_removed_watch;
360 static guint modem_watch;
361 static guint cm_watch;
362 static guint sim_watch;
363 static guint context_added_watch;
364 static guint context_removed_watch;
365 static guint netreg_watch;
366 static guint context_watch;
367
368 static int ofono_init(void)
369 {
370         int err;
371
372         DBG("");
373
374         connection = connman_dbus_get_connection();
375         if (connection == NULL)
376                 return -EIO;
377
378         watch = g_dbus_add_service_watch(connection,
379                                         OFONO_SERVICE, ofono_connect,
380                                         ofono_disconnect, NULL, NULL);
381
382         modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
383                                                 OFONO_MANAGER_INTERFACE,
384                                                 MODEM_ADDED,
385                                                 modem_added,
386                                                 NULL, NULL);
387
388         modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
389                                                 OFONO_MANAGER_INTERFACE,
390                                                 MODEM_REMOVED,
391                                                 modem_removed,
392                                                 NULL, NULL);
393
394         modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
395                                                 OFONO_MODEM_INTERFACE,
396                                                 PROPERTY_CHANGED,
397                                                 modem_changed,
398                                                 NULL, NULL);
399
400         cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
401                                                 OFONO_CM_INTERFACE,
402                                                 PROPERTY_CHANGED,
403                                                 cm_changed,
404                                                 NULL, NULL);
405
406         sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
407                                                 OFONO_SIM_INTERFACE,
408                                                 PROPERTY_CHANGED,
409                                                 sim_changed,
410                                                 NULL, NULL);
411
412         context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
413                                                 OFONO_CM_INTERFACE,
414                                                 CONTEXT_ADDED,
415                                                 cm_context_added,
416                                                 NULL, NULL);
417
418         context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
419                                                 OFONO_CM_INTERFACE,
420                                                 CONTEXT_REMOVED,
421                                                 cm_context_removed,
422                                                 NULL, NULL);
423
424         context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
425                                                 OFONO_CONTEXT_INTERFACE,
426                                                 PROPERTY_CHANGED,
427                                                 context_changed,
428                                                 NULL, NULL);
429
430         netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
431                                                 OFONO_NETREG_INTERFACE,
432                                                 PROPERTY_CHANGED,
433                                                 netreg_changed,
434                                                 NULL, NULL);
435
436
437         if (watch == 0 || modem_added_watch == 0 || modem_removed_watch == 0 ||
438                         modem_watch == 0 || cm_watch == 0 || sim_watch == 0 ||
439                         context_added_watch == 0 ||
440                         context_removed_watch == 0 ||
441                         context_watch == 0 || netreg_watch == 0) {
442                 err = -EIO;
443                 goto remove;
444         }
445
446         err = connman_network_driver_register(&network_driver);
447         if (err < 0)
448                 goto remove;
449
450         err = connman_device_driver_register(&modem_driver);
451         if (err < 0) {
452                 connman_network_driver_unregister(&network_driver);
453                 goto remove;
454         }
455
456         return 0;
457
458 remove:
459         g_dbus_remove_watch(connection, netreg_watch);
460         g_dbus_remove_watch(connection, context_watch);
461         g_dbus_remove_watch(connection, context_removed_watch);
462         g_dbus_remove_watch(connection, context_added_watch);
463         g_dbus_remove_watch(connection, sim_watch);
464         g_dbus_remove_watch(connection, cm_watch);
465         g_dbus_remove_watch(connection, modem_watch);
466         g_dbus_remove_watch(connection, modem_removed_watch);
467         g_dbus_remove_watch(connection, modem_added_watch);
468         g_dbus_remove_watch(connection, watch);
469         dbus_connection_unref(connection);
470
471         return err;
472 }
473
474 static void ofono_exit(void)
475 {
476         DBG("");
477
478         if (modem_hash != NULL) {
479                 g_hash_table_destroy(modem_hash);
480                 modem_hash = NULL;
481         }
482
483         connman_device_driver_unregister(&modem_driver);
484         connman_network_driver_unregister(&network_driver);
485
486         g_dbus_remove_watch(connection, netreg_watch);
487         g_dbus_remove_watch(connection, context_watch);
488         g_dbus_remove_watch(connection, context_removed_watch);
489         g_dbus_remove_watch(connection, context_added_watch);
490         g_dbus_remove_watch(connection, sim_watch);
491         g_dbus_remove_watch(connection, cm_watch);
492         g_dbus_remove_watch(connection, modem_watch);
493         g_dbus_remove_watch(connection, modem_added_watch);
494         g_dbus_remove_watch(connection, modem_removed_watch);
495         g_dbus_remove_watch(connection, watch);
496
497         dbus_connection_unref(connection);
498 }
499
500 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
501                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)