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