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