profile: Ignore malformed profiles
[framework/connectivity/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
367 static char *get_ident(const char *path)
368 {
369         char *pos;
370
371         if (*path != '/')
372                 return NULL;
373
374         pos = strrchr(path, '/');
375         if (pos == NULL)
376                 return NULL;
377
378         return pos + 1;
379 }
380
381 static void create_service(struct connman_network *network)
382 {
383         const char *path;
384         char *group;
385
386         DBG("");
387
388         path = connman_network_get_string(network, "Path");
389
390         group = get_ident(path);
391
392         connman_network_set_group(network, group);
393 }
394
395 static int network_probe(struct connman_network *network)
396 {
397         return 0;
398 }
399
400 static gboolean pending_network_is_available(struct connman_network *network)
401 {
402         /* Modem or network may be removed */
403         if (network == NULL || connman_network_get_device(network) == NULL) {
404                 DBG("Modem or network was removed");
405                 return FALSE;
406         }
407
408         return TRUE;
409 }
410
411 static void set_connected(struct network_info *info,
412                                 connman_bool_t connected)
413 {
414         DBG("network %p connected %d", info->network, connected);
415
416         switch (info->method) {
417         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
418         case CONNMAN_IPCONFIG_METHOD_OFF:
419         case CONNMAN_IPCONFIG_METHOD_MANUAL:
420         case CONNMAN_IPCONFIG_METHOD_AUTO:
421                 return;
422
423         case CONNMAN_IPCONFIG_METHOD_FIXED:
424                 connman_network_set_ipv4_method(info->network, info->method);
425                 connman_network_set_ipaddress(info->network, &info->ipaddress);
426
427                 break;
428
429         case CONNMAN_IPCONFIG_METHOD_DHCP:
430                 connman_network_set_ipv4_method(info->network, info->method);
431
432                 break;
433         }
434
435         connman_network_set_connected(info->network, connected);
436 }
437
438 static void set_active_reply(DBusPendingCall *call, void *user_data)
439 {
440         char const *path = user_data;
441         DBusMessage *reply;
442         DBusError error;
443         struct network_info *info;
444
445         info = g_hash_table_lookup(network_hash, path);
446
447         DBG("path %s network %p", path, info->network);
448
449         reply = dbus_pending_call_steal_reply(call);
450
451         if (!pending_network_is_available(info->network))
452                 goto done;
453
454         dbus_error_init(&error);
455
456         if (dbus_set_error_from_message(&error, reply)) {
457                 connman_error("SetProperty(Active) %s %s",
458                                 error.name, error.message);
459
460                 if (connman_network_get_index(info->network) < 0)
461                         connman_network_set_error(info->network,
462                                 CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
463
464                 dbus_error_free(&error);
465         } else if (connman_network_get_index(info->network) >= 0)
466                 set_connected(info, TRUE);
467
468 done:
469         dbus_message_unref(reply);
470
471         dbus_pending_call_unref(call);
472 }
473
474 static int set_network_active(struct connman_network *network)
475 {
476         dbus_bool_t value = TRUE;
477         const char *path = connman_network_get_string(network, "Path");
478
479         DBG("network %p, path %s", network, path);
480
481         return set_property(path, OFONO_CONTEXT_INTERFACE,
482                                 "Active", DBUS_TYPE_BOOLEAN, &value,
483                                 set_active_reply, g_strdup(path), g_free);
484 }
485
486 static int set_network_inactive(struct connman_network *network)
487 {
488         int err;
489         dbus_bool_t value = FALSE;
490         const char *path = connman_network_get_string(network, "Path");
491
492         DBG("network %p, path %s", network, path);
493
494         err = set_property(path, OFONO_CONTEXT_INTERFACE,
495                                 "Active", DBUS_TYPE_BOOLEAN, &value,
496                                 NULL, NULL, NULL);
497
498         if (err == -EINPROGRESS)
499                 err = 0;
500
501         return err;
502 }
503
504 static int network_connect(struct connman_network *network)
505 {
506         struct connman_device *device;
507         struct modem_data *modem;
508
509         DBG("network %p", network);
510
511         device = connman_network_get_device(network);
512         if (device == NULL)
513                 return -ENODEV;
514
515         modem = connman_device_get_data(device);
516         if (modem == NULL)
517                 return -ENODEV;
518
519         if (modem->registered == FALSE)
520                 return -ENOLINK;
521
522         if (modem->powered == FALSE)
523                 return -ENOLINK;
524
525         if (modem->roaming_allowed == FALSE && modem->roaming == TRUE)
526                 return -ENOLINK;
527
528         return set_network_active(network);
529 }
530
531 static int network_disconnect(struct connman_network *network)
532 {
533         DBG("network %p", network);
534
535         if (connman_network_get_index(network) < 0)
536                 return -ENOTCONN;
537
538         connman_network_set_associating(network, FALSE);
539
540         return set_network_inactive(network);
541 }
542
543 static void network_remove(struct connman_network *network)
544 {
545         char const *path = connman_network_get_string(network, "Path");
546
547         DBG("network %p path %s", network, path);
548
549         g_hash_table_remove(network_hash, path);
550 }
551
552 static struct connman_network_driver network_driver = {
553         .name           = "network",
554         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
555         .probe          = network_probe,
556         .remove         = network_remove,
557         .connect        = network_connect,
558         .disconnect     = network_disconnect,
559 };
560
561 static void update_settings(DBusMessageIter *array,
562                                 struct network_info *info);
563
564 static int add_network(struct connman_device *device,
565                         const char *path, DBusMessageIter *dict)
566 {
567         struct modem_data *modem = connman_device_get_data(device);
568         struct connman_network *network;
569         struct network_info *info;
570         char *ident;
571         const char *hash_path;
572         char const *operator;
573         dbus_bool_t active = FALSE;
574
575         DBG("modem %p device %p path %s", modem, device, path);
576
577         ident = get_ident(path);
578
579         network = connman_device_get_network(device, ident);
580         if (network != NULL)
581                 return -EALREADY;
582
583         info = g_hash_table_lookup(network_hash, path);
584         if (info != NULL) {
585                 DBG("path %p already exists with device %p", path,
586                         connman_network_get_device(info->network));
587                 if (connman_network_get_device(info->network))
588                         return -EALREADY;
589                 g_hash_table_remove(network_hash, path);
590         }
591
592         network = connman_network_create(ident, CONNMAN_NETWORK_TYPE_CELLULAR);
593         if (network == NULL)
594                 return -ENOMEM;
595
596         info = g_try_new0(struct network_info, 1);
597         if (info == NULL) {
598                 connman_network_unref(network);
599                 return -ENOMEM;
600         }
601
602         connman_ipaddress_clear(&info->ipaddress);
603         info->network = network;
604
605         connman_network_set_string(network, "Path", path);
606         hash_path = connman_network_get_string(network, "Path");
607         if (hash_path == NULL)
608                 goto error;
609
610         create_service(network);
611
612         connman_network_ref(network);
613         g_hash_table_insert(network_hash, (char *) hash_path, info);
614
615         connman_network_set_available(network, TRUE);
616         connman_network_set_index(network, -1);
617
618         operator = connman_device_get_string(device, "Operator");
619         if (operator)
620                 connman_network_set_name(network, operator);
621
622         if (modem->has_strength)
623                 connman_network_set_strength(network, modem->strength);
624
625         connman_network_set_roaming(network, modem->roaming);
626
627         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
628                 DBusMessageIter entry, value;
629                 const char *key;
630
631                 dbus_message_iter_recurse(dict, &entry);
632                 dbus_message_iter_get_basic(&entry, &key);
633
634                 dbus_message_iter_next(&entry);
635                 dbus_message_iter_recurse(&entry, &value);
636
637                 if (g_str_equal(key, "Type")) {
638                         const char *type;
639
640                         dbus_message_iter_get_basic(&value, &type);
641                         if (g_strcmp0(type, "internet") != 0) {
642                                 DBG("path %p type %s", path, type);
643                                 goto error;
644                         }
645                 } else if (g_str_equal(key, "Settings"))
646                         update_settings(&value, info);
647                 else if (g_str_equal(key, "Active") == TRUE)
648                         dbus_message_iter_get_basic(&value, &active);
649
650                 dbus_message_iter_next(dict);
651         }
652
653         if (connman_device_add_network(device, network) != 0)
654                 goto error;
655
656         /* Connect only if requested to do so */
657         if (active && connman_network_get_connecting(network) == TRUE)
658                 set_connected(info, active);
659
660         return 0;
661
662 error:
663         connman_network_unref(network);
664         g_hash_table_remove(network_hash, hash_path);
665         return -EIO;
666 }
667
668 static void check_networks_reply(DBusPendingCall *call, void *user_data)
669 {
670         char *path = user_data;
671         struct modem_data *modem;
672         DBusMessage *reply;
673         DBusMessageIter array, entry, value, properties;
674
675         DBG("path %s", path);
676
677         modem = g_hash_table_lookup(modem_hash, path);
678         if (modem == NULL)
679                 return;
680         if (modem->device == NULL)
681                 return;
682
683         reply = dbus_pending_call_steal_reply(call);
684
685         if (dbus_message_has_signature(reply, "a(oa{sv})") == FALSE)
686                 goto done;
687
688         dbus_message_iter_init(reply, &array);
689
690         dbus_message_iter_recurse(&array, &entry);
691
692         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRUCT) {
693                 char const *network_path;
694
695                 dbus_message_iter_recurse(&entry, &value);
696                 dbus_message_iter_get_basic(&value, &network_path);
697
698                 dbus_message_iter_next(&value);
699                 dbus_message_iter_recurse(&value, &properties);
700
701                 add_network(modem->device, network_path, &properties);
702
703                 dbus_message_iter_next(&entry);
704         }
705
706 done:
707         dbus_message_unref(reply);
708
709         dbus_pending_call_unref(call);
710 }
711
712 static void check_networks(struct modem_data *modem)
713 {
714         char const *path = modem->path;
715
716         DBG("modem %p path %s", modem, path);
717
718         call_ofono(path, OFONO_GPRS_INTERFACE, "GetContexts",
719                         check_networks_reply, g_strdup(path), g_free,
720                         DBUS_TYPE_INVALID);
721 }
722
723 static void modem_clear_network_errors(struct modem_data *modem)
724 {
725         struct connman_device *device = modem->device;
726         GHashTableIter i;
727         gpointer value;
728
729         if (device == NULL)
730                 return;
731
732         g_hash_table_iter_init(&i, network_hash);
733
734         while (g_hash_table_iter_next(&i, NULL, &value)) {
735                 struct network_info *info = value;
736
737                 if (connman_network_get_device(info->network) == device)
738                         connman_network_clear_error(info->network);
739         }
740 }
741
742 static void modem_operator_name_changed(struct modem_data *modem,
743                                         char const *name)
744 {
745         struct connman_device *device = modem->device;
746         GHashTableIter i;
747         gpointer value;
748
749         if (device == NULL)
750                 return;
751
752         connman_device_set_string(device, "Operator", name);
753
754         for (g_hash_table_iter_init(&i, network_hash);
755              g_hash_table_iter_next(&i, NULL, &value);) {
756                 struct network_info *info = value;
757
758                 if (connman_network_get_device(info->network) == device) {
759                         connman_network_set_name(info->network, name);
760                         connman_network_update(info->network);
761                 }
762         }
763 }
764
765 static void modem_strength_changed(struct modem_data *modem, uint8_t strength)
766 {
767         struct connman_device *device = modem->device;
768         GHashTableIter i;
769         gpointer value;
770
771         modem->strength = strength;
772         modem->has_strength = TRUE;
773
774         if (device == NULL)
775                 return;
776
777         for (g_hash_table_iter_init(&i, network_hash);
778              g_hash_table_iter_next(&i, NULL, &value);) {
779                 struct network_info *info = value;
780
781                 if (connman_network_get_device(info->network) == device) {
782                         connman_network_set_strength(info->network, strength);
783                         connman_network_update(info->network);
784                 }
785         }
786 }
787
788 static void modem_roaming_changed(struct modem_data *modem,
789                                         char const *status)
790 {
791         struct connman_device *device = modem->device;
792         connman_bool_t roaming = FALSE;
793         connman_bool_t registered = FALSE;
794         connman_bool_t was_roaming = modem->roaming;
795         GHashTableIter i;
796         gpointer value;
797
798         if (g_str_equal(status, "roaming"))
799                 roaming = TRUE;
800         else if (g_str_equal(status, "registered"))
801                 registered = TRUE;
802
803         registered = registered || roaming;
804
805         if (modem->roaming == roaming && modem->registered == registered)
806                 return;
807
808         modem->registered = registered;
809         modem->roaming = roaming;
810
811         if (roaming == was_roaming)
812                 return;
813
814         if (device == NULL)
815                 return;
816
817         g_hash_table_iter_init(&i, network_hash);
818
819         while (g_hash_table_iter_next(&i, NULL, &value)) {
820                 struct network_info *info = value;
821
822                 if (connman_network_get_device(info->network) == device) {
823                         connman_network_set_roaming(info->network, roaming);
824                         connman_network_update(info->network);
825                 }
826         }
827 }
828
829 static void modem_registration_removed(struct modem_data *modem)
830 {
831         modem->registered = FALSE;
832         modem->roaming = FALSE;
833 }
834
835 static void modem_registration_changed(struct modem_data *modem,
836                                         DBusMessageIter *entry)
837 {
838         DBusMessageIter iter;
839         const char *key;
840         int type;
841         connman_uint8_t strength;
842         char const *name, *status, *mcc_s;
843
844         dbus_message_iter_get_basic(entry, &key);
845
846         DBG("key %s", key);
847
848         dbus_message_iter_next(entry);
849
850         dbus_message_iter_recurse(entry, &iter);
851
852         type = dbus_message_iter_get_arg_type(&iter);
853         if (type != DBUS_TYPE_BYTE && type != DBUS_TYPE_STRING)
854                 return;
855
856         if (g_str_equal(key, "Name") && type == DBUS_TYPE_STRING) {
857                 dbus_message_iter_get_basic(&iter, &name);
858                 modem_operator_name_changed(modem, name);
859         } else if (g_str_equal(key, "Strength") && type == DBUS_TYPE_BYTE) {
860                 dbus_message_iter_get_basic(&iter, &strength);
861                 modem_strength_changed(modem, strength);
862         } else if (g_str_equal(key, "Status") && type == DBUS_TYPE_STRING) {
863                 dbus_message_iter_get_basic(&iter, &status);
864                 modem_roaming_changed(modem, status);
865         } else if (g_str_equal(key, "MobileCountryCode") &&
866                                         type == DBUS_TYPE_STRING) {
867                 int mcc;
868                 char *alpha2;
869
870                 dbus_message_iter_get_basic(&iter, &mcc_s);
871
872                 mcc = atoi(mcc_s);
873                 if (mcc > 799)
874                         return;
875
876                 alpha2 = mcc_country_codes[mcc - 200];
877                 connman_technology_set_regdom(alpha2);
878         }
879
880 }
881
882 static gboolean reg_changed(DBusConnection *connection,
883                                 DBusMessage *message, void *user_data)
884 {
885         const char *path = dbus_message_get_path(message);
886         struct modem_data *modem;
887         DBusMessageIter iter;
888
889         DBG("path %s", path);
890
891         modem = g_hash_table_lookup(modem_hash, path);
892         if (modem == NULL)
893                 return TRUE;
894
895         if (dbus_message_iter_init(message, &iter))
896                 modem_registration_changed(modem, &iter);
897
898         return TRUE;
899 }
900
901 static void check_registration_reply(DBusPendingCall *call, void *user_data)
902 {
903         char const *path = user_data;
904         struct modem_data *modem;
905         DBusMessage *reply;
906         DBusMessageIter array, dict, entry;
907
908         DBG("path %s", path);
909
910         modem = g_hash_table_lookup(modem_hash, path);
911         if (modem == NULL)
912                 return;
913
914         reply = dbus_pending_call_steal_reply(call);
915
916         if (dbus_message_iter_init(reply, &array) == FALSE)
917                 goto done;
918
919         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
920                 goto done;
921
922         dbus_message_iter_recurse(&array, &dict);
923         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
924                 dbus_message_iter_recurse(&dict, &entry);
925                 modem_registration_changed(modem, &entry);
926                 dbus_message_iter_next(&dict);
927         }
928
929 done:
930         dbus_message_unref(reply);
931
932         dbus_pending_call_unref(call);
933 }
934
935 static void check_registration(struct modem_data *modem)
936 {
937         char const *path = modem->path;
938
939         DBG("modem %p path %s", modem, path);
940
941         call_ofono(path, OFONO_REGISTRATION_INTERFACE, GET_PROPERTIES,
942                         check_registration_reply, g_strdup(path), g_free,
943                         DBUS_TYPE_INVALID);
944 }
945
946 static void modem_gprs_changed(struct modem_data *modem,
947                                         DBusMessageIter *entry)
948 {
949         DBusMessageIter iter;
950         const char *key;
951         int type;
952         dbus_bool_t value;
953
954         dbus_message_iter_get_basic(entry, &key);
955
956         DBG("key %s", key);
957
958         dbus_message_iter_next(entry);
959
960         dbus_message_iter_recurse(entry, &iter);
961
962         type = dbus_message_iter_get_arg_type(&iter);
963
964         if (type != DBUS_TYPE_BOOLEAN)
965                 return;
966
967         dbus_message_iter_get_basic(&iter, &value);
968
969         if (g_str_equal(key, "Attached") == TRUE) {
970                 DBG("Attached %d", value);
971
972                 modem->attached = value;
973
974                 if (value)
975                         modem_clear_network_errors(modem);
976         } else if (g_str_equal(key, "Powered") == TRUE) {
977                 DBG("Powered %d", value);
978
979                 modem->powered = value;
980         } else if (g_str_equal(key, "RoamingAllowed") == TRUE) {
981                 DBG("RoamingAllowed %d", value);
982
983                 modem->roaming_allowed = value;
984         }
985 }
986
987 static void check_gprs_reply(DBusPendingCall *call, void *user_data)
988 {
989         char const *path = user_data;
990         struct modem_data *modem;
991         DBusMessage *reply;
992         DBusMessageIter array, dict, entry;
993
994         DBG("path %s", path);
995
996         modem = g_hash_table_lookup(modem_hash, path);
997         if (modem == NULL)
998                 return;
999
1000         reply = dbus_pending_call_steal_reply(call);
1001
1002         if (dbus_message_iter_init(reply, &array) == FALSE)
1003                 goto done;
1004
1005         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
1006                 goto done;
1007
1008         dbus_message_iter_recurse(&array, &dict);
1009         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1010                 dbus_message_iter_recurse(&dict, &entry);
1011                 modem_gprs_changed(modem, &entry);
1012                 dbus_message_iter_next(&dict);
1013         }
1014
1015 done:
1016         dbus_message_unref(reply);
1017
1018         dbus_pending_call_unref(call);
1019
1020         check_networks(modem);
1021 }
1022
1023 static void check_gprs(struct modem_data *modem)
1024 {
1025         char const *path = modem->path;
1026
1027         DBG("modem %p path %s", modem, path);
1028
1029         call_ofono(path, OFONO_GPRS_INTERFACE, GET_PROPERTIES,
1030                         check_gprs_reply, g_strdup(path), g_free,
1031                         DBUS_TYPE_INVALID);
1032 }
1033
1034 static void add_device(const char *path, const char *imsi)
1035 {
1036         struct modem_data *modem;
1037         struct connman_device *device;
1038
1039         DBG("path %s imsi %s", path, imsi);
1040
1041         if (path == NULL)
1042                 return;
1043
1044         if (imsi == NULL)
1045                 return;
1046
1047         modem = g_hash_table_lookup(modem_hash, path);
1048         if (modem == NULL)
1049                 return;
1050
1051         if (modem->device) {
1052                 if (!g_strcmp0(imsi, connman_device_get_ident(modem->device)))
1053                         return;
1054
1055                 modem_remove_device(modem);
1056         }
1057
1058         if (strlen(imsi) == 0)
1059                 return;
1060
1061         device = connman_device_create(imsi, CONNMAN_DEVICE_TYPE_CELLULAR);
1062         if (device == NULL)
1063                 return;
1064
1065         connman_device_set_ident(device, imsi);
1066
1067         connman_device_set_string(device, "Path", path);
1068
1069         connman_device_set_data(device, modem);
1070
1071         if (connman_device_register(device) < 0) {
1072                 connman_device_unref(device);
1073                 return;
1074         }
1075
1076         modem->device = device;
1077
1078         if (modem->has_reg)
1079                 check_registration(modem);
1080
1081         if (modem->has_gprs)
1082                 check_gprs(modem);
1083 }
1084
1085 static void sim_properties_reply(DBusPendingCall *call, void *user_data)
1086 {
1087         const char *path = user_data;
1088         const char *imsi = NULL;
1089         DBusMessage *reply;
1090         DBusMessageIter array, dict;
1091
1092         DBG("path %s", path);
1093
1094         reply = dbus_pending_call_steal_reply(call);
1095
1096         if (dbus_message_iter_init(reply, &array) == FALSE)
1097                 goto done;
1098
1099         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
1100                 goto done;
1101
1102         dbus_message_iter_recurse(&array, &dict);
1103
1104         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1105                 DBusMessageIter entry, value;
1106                 const char *key;
1107
1108                 dbus_message_iter_recurse(&dict, &entry);
1109                 dbus_message_iter_get_basic(&entry, &key);
1110
1111                 dbus_message_iter_next(&entry);
1112                 dbus_message_iter_recurse(&entry, &value);
1113
1114                 if (g_str_equal(key, "SubscriberIdentity")) {
1115                         dbus_message_iter_get_basic(&value, &imsi);
1116                         add_device(path, imsi);
1117                 }
1118
1119                 dbus_message_iter_next(&dict);
1120         }
1121
1122 done:
1123         dbus_message_unref(reply);
1124
1125         dbus_pending_call_unref(call);
1126 }
1127
1128 static void get_imsi(const char *path)
1129 {
1130         DBG("path %s", path);
1131
1132         call_ofono(path, OFONO_SIM_INTERFACE, GET_PROPERTIES,
1133                         sim_properties_reply, g_strdup(path), g_free,
1134                         DBUS_TYPE_INVALID);
1135 }
1136
1137 static int gprs_change_powered(const char *path, dbus_bool_t powered)
1138 {
1139         DBG("path %s powered %d", path, powered);
1140
1141         return set_property(path, OFONO_GPRS_INTERFACE, "Powered",
1142                                 DBUS_TYPE_BOOLEAN, &powered,
1143                                 NULL, NULL, NULL);
1144 }
1145
1146 static int modem_change_powered(const char *path, dbus_bool_t powered)
1147 {
1148         DBG("path %s powered %d", path, powered);
1149
1150         return set_property(path, OFONO_MODEM_INTERFACE, "Powered",
1151                                 DBUS_TYPE_BOOLEAN, &powered,
1152                                 NULL, NULL, NULL);
1153 }
1154
1155
1156 static gboolean modem_has_interface(DBusMessageIter *array,
1157                                         char const *interface)
1158 {
1159         DBusMessageIter entry;
1160
1161         dbus_message_iter_recurse(array, &entry);
1162
1163         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
1164                 const char *element;
1165
1166                 dbus_message_iter_get_basic(&entry, &element);
1167
1168                 if (g_strcmp0(interface, element) == 0)
1169                         return TRUE;
1170
1171                 dbus_message_iter_next(&entry);
1172         }
1173
1174         return FALSE;
1175 }
1176
1177 static gboolean modem_has_sim(DBusMessageIter *array)
1178 {
1179         return modem_has_interface(array, OFONO_SIM_INTERFACE);
1180 }
1181
1182 static gboolean modem_has_reg(DBusMessageIter *array)
1183 {
1184         return modem_has_interface(array, OFONO_REGISTRATION_INTERFACE);
1185 }
1186
1187 static gboolean modem_has_gprs(DBusMessageIter *array)
1188 {
1189         return modem_has_interface(array, OFONO_GPRS_INTERFACE);
1190 }
1191
1192 static void add_modem(const char *path, DBusMessageIter *prop)
1193 {
1194         struct modem_data *modem;
1195         dbus_bool_t powered = FALSE;
1196         dbus_bool_t online = FALSE;
1197         dbus_bool_t has_online = FALSE;
1198         dbus_bool_t locked = FALSE;
1199         gboolean has_sim = FALSE;
1200         gboolean has_reg = FALSE;
1201         gboolean has_gprs = FALSE;
1202
1203         modem = g_hash_table_lookup(modem_hash, path);
1204
1205         if (modem != NULL)
1206                 return;
1207
1208         modem = g_try_new0(struct modem_data, 1);
1209         if (modem == NULL)
1210                 return;
1211
1212         modem->path = g_strdup(path);
1213         modem->device = NULL;
1214         modem->available = TRUE;
1215
1216         g_hash_table_insert(modem_hash, g_strdup(path), modem);
1217
1218         while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
1219                 DBusMessageIter entry, value;
1220                 const char *key;
1221
1222                 dbus_message_iter_recurse(prop, &entry);
1223                 dbus_message_iter_get_basic(&entry, &key);
1224
1225                 dbus_message_iter_next(&entry);
1226                 dbus_message_iter_recurse(&entry, &value);
1227
1228                 if (g_str_equal(key, "Powered") == TRUE)
1229                         dbus_message_iter_get_basic(&value, &powered);
1230                 else if (g_str_equal(key, "Lockdown") == TRUE)
1231                         dbus_message_iter_get_basic(&value, &locked);
1232                 else if (g_str_equal(key, "Online") == TRUE) {
1233                         has_online = TRUE;
1234                         dbus_message_iter_get_basic(&value, &online);
1235                 } else if (g_str_equal(key, "Interfaces") == TRUE) {
1236                         has_sim = modem_has_sim(&value);
1237                         has_reg = modem_has_reg(&value);
1238                         has_gprs = modem_has_gprs(&value);
1239                 }
1240
1241                 dbus_message_iter_next(prop);
1242         }
1243
1244         if (locked)
1245                 return;
1246
1247         if (!powered)
1248                 modem_change_powered(path, TRUE);
1249
1250         modem->has_sim = has_sim;
1251         modem->has_reg = has_reg;
1252         modem->has_gprs = has_gprs;
1253
1254         update_modem_online(modem, online);
1255
1256         if (has_sim)
1257                 get_imsi(path);
1258 }
1259
1260 static void manager_modems_reply(DBusPendingCall *call, void *user_data)
1261 {
1262         DBusMessage *reply;
1263         DBusError error;
1264         DBusMessageIter array, dict;
1265
1266         DBG("");
1267
1268         reply = dbus_pending_call_steal_reply(call);
1269
1270         if (dbus_message_has_signature(reply, "a(oa{sv})") == FALSE)
1271                 goto done;
1272
1273         dbus_error_init(&error);
1274
1275         if (dbus_set_error_from_message(&error, reply)) {
1276                 connman_error("ModemManager.GetModems() %s %s",
1277                                 error.name, error.message);
1278                 dbus_error_free(&error);
1279                 goto done;
1280         }
1281
1282         if (dbus_message_iter_init(reply, &array) == FALSE)
1283                 goto done;
1284
1285         dbus_message_iter_recurse(&array, &dict);
1286
1287         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
1288                 DBusMessageIter value, properties;
1289                 const char *modem_path;
1290
1291                 dbus_message_iter_recurse(&dict, &value);
1292                 dbus_message_iter_get_basic(&value, &modem_path);
1293
1294                 dbus_message_iter_next(&value);
1295                 dbus_message_iter_recurse(&value, &properties);
1296
1297                 /* Add modem */
1298                 add_modem(modem_path, &properties);
1299
1300                 dbus_message_iter_next(&dict);
1301         }
1302
1303 done:
1304         dbus_message_unref(reply);
1305
1306         dbus_pending_call_unref(call);
1307 }
1308
1309 static void ofono_connect(DBusConnection *connection, void *user_data)
1310 {
1311         DBG("connection %p", connection);
1312
1313         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
1314                                                 g_free, remove_modem);
1315
1316         network_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
1317                                                 NULL, remove_network);
1318
1319         call_ofono("/", OFONO_MANAGER_INTERFACE, GET_MODEMS,
1320                         manager_modems_reply, NULL, NULL,
1321                         DBUS_TYPE_INVALID);
1322 }
1323
1324 static void ofono_disconnect(DBusConnection *connection, void *user_data)
1325 {
1326         DBG("connection %p", connection);
1327
1328         if (modem_hash == NULL)
1329                 return;
1330
1331         g_hash_table_destroy(modem_hash);
1332
1333         modem_hash = NULL;
1334 }
1335
1336 static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
1337                                 void *user_data)
1338 {
1339         const char *path = dbus_message_get_path(message);
1340         struct modem_data *modem;
1341         DBusMessageIter iter, value;
1342         const char *key;
1343
1344         DBG("path %s", path);
1345
1346         modem = g_hash_table_lookup(modem_hash, path);
1347         if (modem == NULL)
1348                 return TRUE;
1349
1350         if (dbus_message_iter_init(message, &iter) == FALSE)
1351                 return TRUE;
1352
1353         dbus_message_iter_get_basic(&iter, &key);
1354
1355         dbus_message_iter_next(&iter);
1356         dbus_message_iter_recurse(&iter, &value);
1357
1358         if (g_str_equal(key, "Powered") == TRUE) {
1359                 dbus_bool_t powered;
1360
1361                 dbus_message_iter_get_basic(&value, &powered);
1362                 if (powered == TRUE)
1363                         return TRUE;
1364
1365                 modem->has_sim = FALSE;
1366                 modem->has_reg = FALSE;
1367                 modem->has_gprs = FALSE;
1368
1369                 modem_remove_device(modem);
1370         } else if (g_str_equal(key, "Online") == TRUE) {
1371                 dbus_bool_t online;
1372
1373                 dbus_message_iter_get_basic(&value, &online);
1374
1375                 update_modem_online(modem, online);
1376         } else if (g_str_equal(key, "Lockdown") == TRUE) {
1377                 dbus_bool_t locked;
1378
1379                 dbus_message_iter_get_basic(&value, &locked);
1380
1381                 if (!locked)
1382                         modem_change_powered(path, TRUE);
1383
1384         } else if (g_str_equal(key, "Interfaces") == TRUE) {
1385                 gboolean has_sim = modem_has_sim(&value);
1386                 gboolean has_reg = modem_has_reg(&value);
1387                 gboolean had_reg = modem->has_reg;
1388                 gboolean has_gprs = modem_has_gprs(&value);
1389                 gboolean had_gprs = modem->has_gprs;
1390
1391                 modem->has_sim = has_sim;
1392                 modem->has_reg = has_reg;
1393                 modem->has_gprs = has_gprs;
1394
1395                 if (modem->device == NULL) {
1396                         if (has_sim)
1397                                 get_imsi(modem->path);
1398                 } else if (!has_sim) {
1399                         modem_remove_device(modem);
1400                 } else {
1401                         if (has_reg && !had_reg)
1402                                 check_registration(modem);
1403                         else if (had_reg && !has_reg)
1404                                 modem_registration_removed(modem);
1405
1406                         if (has_gprs && !had_gprs) {
1407                                 gprs_change_powered(modem->path, TRUE);
1408                                 check_gprs(modem);
1409                         }
1410                 }
1411         }
1412
1413         return TRUE;
1414 }
1415
1416 static gboolean sim_changed(DBusConnection *connection, DBusMessage *message,
1417                                 void *user_data)
1418 {
1419         const char *path = dbus_message_get_path(message);
1420         struct modem_data *modem;
1421         DBusMessageIter iter, value;
1422         const char *key;
1423
1424         DBG("path %s", path);
1425
1426         modem = g_hash_table_lookup(modem_hash, path);
1427         if (modem == NULL)
1428                 return TRUE;
1429
1430         if (dbus_message_iter_init(message, &iter) == FALSE)
1431                 return TRUE;
1432
1433         dbus_message_iter_get_basic(&iter, &key);
1434
1435         dbus_message_iter_next(&iter);
1436         dbus_message_iter_recurse(&iter, &value);
1437
1438         if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
1439                 char *imsi;
1440
1441                 dbus_message_iter_get_basic(&value, &imsi);
1442
1443                 add_device(path, imsi);
1444         } else if (g_str_equal(key, "Present") == TRUE) {
1445                 dbus_bool_t present;
1446
1447                 dbus_message_iter_get_basic(&value, &present);
1448
1449                 if (present)
1450                         return TRUE;
1451
1452                 if (modem->device != NULL)
1453                         modem_remove_device(modem);
1454
1455                 modem->has_gprs = FALSE;
1456                 modem->has_reg = FALSE;
1457         }
1458
1459         return TRUE;
1460 }
1461
1462 static gboolean gprs_changed(DBusConnection *connection, DBusMessage *message,
1463                                 void *user_data)
1464 {
1465         const char *path = dbus_message_get_path(message);
1466         struct modem_data *modem;
1467         DBusMessageIter iter;
1468
1469         DBG("path %s", path);
1470
1471         modem = g_hash_table_lookup(modem_hash, path);
1472         if (modem == NULL)
1473                 return TRUE;
1474
1475         if (dbus_message_iter_init(message, &iter))
1476                 modem_gprs_changed(modem, &iter);
1477
1478         return TRUE;
1479 }
1480
1481 static gboolean context_added(DBusConnection *connection,
1482                                 DBusMessage *message, void *user_data)
1483 {
1484         const char *path = dbus_message_get_path(message);
1485         const char *network_path;
1486         struct modem_data *modem;
1487         DBusMessageIter iter, properties;
1488
1489         DBG("path %s", path);
1490
1491         modem = g_hash_table_lookup(modem_hash, path);
1492         if (modem == NULL || modem->device == NULL)
1493                 return TRUE;
1494
1495         if (dbus_message_iter_init(message, &iter) == FALSE)
1496                 return TRUE;
1497
1498         dbus_message_iter_get_basic(&iter, &network_path);
1499
1500         dbus_message_iter_next(&iter);
1501         dbus_message_iter_recurse(&iter, &properties);
1502
1503         add_network(modem->device, network_path, &properties);
1504
1505         return TRUE;
1506 }
1507
1508 static gboolean context_removed(DBusConnection *connection,
1509                                 DBusMessage *message, void *user_data)
1510 {
1511         const char *path = dbus_message_get_path(message);
1512         const char *network_path, *identifier;
1513         struct modem_data *modem;
1514         struct network_info *info;
1515         DBusMessageIter iter;
1516
1517         DBG("path %s", path);
1518
1519         modem = g_hash_table_lookup(modem_hash, path);
1520         if (modem == NULL || modem->device == NULL)
1521                 return TRUE;
1522
1523         if (dbus_message_iter_init(message, &iter) == FALSE)
1524                 return TRUE;
1525
1526         dbus_message_iter_get_basic(&iter, &network_path);
1527
1528         info = g_hash_table_lookup(network_hash, network_path);
1529         if (info == NULL)
1530                 return TRUE;
1531
1532         identifier = connman_network_get_identifier(info->network);
1533         connman_device_remove_network(modem->device, identifier);
1534
1535         return TRUE;
1536 }
1537
1538 static gboolean modem_added(DBusConnection *connection,
1539                                 DBusMessage *message, void *user_data)
1540 {
1541         DBusMessageIter iter, properties;
1542         const char *modem_path;
1543
1544         DBG("");
1545
1546         if (dbus_message_iter_init(message, &iter) == FALSE)
1547                 return TRUE;
1548
1549         dbus_message_iter_get_basic(&iter, &modem_path);
1550
1551         dbus_message_iter_next(&iter);
1552         dbus_message_iter_recurse(&iter, &properties);
1553
1554         add_modem(modem_path, &properties);
1555
1556         return TRUE;
1557 }
1558
1559 static gboolean modem_removed(DBusConnection *connection,
1560                                 DBusMessage *message, void *user_data)
1561 {
1562         DBusMessageIter iter;
1563         const char *modem_path;
1564
1565         DBG("");
1566
1567         if (dbus_message_iter_init(message, &iter) == FALSE)
1568                 return TRUE;
1569
1570         dbus_message_iter_get_basic(&iter, &modem_path);
1571
1572         g_hash_table_remove(modem_hash, modem_path);
1573
1574         return TRUE;
1575 }
1576
1577
1578 static void get_dns(DBusMessageIter *array, struct network_info *info)
1579 {
1580         DBusMessageIter entry;
1581         gchar *nameservers = NULL, *nameservers_old = NULL;
1582
1583         DBG("");
1584
1585
1586         dbus_message_iter_recurse(array, &entry);
1587
1588         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
1589                 const char *dns;
1590
1591                 dbus_message_iter_get_basic(&entry, &dns);
1592
1593                 DBG("dns %s", dns);
1594
1595                 if (nameservers == NULL) {
1596
1597                         nameservers = g_strdup(dns);
1598                 } else {
1599
1600                         nameservers_old = nameservers;
1601                         nameservers = g_strdup_printf("%s %s",
1602                                                 nameservers_old, dns);
1603                         g_free(nameservers_old);
1604                 }
1605
1606                 dbus_message_iter_next(&entry);
1607         }
1608
1609         connman_network_set_nameservers(info->network, nameservers);
1610
1611         g_free(nameservers);
1612 }
1613
1614 static void update_settings(DBusMessageIter *array,
1615                                 struct network_info *info)
1616 {
1617         DBusMessageIter dict;
1618         char *address = NULL, *netmask = NULL, *gateway = NULL;
1619         const char *interface = NULL;
1620
1621         DBG("network %p", info->network);
1622
1623         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
1624                 return;
1625
1626         dbus_message_iter_recurse(array, &dict);
1627
1628         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1629                 DBusMessageIter entry, value;
1630                 const char *key, *val;
1631
1632                 dbus_message_iter_recurse(&dict, &entry);
1633                 dbus_message_iter_get_basic(&entry, &key);
1634
1635                 DBG("key %s", key);
1636
1637                 dbus_message_iter_next(&entry);
1638                 dbus_message_iter_recurse(&entry, &value);
1639
1640                 if (g_str_equal(key, "Interface") == TRUE) {
1641                         int index;
1642
1643                         dbus_message_iter_get_basic(&value, &interface);
1644
1645                         DBG("interface %s", interface);
1646
1647                         index = connman_inet_ifindex(interface);
1648                         if (index >= 0) {
1649                                 connman_network_set_index(info->network, index);
1650                         } else {
1651                                 connman_error("Can not find interface %s",
1652                                                                 interface);
1653                                 break;
1654                         }
1655                 } else if (g_str_equal(key, "Method") == TRUE) {
1656                         const char *method;
1657
1658                         dbus_message_iter_get_basic(&value, &method);
1659
1660                         if (g_strcmp0(method, "static") == 0) {
1661
1662                                 info->method = CONNMAN_IPCONFIG_METHOD_FIXED;
1663                         } else if (g_strcmp0(method, "dhcp") == 0) {
1664
1665                                 info->method = CONNMAN_IPCONFIG_METHOD_DHCP;
1666                                 break;
1667                         }
1668                 } else if (g_str_equal(key, "Address") == TRUE) {
1669                         dbus_message_iter_get_basic(&value, &val);
1670
1671                         address = g_strdup(val);
1672
1673                         DBG("address %s", address);
1674                 } else if (g_str_equal(key, "Netmask") == TRUE) {
1675                         dbus_message_iter_get_basic(&value, &val);
1676
1677                         netmask = g_strdup(val);
1678
1679                         DBG("netmask %s", netmask);
1680                 } else if (g_str_equal(key, "DomainNameServers") == TRUE) {
1681
1682                         get_dns(&value, info);
1683                 } else if (g_str_equal(key, "Gateway") == TRUE) {
1684                         dbus_message_iter_get_basic(&value, &val);
1685
1686                         gateway = g_strdup(val);
1687
1688                         DBG("gateway %s", gateway);
1689                 }
1690
1691                 dbus_message_iter_next(&dict);
1692         }
1693
1694
1695         if (info->method == CONNMAN_IPCONFIG_METHOD_FIXED) {
1696                 connman_ipaddress_set_ipv4(&info->ipaddress, address,
1697                                                 netmask, gateway);
1698         }
1699
1700         /* deactive, oFono send NULL inteface before deactive signal */
1701         if (interface == NULL)
1702                 connman_network_set_index(info->network, -1);
1703
1704         g_free(address);
1705         g_free(netmask);
1706         g_free(gateway);
1707 }
1708
1709 static gboolean context_changed(DBusConnection *connection,
1710                                         DBusMessage *message, void *user_data)
1711 {
1712         const char *path = dbus_message_get_path(message);
1713         struct network_info *info;
1714         DBusMessageIter iter, value;
1715         const char *key;
1716
1717         DBG("path %s", path);
1718
1719         info = g_hash_table_lookup(network_hash, path);
1720         if (info == NULL)
1721                 return TRUE;
1722
1723         if (!pending_network_is_available(info->network)) {
1724                 remove_network(info->network);
1725                 return TRUE;
1726         }
1727
1728         if (dbus_message_iter_init(message, &iter) == FALSE)
1729                 return TRUE;
1730
1731         dbus_message_iter_get_basic(&iter, &key);
1732
1733         dbus_message_iter_next(&iter);
1734         dbus_message_iter_recurse(&iter, &value);
1735
1736         DBG("key %s", key);
1737
1738         if (g_str_equal(key, "Settings") == TRUE)
1739                 update_settings(&value, info);
1740         else if (g_str_equal(key, "Active") == TRUE) {
1741                 dbus_bool_t active;
1742
1743                 dbus_message_iter_get_basic(&value, &active);
1744
1745                 if (active == FALSE)
1746                         set_connected(info, active);
1747
1748                 /* Connect only if requested to do so */
1749                 if (active == TRUE &&
1750                         connman_network_get_connecting(info->network) == TRUE)
1751                         set_connected(info, active);
1752         }
1753
1754         return TRUE;
1755 }
1756
1757 static guint watch;
1758 static guint reg_watch;
1759 static guint sim_watch;
1760 static guint gprs_watch;
1761 static guint context_added_watch;
1762 static guint context_removed_watch;
1763 static guint modem_watch;
1764 static guint modem_added_watch;
1765 static guint modem_removed_watch;
1766 static guint context_watch;
1767
1768 static int ofono_init(void)
1769 {
1770         int err;
1771
1772         connection = connman_dbus_get_connection();
1773         if (connection == NULL)
1774                 return -EIO;
1775
1776         watch = g_dbus_add_service_watch(connection, OFONO_SERVICE,
1777                         ofono_connect, ofono_disconnect, NULL, NULL);
1778
1779         reg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1780                                                 OFONO_REGISTRATION_INTERFACE,
1781                                                 PROPERTY_CHANGED,
1782                                                 reg_changed,
1783                                                 NULL, NULL);
1784
1785         gprs_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1786                                                 OFONO_GPRS_INTERFACE,
1787                                                 PROPERTY_CHANGED,
1788                                                 gprs_changed,
1789                                                 NULL, NULL);
1790
1791         context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1792                                                 OFONO_GPRS_INTERFACE,
1793                                                 CONTEXT_ADDED,
1794                                                 context_added,
1795                                                 NULL, NULL);
1796
1797         context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1798                                                 OFONO_GPRS_INTERFACE,
1799                                                 CONTEXT_REMOVED,
1800                                                 context_removed,
1801                                                 NULL, NULL);
1802
1803         modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1804                                                 OFONO_MODEM_INTERFACE,
1805                                                 PROPERTY_CHANGED,
1806                                                 modem_changed,
1807                                                 NULL, NULL);
1808
1809         sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1810                                                 OFONO_SIM_INTERFACE,
1811                                                 PROPERTY_CHANGED,
1812                                                 sim_changed,
1813                                                 NULL, NULL);
1814
1815         modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1816                                                 OFONO_MANAGER_INTERFACE,
1817                                                 MODEM_ADDED,
1818                                                 modem_added,
1819                                                 NULL, NULL);
1820
1821         modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1822                                                 OFONO_MANAGER_INTERFACE,
1823                                                 MODEM_REMOVED,
1824                                                 modem_removed,
1825                                                 NULL, NULL);
1826
1827         context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1828                                                 OFONO_CONTEXT_INTERFACE,
1829                                                 PROPERTY_CHANGED,
1830                                                 context_changed,
1831                                                 NULL, NULL);
1832
1833         if (watch == 0 || gprs_watch == 0 || context_added_watch == 0 ||
1834                         context_removed_watch == 0 || modem_watch == 0 ||
1835                         reg_watch == 0 || sim_watch == 0 ||
1836                         modem_added_watch == 0 || modem_removed_watch == 0 ||
1837                                 context_watch == 0) {
1838                 err = -EIO;
1839                 goto remove;
1840         }
1841
1842         err = connman_network_driver_register(&network_driver);
1843         if (err < 0)
1844                 goto remove;
1845
1846         err = connman_device_driver_register(&modem_driver);
1847         if (err < 0) {
1848                 connman_network_driver_unregister(&network_driver);
1849                 goto remove;
1850         }
1851
1852         return 0;
1853
1854 remove:
1855         g_dbus_remove_watch(connection, watch);
1856         g_dbus_remove_watch(connection, sim_watch);
1857         g_dbus_remove_watch(connection, reg_watch);
1858         g_dbus_remove_watch(connection, gprs_watch);
1859         g_dbus_remove_watch(connection, context_added_watch);
1860         g_dbus_remove_watch(connection, context_removed_watch);
1861         g_dbus_remove_watch(connection, modem_watch);
1862         g_dbus_remove_watch(connection, modem_added_watch);
1863         g_dbus_remove_watch(connection, modem_removed_watch);
1864         g_dbus_remove_watch(connection, context_watch);
1865
1866         dbus_connection_unref(connection);
1867
1868         return err;
1869 }
1870
1871 static void ofono_exit(void)
1872 {
1873         g_dbus_remove_watch(connection, watch);
1874         g_dbus_remove_watch(connection, sim_watch);
1875         g_dbus_remove_watch(connection, reg_watch);
1876         g_dbus_remove_watch(connection, gprs_watch);
1877         g_dbus_remove_watch(connection, context_added_watch);
1878         g_dbus_remove_watch(connection, context_removed_watch);
1879         g_dbus_remove_watch(connection, modem_watch);
1880         g_dbus_remove_watch(connection, modem_added_watch);
1881         g_dbus_remove_watch(connection, modem_removed_watch);
1882         g_dbus_remove_watch(connection, context_watch);
1883
1884         ofono_disconnect(connection, NULL);
1885
1886         connman_device_driver_unregister(&modem_driver);
1887         connman_network_driver_unregister(&network_driver);
1888
1889         dbus_connection_unref(connection);
1890 }
1891
1892 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
1893                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)