Add static IP support for oFono interaction
[platform/upstream/connman.git] / plugins / ofono.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27
28 #include <gdbus.h>
29 #include <string.h>
30
31 #define CONNMAN_API_SUBJECT_TO_CHANGE
32 #include <connman/plugin.h>
33 #include <connman/element.h>
34 #include <connman/device.h>
35 #include <connman/network.h>
36 #include <connman/dbus.h>
37 #include <connman/inet.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_GPRS_INTERFACE            OFONO_SERVICE ".DataConnectionManager"
45 #define OFONO_SIM_INTERFACE             OFONO_SERVICE ".SimManager"
46 #define OFONO_PRI_CONTEXT_INTERFACE     OFONO_SERVICE ".PrimaryDataContext"
47
48 #define PROPERTY_CHANGED                "PropertyChanged"
49 #define GET_PROPERTIES                  "GetProperties"
50 #define SET_PROPERTY                    "SetProperty"
51
52 #define TIMEOUT 5000
53
54 static DBusConnection *connection;
55
56 static GHashTable *modem_hash = NULL;
57
58 struct modem_data {
59         char *path;
60         struct connman_device *device;
61         gboolean available;
62 };
63
64 static int modem_probe(struct connman_device *device)
65 {
66         DBG("device %p", device);
67
68         return 0;
69 }
70
71 static void modem_remove(struct connman_device *device)
72 {
73         DBG("device %p", device);
74 }
75
76 static void powered_reply(DBusPendingCall *call, void *user_data)
77 {
78         DBusMessage *reply;
79         DBusError error;
80
81         DBG("");
82
83         dbus_error_init(&error);
84
85         reply = dbus_pending_call_steal_reply(call);
86
87         if (dbus_set_error_from_message(&error, reply)) {
88                 connman_error("%s", error.message);
89                 dbus_error_free(&error);
90         }
91
92         dbus_message_unref(reply);
93 }
94
95 static int gprs_change_powered(const char *path, dbus_bool_t powered)
96 {
97         DBusMessage *message;
98         DBusMessageIter iter;
99         DBusPendingCall *call;
100
101         DBG("path %s powered %d", path, powered);
102
103         if (path == NULL)
104                 return -EINVAL;
105
106         message = dbus_message_new_method_call(OFONO_SERVICE, path,
107                                         OFONO_GPRS_INTERFACE, SET_PROPERTY);
108         if (message == NULL)
109                 return -ENOMEM;
110
111         dbus_message_set_auto_start(message, FALSE);
112
113         dbus_message_iter_init_append(message, &iter);
114         connman_dbus_property_append_variant(&iter, "Powered",
115                                                 DBUS_TYPE_BOOLEAN, &powered);
116
117         if (dbus_connection_send_with_reply(connection, message,
118                                                 &call, TIMEOUT) == FALSE) {
119                 connman_error("Failed to change powered property");
120                 dbus_message_unref(message);
121                 return -EINVAL;
122         }
123
124         if (call == NULL) {
125                 connman_error("D-Bus connection not available");
126                 dbus_message_unref(message);
127                 return -EINVAL;
128         }
129
130         dbus_pending_call_set_notify(call, powered_reply, (void *)path, NULL);
131
132         dbus_message_unref(message);
133
134         return -EINPROGRESS;
135 }
136
137 static int modem_enable(struct connman_device *device)
138 {
139         const char *path = connman_device_get_string(device, "Path");
140
141         DBG("device %p, path, %s", device, path);
142
143         return gprs_change_powered(path, TRUE);
144 }
145
146 static int modem_disable(struct connman_device *device)
147 {
148         const char *path = connman_device_get_string(device, "Path");
149
150         DBG("device %p, path %s", device, path);
151
152         return gprs_change_powered(path, FALSE);
153 }
154
155 static struct connman_device_driver modem_driver = {
156         .name           = "modem",
157         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
158         .probe          = modem_probe,
159         .remove         = modem_remove,
160         .enable         = modem_enable,
161         .disable        = modem_disable,
162 };
163
164 static char *get_ident(const char *path)
165 {
166         char *ident, *pos;
167
168         if (*path != '/')
169                 return NULL;
170
171         ident = g_strdup(path + 1);
172
173         pos = ident;
174
175         while ((pos = strchr(pos, '/')) != NULL)
176                 *pos = '_';
177
178         return ident;
179 }
180
181 static void config_network_reply(DBusPendingCall *call, void *user_data)
182 {
183         struct connman_network *network = user_data;
184         DBusMessage *reply;
185         DBusMessageIter array, dict;
186         gboolean internet_type = FALSE;
187
188         DBG("network %p", network);
189
190         reply = dbus_pending_call_steal_reply(call);
191         if (reply == NULL)
192                 goto done;
193
194         if (dbus_message_iter_init(reply, &array) == FALSE)
195                 goto done;
196
197         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
198                 goto done;
199
200         dbus_message_iter_recurse(&array, &dict);
201
202         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
203                 DBusMessageIter entry, value;
204                 const char *key;
205
206                 dbus_message_iter_recurse(&dict, &entry);
207                 dbus_message_iter_get_basic(&entry, &key);
208
209                 dbus_message_iter_next(&entry);
210                 dbus_message_iter_recurse(&entry, &value);
211
212                 if (g_str_equal(key, "Name") == TRUE) {
213                         const char *name;
214
215                         dbus_message_iter_get_basic(&value, &name);
216                         connman_network_set_name(network, name);
217                 } else if (g_str_equal(key, "Type") == TRUE) {
218                         const char *type;
219
220                         dbus_message_iter_get_basic(&value, &type);
221                         if (g_strcmp0(type, "internet") == 0) {
222                                 internet_type = TRUE;
223
224                                 connman_network_set_protocol(network,
225                                                 CONNMAN_NETWORK_PROTOCOL_IP);
226                         } else {
227                                 internet_type = FALSE;
228
229                                 connman_network_set_protocol(network,
230                                         CONNMAN_NETWORK_PROTOCOL_UNKNOWN);
231                         }
232                 }
233
234                 dbus_message_iter_next(&dict);
235         }
236
237         if (internet_type == TRUE) {
238                 const char *path;
239                 char *group;
240
241                 path = connman_network_get_string(network, "Path");
242
243                 group = get_ident(path);
244
245                 connman_network_set_group(network, group);
246
247                 g_free(group);
248         }
249
250 done:
251         dbus_message_unref(reply);
252 }
253
254 static void config_network(struct connman_network *network, const char *path)
255 {
256         DBusMessage *message;
257         DBusPendingCall *call;
258
259         DBG("path %s", path);
260
261         message = dbus_message_new_method_call(OFONO_SERVICE, path,
262                                 OFONO_PRI_CONTEXT_INTERFACE, GET_PROPERTIES);
263         if (message == NULL)
264                 return;
265
266         dbus_message_set_auto_start(message, FALSE);
267
268         if (dbus_connection_send_with_reply(connection, message,
269                                                 &call, TIMEOUT) == FALSE) {
270                 connman_error("Failed to get Primary Context");
271                 goto done;
272         }
273
274         if (call == NULL) {
275                 connman_error("D-Bus connection not available");
276                 goto done;
277         }
278
279         dbus_pending_call_set_notify(call, config_network_reply,
280                                                 (void *)network, NULL);
281
282 done:
283         dbus_message_unref(message);
284 }
285
286 static int network_probe(struct connman_network *network)
287 {
288         const char *path;
289
290         path = connman_network_get_string(network, "Path");
291
292         DBG("network %p path %s", network, path);
293
294         config_network(network, path);
295
296         return 0;
297 }
298
299 static struct connman_network *pending_network;
300
301 static gboolean pending_network_is_available(
302                 struct connman_network *pending_network)
303 {
304         struct connman_device *device;
305         struct connman_network *network;
306         const char *identifier;
307         char *ident;
308
309         /* Modem may be removed during waiting for active reply */
310         device  = connman_network_get_device(pending_network);
311         if (device == NULL)
312                 return FALSE;
313
314         identifier = connman_network_get_identifier(pending_network);
315
316         ident = g_strdup(identifier);
317
318         connman_network_unref(pending_network);
319
320         /* network may be removed during waiting for active reply */
321         network = connman_device_get_network(device, ident);
322
323         g_free(ident);
324
325         if (network == NULL)
326                 return FALSE;
327
328         return TRUE;
329 }
330
331 static void set_active_reply(DBusPendingCall *call, void *user_data)
332 {
333         DBusMessage *reply;
334         DBusError error;
335         struct connman_network *network = user_data;
336
337         DBG("network %p", network);
338
339         if (pending_network_is_available(network) == FALSE)
340                 return;
341
342         reply = dbus_pending_call_steal_reply(call);
343         if (reply == NULL)
344                 return;
345
346         dbus_error_init(&error);
347         if (dbus_set_error_from_message(&error, reply)) {
348                 if (connman_network_get_index(network) < 0)
349                         connman_network_set_error(network,
350                                 CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
351
352                 pending_network = NULL;
353
354                 connman_error("%s", error.message);
355
356                 dbus_error_free(&error);
357         } else
358                 pending_network = network;
359
360         dbus_message_unref(reply);
361 }
362
363 static int set_network_active(struct connman_network *network,
364                                                 dbus_bool_t active)
365 {
366         DBusMessage *message;
367         DBusPendingCall *call;
368         DBusMessageIter iter;
369
370         const char *path = connman_network_get_string(network, "Path");
371
372         DBG("network %p, path %s, active %d", network, path, active);
373
374         if (path == NULL)
375                 return -EINVAL;
376
377         message = dbus_message_new_method_call(OFONO_SERVICE, path,
378                                 OFONO_PRI_CONTEXT_INTERFACE, SET_PROPERTY);
379         if (message == NULL)
380                 return -ENOMEM;
381
382         dbus_message_set_auto_start(message, FALSE);
383
384         dbus_message_iter_init_append(message, &iter);
385         connman_dbus_property_append_variant(&iter, "Active",
386                                                 DBUS_TYPE_BOOLEAN, &active);
387
388         if (dbus_connection_send_with_reply(connection, message,
389                                         &call, TIMEOUT * 10) == FALSE) {
390                 connman_error("Failed to connect service");
391                 dbus_message_unref(message);
392                 return -EINVAL;
393         }
394
395         if (call == NULL) {
396                 connman_error("D-Bus connection not available");
397                 dbus_message_unref(message);
398                 return -EINVAL;
399         }
400
401         connman_network_ref(network);
402
403         dbus_pending_call_set_notify(call, set_active_reply, network, NULL);
404
405         dbus_message_unref(message);
406
407         if (active == TRUE)
408                 return -EINPROGRESS;
409
410         return 0;
411 }
412
413 static int network_connect(struct connman_network *network)
414 {
415         if (connman_network_get_index(network) >= 0)
416                 return -EISCONN;
417
418         return set_network_active(network, TRUE);
419 }
420
421 static int network_disconnect(struct connman_network *network)
422 {
423         if (connman_network_get_index(network) < 0)
424                 return -ENOTCONN;
425
426         return set_network_active(network, FALSE);
427 }
428
429 static void network_remove(struct connman_network *network)
430 {
431         DBG("network %p", network);
432 }
433
434 static struct connman_network_driver network_driver = {
435         .name           = "network",
436         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
437         .probe          = network_probe,
438         .remove         = network_remove,
439         .connect        = network_connect,
440         .disconnect     = network_disconnect,
441 };
442
443 static void add_network(struct connman_device *device, const char *path)
444 {
445         struct connman_network *network;
446         char *ident;
447
448         DBG("device %p path %s", device, path);
449
450         network = connman_device_get_network(device, path);
451         if (network != NULL)
452                 return;
453
454         ident = get_ident(path);
455
456         network = connman_network_create(ident,
457                                         CONNMAN_NETWORK_TYPE_CELLULAR);
458         if (network == NULL)
459                 return;
460
461         g_free(ident);
462
463         connman_network_set_string(network, "Path", path);
464         connman_network_set_available(network, TRUE);
465         connman_network_set_index(network, -1);
466         connman_device_add_network(device, network);
467 }
468
469 static void add_networks(struct connman_device *device, DBusMessageIter *array)
470 {
471         DBusMessageIter entry;
472
473         DBG("");
474
475         dbus_message_iter_recurse(array, &entry);
476
477         while (dbus_message_iter_get_arg_type(&entry) ==
478                                         DBUS_TYPE_OBJECT_PATH) {
479                 const char *path;
480
481                 dbus_message_iter_get_basic(&entry, &path);
482
483                 add_network(device, path);
484
485                 dbus_message_iter_next(&entry);
486         }
487 }
488
489 static void check_networks_reply(DBusPendingCall *call, void *user_data)
490 {
491         struct connman_device *device = user_data;
492         DBusMessage *reply;
493         DBusMessageIter array, dict, contexts;
494         dbus_bool_t attached;
495
496         DBG("device %p", device);
497
498         reply = dbus_pending_call_steal_reply(call);
499         if (reply == NULL)
500                 goto done;
501
502         if (dbus_message_iter_init(reply, &array) == FALSE)
503                 goto done;
504
505         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
506                 goto done;
507
508         dbus_message_iter_recurse(&array, &dict);
509
510         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
511                 DBusMessageIter entry, value;
512                 const char *key;
513
514                 dbus_message_iter_recurse(&dict, &entry);
515                 dbus_message_iter_get_basic(&entry, &key);
516
517                 dbus_message_iter_next(&entry);
518                 dbus_message_iter_recurse(&entry, &value);
519
520                 DBG("key %s", key);
521
522                 if (g_str_equal(key, "Attached") == TRUE) {
523                         dbus_message_iter_get_basic(&value, &attached);
524                         DBG("Attached %d", attached);
525                 } else if (g_str_equal(key, "PrimaryContexts") == TRUE) {
526                         contexts = value;
527                 } else if (g_str_equal(key, "Status") == TRUE) {
528                         const char *status;
529
530                         dbus_message_iter_get_basic(&value, &status);
531                         /* FIXME: add roaming support */
532                 } else if (g_str_equal(key, "Powered") == TRUE) {
533                         dbus_bool_t powered;
534
535                         dbus_message_iter_get_basic(&value, &powered);
536
537                         connman_device_set_powered(device, powered);
538                 }
539
540                 dbus_message_iter_next(&dict);
541         }
542
543         if (attached == TRUE)
544                 add_networks(device, &contexts);
545
546 done:
547         dbus_message_unref(reply);
548 }
549
550 static void check_networks(struct modem_data *modem)
551 {
552         DBusMessage *message;
553         DBusPendingCall *call;
554         struct connman_device *device;
555
556         DBG("modem %p", modem);
557
558         if (modem == NULL)
559                 return;
560
561         device = modem->device;
562         if (device == NULL)
563                 return;
564
565         message = dbus_message_new_method_call(OFONO_SERVICE, modem->path,
566                                         OFONO_GPRS_INTERFACE, GET_PROPERTIES);
567         if (message == NULL)
568                 return;
569
570         dbus_message_set_auto_start(message, FALSE);
571
572         if (dbus_connection_send_with_reply(connection, message,
573                                                 &call, TIMEOUT) == FALSE) {
574                 connman_error("Failed to get ofono GPRS");
575                 goto done;
576         }
577
578         if (call == NULL) {
579                 connman_error("D-Bus connection not available");
580                 goto done;
581         }
582
583         dbus_pending_call_set_notify(call, check_networks_reply,
584                                                 (void *)device, NULL);
585
586 done:
587         dbus_message_unref(message);
588 }
589
590 static void add_device(const char *path, const char *imsi)
591 {
592         struct modem_data *modem;
593         struct connman_device *device;
594
595         DBG("path %s imsi %s", path, imsi);
596
597         if (path == NULL)
598                 return;
599
600         if (imsi == NULL)
601                 return;
602
603         modem = g_hash_table_lookup(modem_hash, path);
604         if (modem == NULL)
605                 return;
606
607         device = connman_device_create(imsi, CONNMAN_DEVICE_TYPE_CELLULAR);
608         if (device == NULL)
609                 return;
610
611         connman_device_set_ident(device, imsi);
612
613         connman_device_set_mode(device, CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE);
614
615         connman_device_set_string(device, "Path", path);
616
617         if (connman_device_register(device) < 0) {
618                 connman_device_unref(device);
619                 return;
620         }
621
622         modem->device = device;
623
624         check_networks(modem);
625 }
626
627 static void sim_properties_reply(DBusPendingCall *call, void *user_data)
628 {
629         const char *path = user_data;
630         DBusMessage *reply;
631         DBusMessageIter array, dict;
632
633         DBG("path %s", path);
634
635         reply = dbus_pending_call_steal_reply(call);
636         if (reply == NULL)
637                 return;
638
639         if (dbus_message_iter_init(reply, &array) == FALSE)
640                 goto done;
641
642         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
643                 goto done;
644
645         dbus_message_iter_recurse(&array, &dict);
646
647         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
648                 DBusMessageIter entry, value;
649                 const char *key, *imsi;
650
651                 dbus_message_iter_recurse(&dict, &entry);
652                 dbus_message_iter_get_basic(&entry, &key);
653
654                 dbus_message_iter_next(&entry);
655                 dbus_message_iter_recurse(&entry, &value);
656
657                 if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
658                         dbus_message_iter_get_basic(&value, &imsi);
659
660                         add_device(path, imsi);
661                 }
662
663                 dbus_message_iter_next(&dict);
664         }
665
666 done:
667         dbus_message_unref(reply);
668 }
669
670 static void get_imsi(const char *path)
671 {
672         DBusMessage *message;
673         DBusPendingCall *call;
674
675         DBG("path %s", path);
676
677         message = dbus_message_new_method_call(OFONO_SERVICE, path,
678                                 OFONO_SIM_INTERFACE, GET_PROPERTIES);
679         if (message == NULL)
680                 return;
681
682         dbus_message_set_auto_start(message, FALSE);
683
684         if (dbus_connection_send_with_reply(connection, message,
685                                                 &call, TIMEOUT) == FALSE) {
686                 connman_error("Failed to get ofono modem sim");
687                 goto done;
688         }
689
690         if (call == NULL) {
691                 connman_error("D-Bus connection not available");
692                 goto done;
693         }
694
695         dbus_pending_call_set_notify(call, sim_properties_reply,
696                                                 (void *)path, NULL);
697
698 done:
699         dbus_message_unref(message);
700 }
701
702 static int modem_change_powered(const char *path, dbus_bool_t powered)
703 {
704         DBusMessage *message;
705         DBusMessageIter iter;
706         DBusPendingCall *call;
707
708         DBG("path %s powered %d", path, powered);
709
710         if (path == NULL)
711                 return -EINVAL;
712
713         message = dbus_message_new_method_call(OFONO_SERVICE, path,
714                                         OFONO_MODEM_INTERFACE, SET_PROPERTY);
715         if (message == NULL)
716                 return -ENOMEM;
717
718         dbus_message_set_auto_start(message, FALSE);
719
720         dbus_message_iter_init_append(message, &iter);
721         connman_dbus_property_append_variant(&iter, "Powered",
722                                                 DBUS_TYPE_BOOLEAN, &powered);
723
724         if (dbus_connection_send_with_reply(connection, message,
725                                                 &call, TIMEOUT) == FALSE) {
726                 connman_error("Failed to change powered property");
727                 dbus_message_unref(message);
728                 return -EINVAL;
729         }
730
731         if (call == NULL) {
732                 connman_error("D-Bus connection not available");
733                 dbus_message_unref(message);
734                 return -EINVAL;
735         }
736
737         dbus_pending_call_set_notify(call, powered_reply, NULL, NULL);
738
739         dbus_message_unref(message);
740
741         return -EINPROGRESS;
742 }
743
744 static struct modem_data *add_modem(const char *path)
745 {
746         struct modem_data *modem;
747
748         if (path == NULL)
749                 return NULL;
750
751         modem = g_hash_table_lookup(modem_hash, path);
752         if (modem != NULL) {
753                 modem->available = TRUE;
754
755                 return modem;
756         }
757
758         modem = g_try_new0(struct modem_data, 1);
759         if (modem == NULL)
760                 return NULL;
761
762         modem->path = g_strdup(path);
763         modem->device = NULL;
764         modem->available = TRUE;
765
766         g_hash_table_insert(modem_hash, g_strdup(path), modem);
767
768         return modem;
769 }
770
771 static gboolean modem_has_gprs(DBusMessageIter *array)
772 {
773         DBusMessageIter entry;
774
775         dbus_message_iter_recurse(array, &entry);
776
777         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
778                 const char *interface;
779
780                 dbus_message_iter_get_basic(&entry, &interface);
781
782                 if (g_strcmp0(OFONO_GPRS_INTERFACE, interface) == 0)
783                         return TRUE;
784
785                 dbus_message_iter_next(&entry);
786         }
787
788         return FALSE;
789 }
790
791 static void modem_properties_reply(DBusPendingCall *call, void *user_data)
792 {
793         DBusMessage *reply;
794         DBusMessageIter array, dict;
795         const char *path = user_data;
796
797         DBG("path %s", path);
798
799         reply = dbus_pending_call_steal_reply(call);
800         if (reply == NULL)
801                 goto done;
802
803         if (dbus_message_iter_init(reply, &array) == FALSE)
804                 goto done;
805
806         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
807                 goto done;
808
809         dbus_message_iter_recurse(&array, &dict);
810
811         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
812                 DBusMessageIter entry, value;
813                 const char *key;
814                 dbus_bool_t powered;
815
816                 dbus_message_iter_recurse(&dict, &entry);
817                 dbus_message_iter_get_basic(&entry, &key);
818
819                 dbus_message_iter_next(&entry);
820                 dbus_message_iter_recurse(&entry, &value);
821
822                 if (g_str_equal(key, "Powered") == TRUE) {
823                         dbus_message_iter_get_basic(&value, &powered);
824
825                         if (powered == FALSE) {
826                                 modem_change_powered(path, TRUE);
827                                 break;
828                         }
829                 } else if (g_str_equal(key, "Interface") == TRUE) {
830                         if (modem_has_gprs(&value) == TRUE)
831                                 get_imsi(path);
832                 }
833
834                 dbus_message_iter_next(&dict);
835         }
836
837 done:
838         dbus_message_unref(reply);
839 }
840
841 static void get_modem_properties(struct modem_data *modem)
842 {
843         DBusMessage *message;
844         DBusPendingCall *call;
845
846         DBG("path %s", modem->path);
847
848         if (modem->path == NULL)
849                 return;
850
851         message = dbus_message_new_method_call(OFONO_SERVICE, modem->path,
852                                 OFONO_MODEM_INTERFACE, GET_PROPERTIES);
853         if (message == NULL)
854                 return;
855
856         dbus_message_set_auto_start(message, FALSE);
857
858         if (dbus_connection_send_with_reply(connection, message,
859                                                 &call, TIMEOUT) == FALSE) {
860                 connman_error("Failed to get ofono modem");
861                 goto done;
862         }
863
864         if (call == NULL) {
865                 connman_error("D-Bus connection not available");
866                 goto done;
867         }
868
869         dbus_pending_call_set_notify(call, modem_properties_reply,
870                                                 (void *)modem->path, NULL);
871
872 done:
873         dbus_message_unref(message);
874 }
875
876 static void mask_unavailable(gpointer key, gpointer value, gpointer user_data)
877 {
878         struct modem_data *modem = value;
879
880         modem->available = FALSE;
881 }
882
883 static void modems_set_unavailable()
884 {
885         g_hash_table_foreach(modem_hash, mask_unavailable, NULL);
886 }
887
888 static void cleanup_modem(gpointer key, gpointer value, gpointer user_data)
889 {
890         struct modem_data *modem = value;
891
892         if (modem->available == FALSE)
893                 g_hash_table_remove(modem_hash, key);
894 }
895
896 static void cleanup_modems()
897 {
898         g_hash_table_foreach(modem_hash, cleanup_modem, NULL);
899 }
900
901 static void update_modems(DBusMessageIter *array)
902 {
903         DBusMessageIter entry;
904
905         dbus_message_iter_recurse(array, &entry);
906
907         modems_set_unavailable();
908
909         while (dbus_message_iter_get_arg_type(&entry) ==
910                                         DBUS_TYPE_OBJECT_PATH) {
911                 const char *path;
912                 struct modem_data *modem;
913
914                 dbus_message_iter_get_basic(&entry, &path);
915
916                 modem = add_modem(path);
917                 if (modem != NULL)
918                         get_modem_properties(modem);
919
920                 dbus_message_iter_next(&entry);
921         }
922
923         cleanup_modems();
924 }
925
926 static void manager_properties_reply(DBusPendingCall *call, void *user_data)
927 {
928         DBusMessage *reply;
929         DBusMessageIter array, dict;
930
931         DBG("");
932
933         reply = dbus_pending_call_steal_reply(call);
934         if (reply == NULL)
935                 goto done;
936
937         if (dbus_message_iter_init(reply, &array) == FALSE)
938                 goto done;
939
940         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
941                 goto done;
942
943         dbus_message_iter_recurse(&array, &dict);
944
945         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
946                 DBusMessageIter entry, value;
947                 const char *key;
948
949                 dbus_message_iter_recurse(&dict, &entry);
950                 dbus_message_iter_get_basic(&entry, &key);
951
952                 dbus_message_iter_next(&entry);
953                 dbus_message_iter_recurse(&entry, &value);
954
955                 if (g_str_equal(key, "Modems") == TRUE) {
956                         update_modems(&value);
957                         break;
958                 }
959
960                 dbus_message_iter_next(&dict);
961         }
962
963 done:
964         dbus_message_unref(reply);
965 }
966
967 static void modem_remove_device(struct modem_data *modem)
968 {
969         if (modem->device == NULL)
970                 return;
971
972         connman_device_unregister(modem->device);
973         connman_device_unref(modem->device);
974
975         modem->device = NULL;
976 }
977
978 static void remove_modem(gpointer data)
979 {
980         struct modem_data *modem = data;
981
982         g_free(modem->path);
983
984         modem_remove_device(modem);
985
986         g_free(modem);
987 }
988
989 static void ofono_connect(DBusConnection *connection, void *user_data)
990 {
991         DBusMessage *message;
992         DBusPendingCall *call;
993
994         DBG("connection %p", connection);
995
996         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
997                                                 g_free, remove_modem);
998
999         message = dbus_message_new_method_call(OFONO_SERVICE, "/",
1000                                 OFONO_MANAGER_INTERFACE, GET_PROPERTIES);
1001         if (message == NULL)
1002                 return;
1003
1004         dbus_message_set_auto_start(message, FALSE);
1005
1006         if (dbus_connection_send_with_reply(connection, message,
1007                                                 &call, TIMEOUT) == FALSE) {
1008                 connman_error("Failed to get ofono modems");
1009                 goto done;
1010         }
1011
1012         if (call == NULL) {
1013                 connman_error("D-Bus connection not available");
1014                 goto done;
1015         }
1016
1017         dbus_pending_call_set_notify(call, manager_properties_reply,
1018                                                                 NULL, NULL);
1019
1020 done:
1021         dbus_message_unref(message);
1022
1023 }
1024
1025 static void ofono_disconnect(DBusConnection *connection, void *user_data)
1026 {
1027         DBG("connection %p", connection);
1028
1029         if (modem_hash == NULL)
1030                 return;
1031
1032         g_hash_table_destroy(modem_hash);
1033
1034         modem_hash = NULL;
1035 }
1036
1037 static void modem_changed(DBusConnection *connection, DBusMessage *message)
1038 {
1039         const char *path = dbus_message_get_path(message);
1040         struct modem_data *modem;
1041         DBusMessageIter iter, value;
1042         const char *key;
1043
1044         DBG("path %s", path);
1045
1046         modem = g_hash_table_lookup(modem_hash, path);
1047         if (modem == NULL)
1048                 return;
1049
1050         if (dbus_message_iter_init(message, &iter) == FALSE)
1051                 return;
1052
1053         dbus_message_iter_get_basic(&iter, &key);
1054
1055         dbus_message_iter_next(&iter);
1056         dbus_message_iter_recurse(&iter, &value);
1057
1058         if (g_str_equal(key, "Powered") == TRUE) {
1059                 dbus_bool_t powered;
1060
1061                 dbus_message_iter_get_basic(&value, &powered);
1062                 if (powered == TRUE)
1063                         return;
1064
1065                 modem_remove_device(modem);
1066         } else if (g_str_equal(key, "Interfaces") == TRUE) {
1067                 if (modem_has_gprs(&value) == TRUE) {
1068                         if (modem->device == NULL)
1069                                 get_imsi(modem->path);
1070                 } else if (modem->device != NULL)
1071                         modem_remove_device(modem);
1072         }
1073 }
1074
1075 static void gprs_changed(DBusConnection *connection, DBusMessage *message)
1076 {
1077         const char *path = dbus_message_get_path(message);
1078         struct modem_data *modem;
1079         DBusMessageIter iter, value;
1080         const char *key;
1081
1082         DBG("path %s", path);
1083
1084         modem = g_hash_table_lookup(modem_hash, path);
1085         if (modem == NULL)
1086                 return;
1087
1088         if (dbus_message_iter_init(message, &iter) == FALSE)
1089                 return;
1090
1091         dbus_message_iter_get_basic(&iter, &key);
1092
1093         dbus_message_iter_next(&iter);
1094         dbus_message_iter_recurse(&iter, &value);
1095
1096         if (g_str_equal(key, "Attached") == TRUE) {
1097                 dbus_bool_t attached;
1098
1099                 dbus_message_iter_get_basic(&value, &attached);
1100
1101                 DBG("Attached %d", attached);
1102
1103                 if (attached == TRUE)
1104                         check_networks(modem);
1105                 else if (modem->device != NULL)
1106                         connman_device_remove_all_networks(modem->device);
1107
1108         } else if (g_str_equal(key, "Status") == TRUE) {
1109                 const char *status;
1110                 dbus_message_iter_get_basic(&value, &status);
1111
1112                 DBG("status %s", status);
1113
1114                 /* FIXME: add roaming support */
1115         } else if (g_str_equal(key, "PrimaryContexts") == TRUE) {
1116                 check_networks(modem);
1117         } else if (g_str_equal(key, "Powered") == TRUE) {
1118                 dbus_bool_t powered;
1119
1120                 if (modem->device == NULL)
1121                         return;
1122
1123                 dbus_message_iter_get_basic(&value, &powered);
1124                 connman_device_set_powered(modem->device, powered);
1125         }
1126 }
1127
1128 static void manager_changed(DBusConnection *connection, DBusMessage *message)
1129 {
1130         const char *path = dbus_message_get_path(message);
1131         DBusMessageIter iter, value;
1132         const char *key;
1133
1134         DBG("path %s", path);
1135
1136         if (dbus_message_iter_init(message, &iter) == FALSE)
1137                 return;
1138
1139         dbus_message_iter_get_basic(&iter, &key);
1140
1141         dbus_message_iter_next(&iter);
1142         dbus_message_iter_recurse(&iter, &value);
1143
1144         if (g_str_equal(key, "Modems") == TRUE)
1145                 update_modems(&value);
1146 }
1147
1148 static void get_dns(DBusMessageIter *array, struct connman_element *parent)
1149 {
1150         DBusMessageIter entry;
1151         gchar *nameserver = NULL, *nameserver_old = NULL;
1152
1153         DBG("");
1154
1155         dbus_message_iter_recurse(array, &entry);
1156
1157         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
1158                 const char *dns;
1159
1160                 dbus_message_iter_get_basic(&entry, &dns);
1161
1162                 DBG("dns %s", dns);
1163
1164                 if (nameserver == NULL) {
1165
1166                         nameserver = g_strdup(dns);
1167                 } else {
1168
1169                         nameserver_old = nameserver;
1170                         nameserver = g_strdup_printf("%s %s",
1171                                                 nameserver_old, dns);
1172                         g_free(nameserver_old);
1173                 }
1174
1175                 dbus_message_iter_next(&entry);
1176         }
1177
1178         parent->ipv4.nameserver = nameserver;
1179 }
1180
1181 static void update_settings(DBusMessageIter *array,
1182                         struct connman_element *parent)
1183 {
1184         DBusMessageIter dict;
1185         const char *interface = NULL;
1186
1187         DBG("");
1188
1189         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
1190                 return;
1191
1192         dbus_message_iter_recurse(array, &dict);
1193
1194         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1195                 DBusMessageIter entry, value;
1196                 const char *key;
1197
1198                 dbus_message_iter_recurse(&dict, &entry);
1199                 dbus_message_iter_get_basic(&entry, &key);
1200
1201                 dbus_message_iter_next(&entry);
1202                 dbus_message_iter_recurse(&entry, &value);
1203
1204                 if (g_str_equal(key, "Interface") == TRUE) {
1205                         int index;
1206
1207                         dbus_message_iter_get_basic(&value, &interface);
1208
1209                         DBG("interface %s", interface);
1210
1211                         index = connman_inet_ifindex(interface);
1212                         if (index >= 0) {
1213                                 connman_network_set_index(
1214                                         pending_network, index);
1215                         } else {
1216                                 connman_error("Can not find interface %s",
1217                                                                 interface);
1218                                 break;
1219                         }
1220                 } else if (g_str_equal(key, "Method") == TRUE) {
1221                         const char *method;
1222
1223                         dbus_message_iter_get_basic(&value, &method);
1224                         if (g_strcmp0(method, "static") == 0) {
1225
1226                                 parent->ipv4.method =
1227                                         CONNMAN_IPCONFIG_METHOD_STATIC;
1228                         } else if (g_strcmp0(method, "dhcp") == 0) {
1229
1230                                 parent->ipv4.method =
1231                                         CONNMAN_IPCONFIG_METHOD_DHCP;
1232                                 break;
1233                         }
1234                 } else if (g_str_equal(key, "Address") == TRUE) {
1235                         const char *address;
1236
1237                         dbus_message_iter_get_basic(&value, &address);
1238
1239                         DBG("address %s", address);
1240
1241                         parent->ipv4.address = g_strdup(address);
1242                 } else if (g_str_equal(key, "Netmask") == TRUE) {
1243                         const char *netmask;
1244
1245                         dbus_message_iter_get_basic(&value, &netmask);
1246
1247                         DBG("netmask %s", netmask);
1248
1249                         parent->ipv4.netmask = g_strdup(netmask);
1250                 } else if (g_str_equal(key, "DomainNameServers") == TRUE) {
1251
1252                         get_dns(&value, parent);
1253                 } else if (g_str_equal(key, "Gateway") == TRUE) {
1254                         const char *gateway;
1255
1256                         dbus_message_iter_get_basic(&value, &gateway);
1257
1258                         DBG("gateway %s", gateway);
1259
1260                         parent->ipv4.gateway = g_strdup(gateway);
1261                 }
1262
1263                 dbus_message_iter_next(&dict);
1264         }
1265
1266         /* deactive, oFono send NULL inteface before deactive signal */
1267         if (interface == NULL)
1268                 connman_network_set_index(pending_network, -1);
1269 }
1270
1271 static void cleanup_ipconfig(struct connman_element *parent)
1272 {
1273         g_free(parent->ipv4.address);
1274         parent->ipv4.address = NULL;
1275
1276         g_free(parent->ipv4.netmask);
1277         parent->ipv4.netmask = NULL;
1278
1279         g_free(parent->ipv4.nameserver);
1280         parent->ipv4.nameserver = NULL;
1281
1282         g_free(parent->ipv4.gateway);
1283         parent->ipv4.gateway = NULL;
1284
1285         parent->ipv4.method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
1286 }
1287
1288 static int static_network_set_connected(
1289                 struct connman_network *pending_network,
1290                                 struct connman_element *parent,
1291                                         connman_bool_t connected)
1292 {
1293         if (connected == TRUE) {
1294                 struct connman_element *element;
1295
1296                 if (parent->ipv4.address == NULL)
1297                         goto error;
1298
1299                 if (parent->ipv4.netmask == NULL)
1300                         goto error;
1301
1302                 element = connman_element_create(NULL);
1303                 if (element == NULL) {
1304                         connman_error("Can not create connman_element");
1305                         return -ENOMEM;
1306                 }
1307
1308                 element->type = CONNMAN_ELEMENT_TYPE_IPV4;
1309                 element->index = parent->index;
1310
1311                 if (connman_element_register(element, parent) < 0) {
1312                         connman_element_unref(element);
1313                         goto error;
1314                 }
1315         } else
1316                 cleanup_ipconfig(parent);
1317
1318         connman_network_set_connected(pending_network, connected);
1319
1320         return 0;
1321
1322 error:
1323         connman_network_set_error(pending_network,
1324                 CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
1325
1326         cleanup_ipconfig(parent);
1327
1328         return -EINVAL;
1329 }
1330
1331 static void pri_context_changed(DBusConnection *connection,
1332                                         DBusMessage *message)
1333 {
1334         const char *path = dbus_message_get_path(message);
1335         struct connman_element *parent;
1336         const char *pending_path;
1337         DBusMessageIter iter, value;
1338         const char *key;
1339
1340         DBG("pending_network %p, path %s", pending_network, path);
1341
1342         if (pending_network == NULL)
1343                 return;
1344
1345         pending_path = connman_network_get_string(pending_network, "Path");
1346         if (g_strcmp0(pending_path, path) != 0)
1347                 return;
1348
1349         parent = connman_network_get_element(pending_network);
1350
1351         if (dbus_message_iter_init(message, &iter) == FALSE)
1352                 return;
1353
1354         dbus_message_iter_get_basic(&iter, &key);
1355
1356         dbus_message_iter_next(&iter);
1357         dbus_message_iter_recurse(&iter, &value);
1358
1359         if (g_str_equal(key, "Settings") == TRUE) {
1360
1361                 update_settings(&value, parent);
1362         } else if (g_str_equal(key, "Active") == TRUE) {
1363                 dbus_bool_t active;
1364
1365                 dbus_message_iter_get_basic(&value, &active);
1366
1367                 switch (parent->ipv4.method) {
1368                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1369                 case CONNMAN_IPCONFIG_METHOD_IGNORE:
1370                         break;
1371                 case CONNMAN_IPCONFIG_METHOD_STATIC:
1372                         if (static_network_set_connected(
1373                                         pending_network, parent, active) < 0)
1374                                 set_network_active(pending_network, FALSE);
1375                         break;
1376                 case CONNMAN_IPCONFIG_METHOD_DHCP:
1377                         connman_network_set_connected(pending_network, active);
1378                         break;
1379                 }
1380
1381                 pending_network = NULL;
1382         }
1383 }
1384
1385 static DBusHandlerResult ofono_signal(DBusConnection *connection,
1386                                         DBusMessage *message, void *user_data)
1387 {
1388         if (dbus_message_is_signal(message, OFONO_MODEM_INTERFACE,
1389                                                 PROPERTY_CHANGED) == TRUE) {
1390                 modem_changed(connection, message);
1391         } else if (dbus_message_is_signal(message, OFONO_GPRS_INTERFACE,
1392                                                 PROPERTY_CHANGED) == TRUE) {
1393                 gprs_changed(connection, message);
1394         } else if (dbus_message_is_signal(message, OFONO_MANAGER_INTERFACE,
1395                                                 PROPERTY_CHANGED) == TRUE) {
1396                 manager_changed(connection, message);
1397         } else if (dbus_message_is_signal(message, OFONO_PRI_CONTEXT_INTERFACE,
1398                                                 PROPERTY_CHANGED) == TRUE) {
1399                 pri_context_changed(connection, message);
1400         }
1401
1402         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1403 }
1404
1405 static const char *gprs_rule = "type=signal, member=" PROPERTY_CHANGED
1406                                         ",interface=" OFONO_GPRS_INTERFACE;
1407 static const char *modem_rule = "type=signal,member=" PROPERTY_CHANGED
1408                                         ",interface=" OFONO_MODEM_INTERFACE;
1409 static const char *manager_rule = "type=signal,member=" PROPERTY_CHANGED
1410                                         ",interface=" OFONO_MANAGER_INTERFACE;
1411 static const char *pri_context_rule = "type=signal,member=" PROPERTY_CHANGED
1412                                 ", interface=" OFONO_PRI_CONTEXT_INTERFACE;
1413
1414 static guint watch;
1415
1416 static int ofono_init(void)
1417 {
1418         int err;
1419
1420         connection = connman_dbus_get_connection();
1421         if (connection == NULL)
1422                 return -EIO;
1423
1424         if (dbus_connection_add_filter(connection, ofono_signal,
1425                                                 NULL, NULL) == FALSE) {
1426                 err = -EIO;
1427                 goto unref;
1428         }
1429
1430         err = connman_network_driver_register(&network_driver);
1431         if (err < 0)
1432                 goto remove;
1433
1434         err = connman_device_driver_register(&modem_driver);
1435         if (err < 0) {
1436                 connman_network_driver_unregister(&network_driver);
1437                 goto remove;
1438         }
1439
1440         watch = g_dbus_add_service_watch(connection, OFONO_SERVICE,
1441                         ofono_connect, ofono_disconnect, NULL, NULL);
1442         if (watch == 0) {
1443                 err = -EIO;
1444                 goto remove;
1445         }
1446
1447         dbus_bus_add_match(connection, modem_rule, NULL);
1448         dbus_bus_add_match(connection, gprs_rule, NULL);
1449         dbus_bus_add_match(connection, manager_rule, NULL);
1450         dbus_bus_add_match(connection, pri_context_rule, NULL);
1451
1452         return 0;
1453
1454 remove:
1455         dbus_connection_remove_filter(connection, ofono_signal, NULL);
1456
1457 unref:
1458         dbus_connection_unref(connection);
1459
1460         return err;
1461 }
1462
1463 static void ofono_exit(void)
1464 {
1465         dbus_bus_remove_match(connection, modem_rule, NULL);
1466         dbus_bus_remove_match(connection, gprs_rule, NULL);
1467         dbus_bus_remove_match(connection, manager_rule, NULL);
1468         dbus_bus_remove_match(connection, pri_context_rule, NULL);
1469
1470         g_dbus_remove_watch(connection, watch);
1471
1472         ofono_disconnect(connection, NULL);
1473
1474         connman_device_driver_unregister(&modem_driver);
1475         connman_network_driver_unregister(&network_driver);
1476
1477         dbus_connection_remove_filter(connection, ofono_signal, NULL);
1478
1479         dbus_connection_unref(connection);
1480 }
1481
1482 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
1483                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)