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