ofono: Add connect()/disconnnect network
[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 #include <stdint.h>
33
34 #define CONNMAN_API_SUBJECT_TO_CHANGE
35 #include <connman/plugin.h>
36 #include <connman/device.h>
37 #include <connman/network.h>
38 #include <connman/inet.h>
39 #include <connman/dbus.h>
40 #include <connman/log.h>
41
42 #define uninitialized_var(x) x = x
43
44 #define OFONO_SERVICE                   "org.ofono"
45
46 #define OFONO_MANAGER_INTERFACE         OFONO_SERVICE ".Manager"
47 #define OFONO_MODEM_INTERFACE           OFONO_SERVICE ".Modem"
48 #define OFONO_SIM_INTERFACE             OFONO_SERVICE ".SimManager"
49 #define OFONO_NETREG_INTERFACE          OFONO_SERVICE ".NetworkRegistration"
50 #define OFONO_CM_INTERFACE              OFONO_SERVICE ".ConnectionManager"
51 #define OFONO_CONTEXT_INTERFACE         OFONO_SERVICE ".ConnectionContext"
52
53 #define MODEM_ADDED                     "ModemAdded"
54 #define MODEM_REMOVED                   "ModemRemoved"
55 #define PROPERTY_CHANGED                "PropertyChanged"
56 #define CONTEXT_ADDED                   "ContextAdded"
57 #define CONTEXT_REMOVED                 "ContextRemoved"
58
59 #define GET_PROPERTIES                  "GetProperties"
60 #define SET_PROPERTY                    "SetProperty"
61 #define GET_MODEMS                      "GetModems"
62 #define GET_CONTEXTS                    "GetContexts"
63
64 #define TIMEOUT 40000
65
66 enum ofono_api {
67         OFONO_API_SIM =         0x1,
68         OFONO_API_NETREG =      0x2,
69         OFONO_API_CM =          0x4,
70 };
71
72 static DBusConnection *connection;
73
74 static GHashTable *modem_hash;
75 static GHashTable *context_hash;
76
77 struct network_context {
78         char *path;
79         int index;
80
81         enum connman_ipconfig_method ipv4_method;
82         struct connman_ipaddress *ipv4_address;
83         char *ipv4_nameservers;
84
85         enum connman_ipconfig_method ipv6_method;
86         struct connman_ipaddress *ipv6_address;
87         char *ipv6_nameservers;
88 };
89
90 struct modem_data {
91         char *path;
92
93         struct connman_device *device;
94         struct connman_network *network;
95
96         struct network_context *context;
97
98         /* Modem Interface */
99         char *serial;
100         connman_bool_t powered;
101         connman_bool_t online;
102         uint8_t interfaces;
103
104         connman_bool_t set_powered;
105         connman_bool_t set_online;
106
107         /* ConnectionManager Interface */
108         connman_bool_t attached;
109         connman_bool_t cm_powered;
110
111         connman_bool_t set_cm_powered;
112
113         /* ConnectionContext Interface */
114         connman_bool_t active;
115         connman_bool_t set_active;
116
117         /* SimManager Interface */
118         char *imsi;
119
120         /* Netreg Interface */
121         char *name;
122         uint8_t strength;
123
124         /* pending calls */
125         DBusPendingCall *call_set_property;
126         DBusPendingCall *call_get_properties;
127         DBusPendingCall *call_get_contexts;
128 };
129
130 static char *get_ident(const char *path)
131 {
132         char *pos;
133
134         if (*path != '/')
135                 return NULL;
136
137         pos = strrchr(path, '/');
138         if (pos == NULL)
139                 return NULL;
140
141         return pos + 1;
142 }
143
144 static struct network_context *network_context_alloc(const char *path)
145 {
146         struct network_context *context;
147
148         context = g_try_new0(struct network_context, 1);
149         if (context == NULL)
150                 return NULL;
151
152         context->path = g_strdup(path);
153         context->index = -1;
154
155         context->ipv4_method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
156         context->ipv4_address = NULL;
157         context->ipv4_nameservers = NULL;
158
159         context->ipv6_method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
160         context->ipv6_address = NULL;
161         context->ipv6_nameservers = NULL;
162
163         return context;
164 }
165
166 static void network_context_free(struct network_context *context)
167 {
168         g_free(context->path);
169
170         connman_ipaddress_free(context->ipv4_address);
171         g_free(context->ipv4_nameservers);
172
173         connman_ipaddress_free(context->ipv6_address);
174         g_free(context->ipv6_nameservers);
175
176         free(context);
177 }
178
179 static void set_connected(struct modem_data *modem)
180 {
181         connman_bool_t setip = FALSE;
182
183         DBG("%s", modem->path);
184
185         connman_network_set_index(modem->network, modem->context->index);
186
187         switch (modem->context->ipv4_method) {
188         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
189         case CONNMAN_IPCONFIG_METHOD_OFF:
190         case CONNMAN_IPCONFIG_METHOD_MANUAL:
191         case CONNMAN_IPCONFIG_METHOD_AUTO:
192                 break;
193
194         case CONNMAN_IPCONFIG_METHOD_FIXED:
195                 connman_network_set_ipv4_method(modem->network,
196                                                 modem->context->ipv4_method);
197                 connman_network_set_ipaddress(modem->network,
198                                                 modem->context->ipv4_address);
199                 connman_network_set_nameservers(modem->network,
200                                         modem->context->ipv4_nameservers);
201                 setip = TRUE;
202                 break;
203
204         case CONNMAN_IPCONFIG_METHOD_DHCP:
205                 connman_network_set_ipv4_method(modem->network,
206                                                 modem->context->ipv4_method);
207                 setip = TRUE;
208                 break;
209         }
210
211         switch (modem->context->ipv6_method) {
212         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
213         case CONNMAN_IPCONFIG_METHOD_OFF:
214         case CONNMAN_IPCONFIG_METHOD_MANUAL:
215         case CONNMAN_IPCONFIG_METHOD_DHCP:
216         case CONNMAN_IPCONFIG_METHOD_AUTO:
217                 break;
218
219         case CONNMAN_IPCONFIG_METHOD_FIXED:
220                 connman_network_set_ipv6_method(modem->network,
221                                                         modem->context->ipv6_method);
222                 connman_network_set_ipaddress(modem->network,
223                                                         modem->context->ipv6_address);
224                 setip = TRUE;
225                 break;
226         }
227
228         if (setip == TRUE)
229                 connman_network_set_connected(modem->network, TRUE);
230 }
231
232 static void set_disconnected(struct modem_data *modem)
233 {
234         DBG("%s", modem->path);
235
236         connman_network_set_connected(modem->network, FALSE);
237 }
238
239 typedef void (*set_property_cb)(struct modem_data *data,
240                                 connman_bool_t success);
241 typedef void (*get_properties_cb)(struct modem_data *data,
242                                 DBusMessageIter *dict);
243
244 struct property_info {
245         struct modem_data *modem;
246         const char *path;
247         const char *interface;
248         const char *property;
249         set_property_cb set_property_cb;
250         get_properties_cb get_properties_cb;
251 };
252
253 static void set_property_reply(DBusPendingCall *call, void *user_data)
254 {
255         struct property_info *info = user_data;
256         DBusMessage *reply;
257         DBusError error;
258         connman_bool_t success = TRUE;
259
260         DBG("%s path %s %s.%s", info->modem->path,
261                 info->path, info->interface, info->property);
262
263         info->modem->call_set_property = NULL;
264
265         dbus_error_init(&error);
266
267         reply = dbus_pending_call_steal_reply(call);
268
269         if (dbus_set_error_from_message(&error, reply)) {
270                 connman_error("Failed to change property: %s %s.%s: %s %s",
271                                 info->path, info->interface, info->property,
272                                 error.name, error.message);
273                 dbus_error_free(&error);
274                 success = FALSE;
275         }
276
277         if (info->set_property_cb != NULL)
278                 (*info->set_property_cb)(info->modem, success);
279
280         dbus_message_unref(reply);
281
282         dbus_pending_call_unref(call);
283 }
284
285 static int set_property(struct modem_data *modem,
286                         const char *path, const char *interface,
287                         const char *property, int type, void *value,
288                         set_property_cb notify)
289 {
290         DBusMessage *message;
291         DBusMessageIter iter;
292         struct property_info *info;
293
294         DBG("%s path %s %s.%s", modem->path, path, interface, property);
295
296         if (modem->call_set_property != NULL) {
297                 connman_error("Pending SetProperty");
298                 return -EBUSY;
299         }
300
301         message = dbus_message_new_method_call(OFONO_SERVICE, path,
302                                         interface, SET_PROPERTY);
303         if (message == NULL)
304                 return -ENOMEM;
305
306         dbus_message_iter_init_append(message, &iter);
307         connman_dbus_property_append_basic(&iter, property, type, value);
308
309         if (dbus_connection_send_with_reply(connection, message,
310                         &modem->call_set_property, TIMEOUT) == FALSE) {
311                 connman_error("Failed to change property: %s %s.%s",
312                                 path, interface, property);
313                 dbus_message_unref(message);
314                 return -EINVAL;
315         }
316
317         if (modem->call_set_property == NULL) {
318                 connman_error("D-Bus connection not available");
319                 dbus_message_unref(message);
320                 return -EINVAL;
321         }
322
323         info = g_try_new0(struct property_info, 1);
324         if (info == NULL) {
325                 dbus_message_unref(message);
326                 return -ENOMEM;
327         }
328
329         info->modem = modem;
330         info->path = path;
331         info->interface = interface;
332         info->property = property;
333         info->set_property_cb = notify;
334
335         dbus_pending_call_set_notify(modem->call_set_property,
336                                         set_property_reply, info, g_free);
337
338         dbus_message_unref(message);
339
340         return -EINPROGRESS;
341 }
342
343 static void get_properties_reply(DBusPendingCall *call, void *user_data)
344 {
345         struct property_info *info = user_data;
346         DBusMessageIter array, dict;
347         DBusMessage *reply;
348         DBusError error;
349
350         DBG("%s path %s %s", info->modem->path, info->path, info->interface);
351
352         info->modem->call_get_properties = NULL;
353
354         dbus_error_init(&error);
355
356         reply = dbus_pending_call_steal_reply(call);
357
358         if (dbus_set_error_from_message(&error, reply)) {
359                 connman_error("Failed to get properties: %s %s: %s %s",
360                                 info->path, info->interface,
361                                 error.name, error.message);
362                 dbus_error_free(&error);
363
364                 goto done;
365         }
366
367         if (dbus_message_iter_init(reply, &array) == FALSE)
368                 goto done;
369
370         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
371                 goto done;
372
373         dbus_message_iter_recurse(&array, &dict);
374
375         if (info->get_properties_cb != NULL)
376                 (*info->get_properties_cb)(info->modem, &dict);
377
378 done:
379
380         dbus_message_unref(reply);
381
382         dbus_pending_call_unref(call);
383 }
384
385 static int get_properties(const char *path, const char *interface,
386                                 get_properties_cb notify,
387                                 struct modem_data *modem)
388 {
389         DBusMessage *message;
390         struct property_info *info;
391
392         DBG("%s path %s %s", modem->path, path, interface);
393
394         if (modem->call_get_properties != NULL) {
395                 connman_error("Pending GetProperties");
396                 return -EBUSY;
397         }
398
399         message = dbus_message_new_method_call(OFONO_SERVICE, path,
400                                         interface, GET_PROPERTIES);
401         if (message == NULL)
402                 return -ENOMEM;
403
404         if (dbus_connection_send_with_reply(connection, message,
405                         &modem->call_get_properties, TIMEOUT) == FALSE) {
406                 connman_error("Failed to call %s.GetProperties()", interface);
407                 dbus_message_unref(message);
408                 return -EINVAL;
409         }
410
411         if (modem->call_get_properties == NULL) {
412                 connman_error("D-Bus connection not available");
413                 dbus_message_unref(message);
414                 return -EINVAL;
415         }
416
417         info = g_try_new0(struct property_info, 1);
418         if (info == NULL) {
419                 dbus_message_unref(message);
420                 return -ENOMEM;
421         }
422
423         info->modem = modem;
424         info->path = path;
425         info->interface = interface;
426         info->get_properties_cb = notify;
427
428         dbus_pending_call_set_notify(modem->call_get_properties,
429                                         get_properties_reply, info, g_free);
430
431         dbus_message_unref(message);
432
433         return -EINPROGRESS;
434 }
435
436 static void context_set_active_reply(struct modem_data *modem,
437                                         connman_bool_t success)
438 {
439         DBG("%s", modem->path);
440
441         if (success == TRUE) {
442                 /*
443                  * Don't handle do anything on success here. oFono will send
444                  * the change via PropertyChanged singal.
445                  */
446                 return;
447         }
448
449         /*
450          * Active = True might fail due a timeout. That means oFono
451          * still tries to go online. If we retry to set Active = True,
452          * we just get a InProgress error message. Should we power
453          * cycle the modem in such cases?
454          */
455
456         connman_network_set_error(modem->network,
457                                 CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
458 }
459
460 static int context_set_active(struct modem_data *modem)
461 {
462         dbus_bool_t active = TRUE;
463
464         DBG("%s", modem->path);
465
466         return set_property(modem, modem->context->path,
467                                 OFONO_CONTEXT_INTERFACE,
468                                 "Active", DBUS_TYPE_BOOLEAN,
469                                 &active,
470                                 context_set_active_reply);
471 }
472
473 static int context_set_inactive(struct modem_data *modem)
474 {
475         dbus_bool_t active = FALSE;
476         int err;
477
478         DBG("%s", modem->path);
479
480         err = set_property(modem, modem->context->path,
481                                 OFONO_CONTEXT_INTERFACE,
482                                 "Active", DBUS_TYPE_BOOLEAN,
483                                 &active,
484                                 NULL);
485         if (err == -EINPROGRESS)
486                 return 0;
487
488         return err;
489 }
490
491 static void modem_set_online_reply(struct modem_data *modem,
492                                         connman_bool_t success)
493 {
494         DBG("%s", modem->path);
495
496         if (success == TRUE) {
497                 /*
498                  * Don't handle do anything on success here. oFono will send
499                  * the change via PropertyChanged singal.
500                  */
501                 return;
502         }
503
504         modem->set_online = FALSE;
505 }
506
507 static int modem_set_online(struct modem_data *modem)
508 {
509         DBG("%s", modem->path);
510
511         modem->set_online = TRUE;
512
513         return set_property(modem, modem->path,
514                                 OFONO_MODEM_INTERFACE,
515                                 "Online", DBUS_TYPE_BOOLEAN,
516                                 &modem->set_online,
517                                 modem_set_online_reply);
518 }
519
520 static void cm_set_powered_reply(struct modem_data *modem,
521                                         connman_bool_t success)
522 {
523         DBG("%s", modem->path);
524
525         if (success == TRUE) {
526                 /*
527                  * Don't handle do anything on success here. oFono will send
528                  * the change via PropertyChanged singal.
529                  */
530                 return;
531         }
532
533         modem->set_cm_powered = FALSE;
534 }
535
536 static int cm_set_powered(struct modem_data *modem)
537 {
538         DBG("%s", modem->path);
539
540         modem->set_cm_powered = TRUE;
541
542         return set_property(modem, modem->path,
543                                 OFONO_CM_INTERFACE,
544                                 "Powered", DBUS_TYPE_BOOLEAN,
545                                 &modem->set_cm_powered,
546                                 cm_set_powered_reply);
547 }
548
549 static int modem_set_powered(struct modem_data *modem)
550 {
551         DBG("%s", modem->path);
552
553         modem->set_powered = TRUE;
554
555         return set_property(modem, modem->path,
556                                 OFONO_MODEM_INTERFACE,
557                                 "Powered", DBUS_TYPE_BOOLEAN,
558                                 &modem->set_powered,
559                                 NULL);
560 }
561
562 static connman_bool_t has_interface(uint8_t interfaces,
563                                         enum ofono_api api)
564 {
565         if ((interfaces & api) == api)
566                 return TRUE;
567
568         return FALSE;
569 }
570
571 static uint8_t extract_interfaces(DBusMessageIter *array)
572 {
573         DBusMessageIter entry;
574         uint8_t interfaces = 0;
575
576         dbus_message_iter_recurse(array, &entry);
577
578         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
579                 const char *name;
580
581                 dbus_message_iter_get_basic(&entry, &name);
582
583                 if (g_str_equal(name, OFONO_SIM_INTERFACE) == TRUE)
584                         interfaces |= OFONO_API_SIM;
585                 else if (g_str_equal(name, OFONO_NETREG_INTERFACE) == TRUE)
586                         interfaces |= OFONO_API_NETREG;
587                 else if (g_str_equal(name, OFONO_CM_INTERFACE) == TRUE)
588                         interfaces |= OFONO_API_CM;
589
590                 dbus_message_iter_next(&entry);
591         }
592
593         return interfaces;
594 }
595
596 static char *extract_nameservers(DBusMessageIter *array)
597 {
598         DBusMessageIter entry;
599         char *nameservers = NULL;
600         char *tmp;
601
602         dbus_message_iter_recurse(array, &entry);
603
604         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
605                 const char *nameserver;
606
607                 dbus_message_iter_get_basic(&entry, &nameserver);
608
609                 if (nameservers == NULL) {
610                         nameservers = g_strdup(nameserver);
611                 } else {
612                         tmp = nameservers;
613                         nameservers = g_strdup_printf("%s %s", tmp, nameserver);
614                         g_free(tmp);
615                 }
616
617                 dbus_message_iter_next(&entry);
618         }
619
620         return nameservers;
621 }
622
623 static void extract_ipv4_settings(DBusMessageIter *array,
624                                 struct network_context *context)
625 {
626         DBusMessageIter dict;
627         char *address = NULL, *netmask = NULL, *gateway = NULL;
628         char *nameservers = NULL;
629         const char *interface = NULL;
630         int index = -1;
631
632         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
633                 return;
634
635         dbus_message_iter_recurse(array, &dict);
636
637         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
638                 DBusMessageIter entry, value;
639                 const char *key, *val;
640
641                 dbus_message_iter_recurse(&dict, &entry);
642                 dbus_message_iter_get_basic(&entry, &key);
643
644                 dbus_message_iter_next(&entry);
645                 dbus_message_iter_recurse(&entry, &value);
646
647                 if (g_str_equal(key, "Interface") == TRUE) {
648                         dbus_message_iter_get_basic(&value, &interface);
649
650                         DBG("Interface %s", interface);
651
652                         index = connman_inet_ifindex(interface);
653
654                         DBG("index %d", index);
655                 } else if (g_str_equal(key, "Method") == TRUE) {
656                         dbus_message_iter_get_basic(&value, &val);
657
658                         DBG("Method %s", val);
659
660                         if (g_strcmp0(val, "static") == 0) {
661                                 context->ipv4_method = CONNMAN_IPCONFIG_METHOD_FIXED;
662                         } else if (g_strcmp0(val, "dhcp") == 0) {
663                                 context->ipv4_method = CONNMAN_IPCONFIG_METHOD_DHCP;
664                                 break;
665                         }
666                 } else if (g_str_equal(key, "Address") == TRUE) {
667                         dbus_message_iter_get_basic(&value, &val);
668
669                         address = g_strdup(val);
670
671                         DBG("Address %s", address);
672                 } else if (g_str_equal(key, "Netmask") == TRUE) {
673                         dbus_message_iter_get_basic(&value, &val);
674
675                         netmask = g_strdup(val);
676
677                         DBG("Netmask %s", netmask);
678                 } else if (g_str_equal(key, "DomainNameServers") == TRUE) {
679                         nameservers = extract_nameservers(&value);
680
681                         DBG("Nameservers %s", nameservers);
682                 } else if (g_str_equal(key, "Gateway") == TRUE) {
683                         dbus_message_iter_get_basic(&value, &val);
684
685                         gateway = g_strdup(val);
686
687                         DBG("Gateway %s", gateway);
688                 }
689
690                 dbus_message_iter_next(&dict);
691         }
692
693         if (index < 0)
694                 goto out;
695
696         if (context->ipv4_method != CONNMAN_IPCONFIG_METHOD_FIXED)
697                 goto out;
698
699         context->ipv4_address = connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4);
700         if (context->ipv4_address == NULL)
701                 goto out;
702
703         context->index = index;
704         connman_ipaddress_set_ipv4(context->ipv4_address, address,
705                                 netmask, gateway);
706
707         context->ipv4_nameservers = nameservers;
708
709 out:
710         if (context->ipv4_nameservers != nameservers)
711                 g_free(nameservers);
712
713         g_free(address);
714         g_free(netmask);
715         g_free(gateway);
716 }
717
718 static void extract_ipv6_settings(DBusMessageIter *array,
719                                 struct network_context *context)
720 {
721         DBusMessageIter dict;
722         char *address = NULL, *gateway = NULL;
723         unsigned char prefix_length;
724         char *nameservers = NULL;
725         const char *interface = NULL;
726         int index = -1;
727
728         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
729                 return;
730
731         dbus_message_iter_recurse(array, &dict);
732
733         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
734                 DBusMessageIter entry, value;
735                 const char *key, *val;
736
737                 dbus_message_iter_recurse(&dict, &entry);
738                 dbus_message_iter_get_basic(&entry, &key);
739
740                 dbus_message_iter_next(&entry);
741                 dbus_message_iter_recurse(&entry, &value);
742
743                 if (g_str_equal(key, "Interface") == TRUE) {
744                         dbus_message_iter_get_basic(&value, &interface);
745
746                         DBG("Interface %s", interface);
747
748                         index = connman_inet_ifindex(interface);
749
750                         DBG("index %d", index);
751                 } else if (g_str_equal(key, "Address") == TRUE) {
752                         dbus_message_iter_get_basic(&value, &val);
753
754                         address = g_strdup(val);
755
756                         DBG("Address %s", address);
757                 } else if (g_str_equal(key, "PrefixLength") == TRUE) {
758                         dbus_message_iter_get_basic(&value, &prefix_length);
759
760                         DBG("prefix length %d", prefix_length);
761                 } else if (g_str_equal(key, "DomainNameServers") == TRUE) {
762                         nameservers = extract_nameservers(&value);
763
764                         DBG("Nameservers %s", nameservers);
765                 } else if (g_str_equal(key, "Gateway") == TRUE) {
766                         dbus_message_iter_get_basic(&value, &val);
767
768                         gateway = g_strdup(val);
769
770                         DBG("Gateway %s", gateway);
771                 }
772
773                 dbus_message_iter_next(&dict);
774         }
775
776         if (index < 0)
777                 goto out;
778
779         context->ipv6_method = CONNMAN_IPCONFIG_METHOD_FIXED;
780
781         context->ipv6_address =
782                 connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV6);
783         if (context->ipv6_address == NULL)
784                 goto out;
785
786         context->index = index;
787         connman_ipaddress_set_ipv6(context->ipv6_address, address,
788                                 prefix_length, gateway);
789
790         context->ipv6_nameservers = nameservers;
791
792 out:
793         if (context->ipv6_nameservers != nameservers)
794                 g_free(nameservers);
795
796         g_free(address);
797         g_free(gateway);
798 }
799
800 static connman_bool_t ready_to_create_device(struct modem_data *modem)
801 {
802         /*
803          * There are three different modem types which behave slightly
804          * different:
805          * - GSM modems will expose the SIM interface then the
806          *   CM interface.
807          * - DUN modems will expose first a unique serial number (BDADDR)
808          *   and then the CM interface.
809          * - CDMA modems will expose CM first and sometime later
810          *   a unique serial number.
811          *
812          * This functions tests if we have the necessary information gathered
813          * before we are able to create a device.
814          */
815
816         if (modem->device != NULL)
817                 return FALSE;
818
819         if (modem->imsi != NULL || modem->serial != NULL)
820                 return TRUE;
821
822         return FALSE;
823 }
824
825 static void create_device(struct modem_data *modem)
826 {
827         struct connman_device *device;
828         char *uninitialized_var(ident);
829
830         DBG("%s", modem->path);
831
832         if (modem->imsi != NULL)
833                 ident = modem->imsi;
834         else if (modem->serial != NULL)
835                 ident = modem->serial;
836
837         if (connman_dbus_validate_ident(ident) == FALSE)
838                 ident = connman_dbus_encode_string(ident);
839         else
840                 ident = g_strdup(ident);
841
842         device = connman_device_create(ident, CONNMAN_DEVICE_TYPE_CELLULAR);
843         if (device == NULL)
844                 goto out;
845
846         DBG("device %p", device);
847
848         connman_device_set_ident(device, ident);
849
850         connman_device_set_string(device, "Path", modem->path);
851
852         connman_device_set_data(device, modem);
853
854         if (connman_device_register(device) < 0) {
855                 connman_error("Failed to register cellular device");
856                 connman_device_unref(device);
857                 goto out;
858         }
859
860         modem->device = device;
861
862 out:
863         g_free(ident);
864 }
865
866 static void destroy_device(struct modem_data *modem)
867 {
868         DBG("%s", modem->path);
869
870         connman_device_set_powered(modem->device, FALSE);
871
872         if (modem->network != NULL) {
873                 connman_device_remove_network(modem->device, modem->network);
874                 connman_network_unref(modem->network);
875                 modem->network = NULL;
876         }
877
878         connman_device_unregister(modem->device);
879         connman_device_unref(modem->device);
880
881         modem->device = NULL;
882 }
883
884 static void add_network(struct modem_data *modem)
885 {
886         const char *group;
887
888         DBG("%s", modem->path);
889
890         if (modem->network != NULL)
891                 return;
892
893         modem->network = connman_network_create(modem->context->path,
894                                                 CONNMAN_NETWORK_TYPE_CELLULAR);
895         if (modem->network == NULL)
896                 return;
897
898         DBG("network %p", modem->network);
899
900         connman_network_set_data(modem->network, modem);
901
902         connman_network_set_string(modem->network, "Path",
903                                         modem->context->path);
904
905         connman_network_set_index(modem->network, modem->context->index);
906
907         if (modem->name != NULL)
908                 connman_network_set_name(modem->network, modem->name);
909         else
910                 connman_network_set_name(modem->network, "");
911
912         connman_network_set_strength(modem->network, modem->strength);
913
914         group = get_ident(modem->context->path);
915         connman_network_set_group(modem->network, group);
916
917         connman_network_set_available(modem->network, TRUE);
918
919         if (connman_device_add_network(modem->device, modem->network) < 0) {
920                 connman_network_unref(modem->network);
921                 modem->network = NULL;
922                 return;
923         }
924 }
925
926 static int add_cm_context(struct modem_data *modem, const char *context_path,
927                                 DBusMessageIter *dict)
928 {
929         const char *context_type;
930         struct network_context *context = NULL;
931         connman_bool_t active = FALSE;
932
933         DBG("%s context path %s", modem->path, context_path);
934
935         if (modem->context != NULL) {
936                 /*
937                  * We have already assigned a context to this modem
938                  * and we do only support one Internet context.
939                  */
940                 return -EALREADY;
941         }
942
943         context = network_context_alloc(context_path);
944         if (context == NULL)
945                 return -ENOMEM;
946
947         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
948                 DBusMessageIter entry, value;
949                 const char *key;
950
951                 dbus_message_iter_recurse(dict, &entry);
952                 dbus_message_iter_get_basic(&entry, &key);
953
954                 dbus_message_iter_next(&entry);
955                 dbus_message_iter_recurse(&entry, &value);
956
957                 if (g_str_equal(key, "Type") == TRUE) {
958                         dbus_message_iter_get_basic(&value, &context_type);
959
960                         DBG("%s context %s type %s", modem->path,
961                                 context_path, context_type);
962                 } else if (g_str_equal(key, "Settings") == TRUE) {
963                         DBG("%s Settings", modem->path);
964
965                         extract_ipv4_settings(&value, context);
966                 } else if (g_str_equal(key, "IPv6.Settings") == TRUE) {
967                         DBG("%s IPv6.Settings", modem->path);
968
969                         extract_ipv6_settings(&value, context);
970                 } else if (g_str_equal(key, "Active") == TRUE) {
971                         dbus_message_iter_get_basic(&value, &active);
972
973                         DBG("%s Active %d", modem->path, active);
974                 }
975
976                 dbus_message_iter_next(dict);
977         }
978
979         if (g_strcmp0(context_type, "internet") != 0) {
980                 network_context_free(context);
981                 return -EINVAL;
982         }
983
984         modem->context = context;
985         modem->active = active;
986
987         g_hash_table_replace(context_hash, g_strdup(context_path), modem);
988
989         return 0;
990 }
991
992 static void remove_cm_context(struct modem_data *modem,
993                                 const char *context_path)
994 {
995         if (modem->context == NULL)
996                 return;
997
998         g_hash_table_remove(context_hash, context_path);
999
1000         network_context_free(modem->context);
1001         modem->context = NULL;
1002 }
1003
1004 static gboolean context_changed(DBusConnection *connection,
1005                                 DBusMessage *message,
1006                                 void *user_data)
1007 {
1008         const char *context_path = dbus_message_get_path(message);
1009         struct modem_data *modem = NULL;
1010         DBusMessageIter iter, value;
1011         const char *key;
1012
1013         DBG("context_path %s", context_path);
1014
1015         modem = g_hash_table_lookup(context_hash, context_path);
1016         if (modem == NULL)
1017                 return TRUE;
1018
1019         if (dbus_message_iter_init(message, &iter) == FALSE)
1020                 return TRUE;
1021
1022         dbus_message_iter_get_basic(&iter, &key);
1023
1024         dbus_message_iter_next(&iter);
1025         dbus_message_iter_recurse(&iter, &value);
1026
1027         /*
1028          * oFono guarantees the ordering of Settings and
1029          * Active. Settings will always be send before Active = True.
1030          * That means we don't have to order here.
1031          */
1032         if (g_str_equal(key, "Settings") == TRUE) {
1033                 DBG("%s Settings", modem->path);
1034
1035                 extract_ipv4_settings(&value, modem->context);
1036         } else if (g_str_equal(key, "IPv6.Settings") == TRUE) {
1037                 DBG("%s IPv6.Settings", modem->path);
1038
1039                 extract_ipv6_settings(&value, modem->context);
1040         } else if (g_str_equal(key, "Active") == TRUE) {
1041                 dbus_message_iter_get_basic(&value, &modem->active);
1042
1043                 DBG("%s Active %d", modem->path, modem->active);
1044
1045                 if (modem->active == TRUE)
1046                         set_connected(modem);
1047                 else
1048                         set_disconnected(modem);
1049         }
1050
1051         return TRUE;
1052 }
1053
1054 static void cm_get_contexts_reply(DBusPendingCall *call, void *user_data)
1055 {
1056         struct modem_data *modem = user_data;
1057         DBusMessageIter array, dict, entry, value;
1058         DBusMessage *reply;
1059         DBusError error;
1060
1061         DBG("%s", modem->path);
1062
1063         modem->call_get_contexts = NULL;
1064
1065         reply = dbus_pending_call_steal_reply(call);
1066
1067         dbus_error_init(&error);
1068
1069         if (dbus_set_error_from_message(&error, reply) == TRUE) {
1070                 connman_error("%s", error.message);
1071                 dbus_error_free(&error);
1072                 goto done;
1073         }
1074
1075         if (dbus_message_iter_init(reply, &array) == FALSE)
1076                 goto done;
1077
1078         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
1079                 goto done;
1080
1081         dbus_message_iter_recurse(&array, &dict);
1082
1083         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
1084                 const char *context_path;
1085
1086                 dbus_message_iter_recurse(&dict, &entry);
1087                 dbus_message_iter_get_basic(&entry, &context_path);
1088
1089                 dbus_message_iter_next(&entry);
1090                 dbus_message_iter_recurse(&entry, &value);
1091
1092                 if (add_cm_context(modem, context_path, &value) == 0)
1093                         break;
1094
1095                 dbus_message_iter_next(&dict);
1096         }
1097
1098 done:
1099         dbus_message_unref(reply);
1100
1101         dbus_pending_call_unref(call);
1102 }
1103
1104 static int cm_get_contexts(struct modem_data *modem)
1105 {
1106         DBusMessage *message;
1107
1108         DBG("%s", modem->path);
1109
1110         if (modem->call_get_contexts != NULL)
1111                 return -EBUSY;
1112
1113         message = dbus_message_new_method_call(OFONO_SERVICE, modem->path,
1114                                         OFONO_CM_INTERFACE, GET_CONTEXTS);
1115         if (message == NULL)
1116                 return -ENOMEM;
1117
1118         if (dbus_connection_send_with_reply(connection, message,
1119                         &modem->call_get_contexts, TIMEOUT) == FALSE) {
1120                 connman_error("Failed to call GetContexts()");
1121                 dbus_message_unref(message);
1122                 return -EINVAL;
1123         }
1124
1125         if (modem->call_get_contexts == NULL) {
1126                 connman_error("D-Bus connection not available");
1127                 dbus_message_unref(message);
1128                 return -EINVAL;
1129         }
1130
1131         dbus_pending_call_set_notify(modem->call_get_contexts,
1132                                         cm_get_contexts_reply,
1133                                         modem, NULL);
1134
1135         dbus_message_unref(message);
1136
1137         return -EINPROGRESS;
1138 }
1139
1140 static gboolean cm_context_added(DBusConnection *connection,
1141                                         DBusMessage *message,
1142                                         void *user_data)
1143 {
1144         const char *path = dbus_message_get_path(message);
1145         char *context_path;
1146         struct modem_data *modem;
1147         DBusMessageIter iter, properties;
1148
1149         DBG("%s", path);
1150
1151         modem = g_hash_table_lookup(modem_hash, context_path);
1152         if (modem == NULL)
1153                 return TRUE;
1154
1155         if (dbus_message_iter_init(message, &iter) == FALSE)
1156                 return TRUE;
1157
1158         dbus_message_iter_get_basic(&iter, &context_path);
1159
1160         dbus_message_iter_next(&iter);
1161         dbus_message_iter_recurse(&iter, &properties);
1162
1163         if (add_cm_context(modem, context_path, &properties) != 0)
1164                 return TRUE;
1165
1166         return TRUE;
1167 }
1168
1169 static gboolean cm_context_removed(DBusConnection *connection,
1170                                         DBusMessage *message,
1171                                         void *user_data)
1172 {
1173         const char *path = dbus_message_get_path(message);
1174         const char *context_path;
1175         struct modem_data *modem;
1176         DBusMessageIter iter;
1177
1178         DBG("context path %s", path);
1179
1180         if (dbus_message_iter_init(message, &iter) == FALSE)
1181                 return TRUE;
1182
1183         dbus_message_iter_get_basic(&iter, &context_path);
1184
1185         modem = g_hash_table_lookup(context_hash, context_path);
1186         if (modem == NULL)
1187                 return TRUE;
1188
1189         remove_cm_context(modem, context_path);
1190
1191         return TRUE;
1192 }
1193
1194 static gboolean netreg_changed(DBusConnection *connection, DBusMessage *message,
1195                                 void *user_data)
1196 {
1197         const char *path = dbus_message_get_path(message);
1198         struct modem_data *modem;
1199         DBusMessageIter iter, value;
1200         const char *key;
1201
1202         modem = g_hash_table_lookup(modem_hash, path);
1203         if (modem == NULL)
1204                 return TRUE;
1205
1206         if (dbus_message_iter_init(message, &iter) == FALSE)
1207                 return TRUE;
1208
1209         dbus_message_iter_get_basic(&iter, &key);
1210
1211         dbus_message_iter_next(&iter);
1212         dbus_message_iter_recurse(&iter, &value);
1213
1214         if (g_str_equal(key, "Name") == TRUE) {
1215                 char *name;
1216
1217                 dbus_message_iter_get_basic(&value, &name);
1218
1219                 DBG("%s Name %s", modem->path, name);
1220
1221                 g_free(modem->name);
1222                 modem->name = g_strdup(name);
1223
1224                 if (modem->network == NULL)
1225                         return TRUE;
1226
1227                 connman_network_set_name(modem->network, modem->name);
1228                 connman_network_update(modem->network);
1229         } else if (g_str_equal(key, "Strength") == TRUE) {
1230                 dbus_message_iter_get_basic(&value, &modem->strength);
1231
1232                 DBG("%s Strength %d", modem->path, modem->strength);
1233
1234                 if (modem->network == NULL)
1235                         return TRUE;
1236
1237                 connman_network_set_strength(modem->network, modem->strength);
1238                 connman_network_update(modem->network);
1239         }
1240
1241         return TRUE;
1242 }
1243
1244 static void netreg_properties_reply(struct modem_data *modem,
1245                                         DBusMessageIter *dict)
1246 {
1247         DBG("%s", modem->path);
1248
1249         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1250                 DBusMessageIter entry, value;
1251                 const char *key;
1252
1253                 dbus_message_iter_recurse(dict, &entry);
1254                 dbus_message_iter_get_basic(&entry, &key);
1255
1256                 dbus_message_iter_next(&entry);
1257                 dbus_message_iter_recurse(&entry, &value);
1258
1259                 if (g_str_equal(key, "Name") == TRUE) {
1260                         char *name;
1261
1262                         dbus_message_iter_get_basic(&value, &name);
1263
1264                         DBG("%s Name %s", modem->path, name);
1265
1266                         g_free(modem->name);
1267                         modem->name = g_strdup(name);
1268
1269                         if (modem->network != NULL) {
1270                                 connman_network_set_name(modem->network,
1271                                                                 modem->name);
1272                                 connman_network_update(modem->network);
1273                         }
1274                 } else if (g_str_equal(key, "Strength") == TRUE) {
1275                         dbus_message_iter_get_basic(&value, &modem->strength);
1276
1277                         DBG("%s Strength %d", modem->path,
1278                                 modem->strength);
1279
1280                         if (modem->network != NULL) {
1281                                 connman_network_set_strength(modem->network,
1282                                                         modem->strength);
1283                                 connman_network_update(modem->network);
1284                         }
1285                 }
1286
1287                 dbus_message_iter_next(dict);
1288         }
1289
1290         if (modem->context == NULL) {
1291                 /*
1292                  * netgreg_get_properties() was issued after we got
1293                  * cm_get_contexts_reply() where we create the
1294                  * context. Though before we got the
1295                  * netreg_properties_reply the context was removed
1296                  * again. Therefore we have to skip the network
1297                  * creation.
1298                  */
1299                 return;
1300         }
1301
1302         add_network(modem);
1303
1304         if (modem->active == TRUE)
1305                 set_connected(modem);
1306 }
1307
1308 static int netreg_get_properties(struct modem_data *modem)
1309 {
1310         return get_properties(modem->path, OFONO_NETREG_INTERFACE,
1311                         netreg_properties_reply, modem);
1312 }
1313
1314 static gboolean cm_changed(DBusConnection *connection, DBusMessage *message,
1315                                 void *user_data)
1316 {
1317         const char *path = dbus_message_get_path(message);
1318         struct modem_data *modem;
1319         DBusMessageIter iter, value;
1320         const char *key;
1321
1322         modem = g_hash_table_lookup(modem_hash, path);
1323         if (modem == NULL)
1324                 return TRUE;
1325
1326         if (dbus_message_iter_init(message, &iter) == FALSE)
1327                 return TRUE;
1328
1329         dbus_message_iter_get_basic(&iter, &key);
1330
1331         dbus_message_iter_next(&iter);
1332         dbus_message_iter_recurse(&iter, &value);
1333
1334         if (g_str_equal(key, "Attached") == TRUE) {
1335                 dbus_message_iter_get_basic(&value, &modem->attached);
1336
1337                 DBG("%s Attached %d", modem->path, modem->attached);
1338
1339                 if (modem->attached == TRUE) {
1340                         if (has_interface(modem->interfaces,
1341                                                 OFONO_API_NETREG) == TRUE) {
1342                                 netreg_get_properties(modem);
1343                         }
1344                 }
1345         } else if (g_str_equal(key, "Powered") == TRUE) {
1346                 dbus_message_iter_get_basic(&value, &modem->cm_powered);
1347
1348                 DBG("%s ConnnectionManager Powered %d", modem->path,
1349                         modem->cm_powered);
1350
1351                 if (modem->cm_powered == FALSE)
1352                         cm_set_powered(modem);
1353         }
1354
1355         return TRUE;
1356 }
1357
1358 static void cm_properties_reply(struct modem_data *modem, DBusMessageIter *dict)
1359 {
1360         DBG("%s", modem->path);
1361
1362         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1363                 DBusMessageIter entry, value;
1364                 const char *key;
1365
1366                 dbus_message_iter_recurse(dict, &entry);
1367                 dbus_message_iter_get_basic(&entry, &key);
1368
1369                 dbus_message_iter_next(&entry);
1370                 dbus_message_iter_recurse(&entry, &value);
1371
1372                 if (g_str_equal(key, "Attached") == TRUE) {
1373                         dbus_message_iter_get_basic(&value, &modem->attached);
1374
1375                         DBG("%s Attached %d", modem->path,
1376                                 modem->attached);
1377
1378                         if (modem->attached == TRUE) {
1379                                 if (has_interface(modem->interfaces,
1380                                                 OFONO_API_NETREG) == TRUE) {
1381                                         netreg_get_properties(modem);
1382                                 }
1383                         }
1384                 } else if (g_str_equal(key, "Powered") == TRUE) {
1385                         dbus_message_iter_get_basic(&value, &modem->cm_powered);
1386
1387                         DBG("%s ConnnectionManager Powered %d", modem->path,
1388                                 modem->cm_powered);
1389
1390                         if (modem->cm_powered == FALSE)
1391                                 cm_set_powered(modem);
1392                 }
1393
1394                 dbus_message_iter_next(dict);
1395         }
1396 }
1397
1398 static int cm_get_properties(struct modem_data *modem)
1399 {
1400         return get_properties(modem->path, OFONO_CM_INTERFACE,
1401                                 cm_properties_reply, modem);
1402 }
1403
1404 static void update_sim_imsi(struct modem_data *modem,
1405                                 const char *imsi)
1406 {
1407         DBG("%s imsi %s", modem->path, imsi);
1408
1409         if (g_strcmp0(modem->imsi, imsi) == 0)
1410                 return;
1411
1412         g_free(modem->imsi);
1413         modem->imsi = g_strdup(imsi);
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         modem = g_hash_table_lookup(modem_hash, path);
1425         if (modem == NULL)
1426                 return TRUE;
1427
1428         if (dbus_message_iter_init(message, &iter) == FALSE)
1429                 return TRUE;
1430
1431         dbus_message_iter_get_basic(&iter, &key);
1432
1433         dbus_message_iter_next(&iter);
1434         dbus_message_iter_recurse(&iter, &value);
1435
1436         if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
1437                 char *imsi;
1438
1439                 dbus_message_iter_get_basic(&value, &imsi);
1440
1441                 update_sim_imsi(modem, imsi);
1442
1443                 if (modem->online == FALSE) {
1444                         modem_set_online(modem);
1445                 } else if (has_interface(modem->interfaces,
1446                                                 OFONO_API_CM) == TRUE) {
1447                         if (ready_to_create_device(modem) == TRUE)
1448                                 create_device(modem);
1449                 }
1450         }
1451
1452         return TRUE;
1453 }
1454
1455 static void sim_properties_reply(struct modem_data *modem,
1456                                         DBusMessageIter *dict)
1457 {
1458         DBG("%s", modem->path);
1459
1460         while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
1461                 DBusMessageIter entry, value;
1462                 const char *key;
1463
1464                 dbus_message_iter_recurse(dict, &entry);
1465                 dbus_message_iter_get_basic(&entry, &key);
1466
1467                 dbus_message_iter_next(&entry);
1468                 dbus_message_iter_recurse(&entry, &value);
1469
1470                 if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
1471                         char *imsi;
1472
1473                         dbus_message_iter_get_basic(&value, &imsi);
1474
1475                         update_sim_imsi(modem, imsi);
1476
1477                         if (modem->online == FALSE) {
1478                                 modem_set_online(modem);
1479                                 break;
1480                         }
1481
1482                         if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
1483                                 if (ready_to_create_device(modem) == TRUE)
1484                                         create_device(modem);
1485                                 if (modem->device != NULL) {
1486                                         cm_get_properties(modem);
1487                                         cm_get_contexts(modem);
1488                                 }
1489                         }
1490                         return;
1491                 }
1492
1493                 dbus_message_iter_next(dict);
1494         }
1495 }
1496
1497 static int sim_get_properties(struct modem_data *modem)
1498 {
1499         return get_properties(modem->path, OFONO_SIM_INTERFACE,
1500                         sim_properties_reply, modem);
1501 }
1502
1503 static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
1504                                 void *user_data)
1505 {
1506         const char *path = dbus_message_get_path(message);
1507         struct modem_data *modem;
1508         DBusMessageIter iter, value;
1509         const char *key;
1510
1511         modem = g_hash_table_lookup(modem_hash, path);
1512         if (modem == NULL)
1513                 return TRUE;
1514
1515         if (dbus_message_iter_init(message, &iter) == FALSE)
1516                 return TRUE;
1517
1518         dbus_message_iter_get_basic(&iter, &key);
1519
1520         dbus_message_iter_next(&iter);
1521         dbus_message_iter_recurse(&iter, &value);
1522
1523         if (g_str_equal(key, "Powered") == TRUE) {
1524                 dbus_message_iter_get_basic(&value, &modem->powered);
1525
1526                 DBG("%s Powered %d", modem->path, modem->powered);
1527
1528                 if (modem->powered == FALSE)
1529                         modem_set_powered(modem);
1530         } else if (g_str_equal(key, "Online") == TRUE) {
1531                 dbus_message_iter_get_basic(&value, &modem->online);
1532
1533                 DBG("%s Online %d", modem->path, modem->online);
1534
1535                 if (modem->online == FALSE)
1536                         return TRUE;
1537
1538                 if (has_interface(modem->interfaces, OFONO_API_CM) == FALSE)
1539                         return TRUE;
1540                 if (ready_to_create_device(modem) == TRUE)
1541                         create_device(modem);
1542                 if (modem->device != NULL) {
1543                         cm_get_properties(modem);
1544                         cm_get_contexts(modem);
1545                 }
1546         } else if (g_str_equal(key, "Interfaces") == TRUE) {
1547                 modem->interfaces = extract_interfaces(&value);
1548
1549                 DBG("%s Interfaces 0x%02x", modem->path,
1550                         modem->interfaces);
1551
1552                 if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE) {
1553                         if (modem->imsi == NULL &&
1554                                         modem->set_powered == FALSE) {
1555                                 /*
1556                                  * Only use do GetProperties() when
1557                                  * device has not been powered up.
1558                                  */
1559                                 sim_get_properties(modem);
1560                                 return TRUE;
1561                         }
1562                 }
1563
1564                 if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
1565                         if (ready_to_create_device(modem) == TRUE)
1566                                 create_device(modem);
1567                         if (modem->device != NULL) {
1568                                 cm_get_properties(modem);
1569                                 cm_get_contexts(modem);
1570                                 return TRUE;
1571                         }
1572                 } else {
1573                         if (modem->context != NULL) {
1574                                 remove_cm_context(modem,
1575                                                 modem->context->path);
1576                         }
1577
1578                         if (modem->device != NULL)
1579                                 destroy_device(modem);
1580
1581                         return TRUE;
1582                 }
1583
1584                 if (has_interface(modem->interfaces, OFONO_API_NETREG) == TRUE) {
1585                         if (modem->attached == TRUE)
1586                                 netreg_get_properties(modem);
1587                 }
1588         } else if (g_str_equal(key, "Serial") == TRUE) {
1589                 char *serial;
1590
1591                 dbus_message_iter_get_basic(&value, &serial);
1592
1593                 g_free(modem->serial);
1594                 modem->serial = g_strdup(serial);
1595
1596                 DBG("%s Serial %s", modem->path, modem->serial);
1597
1598                 if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
1599                         if (ready_to_create_device(modem) == TRUE)
1600                                 create_device(modem);
1601                         if (modem->device != NULL) {
1602                                 cm_get_properties(modem);
1603                                 cm_get_contexts(modem);
1604                         }
1605                 }
1606         }
1607
1608         return TRUE;
1609 }
1610
1611 static void add_modem(const char *path, DBusMessageIter *prop)
1612 {
1613         struct modem_data *modem;
1614
1615         DBG("%s", path);
1616
1617         modem = g_hash_table_lookup(modem_hash, path);
1618         if (modem != NULL) {
1619                 /*
1620                  * When oFono powers up we ask for the modems and oFono is
1621                  * reporting with modem_added signal the modems. Only
1622                  * handle them once.
1623                  */
1624                 return;
1625         }
1626
1627         modem = g_try_new0(struct modem_data, 1);
1628         if (modem == NULL)
1629                 return;
1630
1631         modem->path = g_strdup(path);
1632
1633         g_hash_table_insert(modem_hash, g_strdup(path), modem);
1634
1635         while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
1636                 DBusMessageIter entry, value;
1637                 const char *key;
1638
1639                 dbus_message_iter_recurse(prop, &entry);
1640                 dbus_message_iter_get_basic(&entry, &key);
1641
1642                 dbus_message_iter_next(&entry);
1643                 dbus_message_iter_recurse(&entry, &value);
1644
1645                 if (g_str_equal(key, "Powered") == TRUE) {
1646                         dbus_message_iter_get_basic(&value, &modem->powered);
1647
1648                         DBG("%s Powered %d", modem->path, modem->powered);
1649                 } else if (g_str_equal(key, "Online") == TRUE) {
1650                         dbus_message_iter_get_basic(&value, &modem->online);
1651
1652                         DBG("%s Online %d", modem->path, modem->online);
1653                 } else if (g_str_equal(key, "Interfaces") == TRUE) {
1654                         modem->interfaces = extract_interfaces(&value);
1655
1656                         DBG("%s Interfaces 0x%02x", modem->path,
1657                                 modem->interfaces);
1658                 } else if (g_str_equal(key, "Serial") == TRUE) {
1659                         char *serial;
1660
1661                         dbus_message_iter_get_basic(&value, &serial);
1662                         modem->serial = g_strdup(serial);
1663
1664                         DBG("%s Serial %s", modem->path, modem->serial);
1665                 }
1666
1667                 dbus_message_iter_next(prop);
1668         }
1669
1670         if (modem->powered == FALSE) {
1671                 modem_set_powered(modem);
1672         } else if (has_interface(modem->interfaces, OFONO_API_SIM) == TRUE) {
1673                 sim_get_properties(modem);
1674         } else if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
1675                 if (ready_to_create_device(modem) == TRUE)
1676                         create_device(modem);
1677                 if (modem->device != NULL) {
1678                         cm_get_properties(modem);
1679                         cm_get_contexts(modem);
1680                 }
1681         }
1682 }
1683
1684 static void remove_modem(gpointer data)
1685 {
1686         struct modem_data *modem = data;
1687
1688         DBG("%s", modem->path);
1689
1690         if (modem->call_set_property != NULL)
1691                 dbus_pending_call_cancel(modem->call_set_property);
1692
1693         if (modem->call_get_properties != NULL)
1694                 dbus_pending_call_cancel(modem->call_get_properties);
1695
1696         if (modem->call_get_contexts != NULL)
1697                 dbus_pending_call_cancel(modem->call_get_contexts);
1698
1699         if (modem->device != NULL)
1700                 destroy_device(modem);
1701
1702         if (modem->context != NULL)
1703                 remove_cm_context(modem, modem->context->path);
1704
1705         g_free(modem->serial);
1706         g_free(modem->name);
1707         g_free(modem->imsi);
1708         g_free(modem->path);
1709
1710         g_free(modem);
1711 }
1712
1713 static gboolean modem_added(DBusConnection *connection,
1714                                 DBusMessage *message, void *user_data)
1715 {
1716         DBusMessageIter iter, properties;
1717         const char *path;
1718
1719         DBG("");
1720
1721         if (dbus_message_iter_init(message, &iter) == FALSE)
1722                 return TRUE;
1723
1724         dbus_message_iter_get_basic(&iter, &path);
1725
1726         dbus_message_iter_next(&iter);
1727         dbus_message_iter_recurse(&iter, &properties);
1728
1729         add_modem(path, &properties);
1730
1731         return TRUE;
1732 }
1733
1734 static gboolean modem_removed(DBusConnection *connection,
1735                                 DBusMessage *message, void *user_data)
1736 {
1737         DBusMessageIter iter;
1738         const char *path;
1739
1740         DBG("");
1741
1742         if (dbus_message_iter_init(message, &iter) == FALSE)
1743                 return TRUE;
1744
1745         dbus_message_iter_get_basic(&iter, &path);
1746
1747         g_hash_table_remove(modem_hash, path);
1748
1749         return TRUE;
1750 }
1751
1752 static void manager_get_modems_reply(DBusPendingCall *call, void *user_data)
1753 {
1754         DBusMessage *reply;
1755         DBusError error;
1756         DBusMessageIter array, dict;
1757
1758         DBG("");
1759
1760         reply = dbus_pending_call_steal_reply(call);
1761
1762         dbus_error_init(&error);
1763
1764         if (dbus_set_error_from_message(&error, reply) == TRUE) {
1765                 connman_error("%s", error.message);
1766                 dbus_error_free(&error);
1767                 goto done;
1768         }
1769
1770         if (dbus_message_iter_init(reply, &array) == FALSE)
1771                 goto done;
1772
1773         dbus_message_iter_recurse(&array, &dict);
1774
1775         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
1776                 DBusMessageIter value, properties;
1777                 const char *path;
1778
1779                 dbus_message_iter_recurse(&dict, &value);
1780                 dbus_message_iter_get_basic(&value, &path);
1781
1782                 dbus_message_iter_next(&value);
1783                 dbus_message_iter_recurse(&value, &properties);
1784
1785                 add_modem(path, &properties);
1786
1787                 dbus_message_iter_next(&dict);
1788         }
1789
1790 done:
1791         dbus_message_unref(reply);
1792
1793         dbus_pending_call_unref(call);
1794 }
1795
1796 static int manager_get_modems(void)
1797 {
1798         DBusMessage *message;
1799         DBusPendingCall *call;
1800
1801         DBG("");
1802
1803         message = dbus_message_new_method_call(OFONO_SERVICE, "/",
1804                                         OFONO_MANAGER_INTERFACE, GET_MODEMS);
1805         if (message == NULL)
1806                 return -ENOMEM;
1807
1808         if (dbus_connection_send_with_reply(connection, message,
1809                                                &call, TIMEOUT) == FALSE) {
1810                 connman_error("Failed to call GetModems()");
1811                 dbus_message_unref(message);
1812                 return -EINVAL;
1813         }
1814
1815         if (call == NULL) {
1816                 connman_error("D-Bus connection not available");
1817                 dbus_message_unref(message);
1818                 return -EINVAL;
1819         }
1820
1821         dbus_pending_call_set_notify(call, manager_get_modems_reply,
1822                                         NULL, NULL);
1823
1824         dbus_message_unref(message);
1825
1826         return -EINPROGRESS;
1827 }
1828
1829 static void ofono_connect(DBusConnection *conn, void *user_data)
1830 {
1831         DBG("");
1832
1833         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
1834                                                 g_free, remove_modem);
1835         if (modem_hash == NULL)
1836                 return;
1837
1838         context_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
1839                                                 g_free, NULL);
1840         if (context_hash == NULL) {
1841                 g_hash_table_destroy(modem_hash);
1842                 return;
1843         }
1844
1845         manager_get_modems();
1846 }
1847
1848 static void ofono_disconnect(DBusConnection *conn, void *user_data)
1849 {
1850         DBG("");
1851
1852         if (modem_hash == NULL || context_hash == NULL)
1853                 return;
1854
1855         g_hash_table_destroy(modem_hash);
1856         modem_hash = NULL;
1857
1858         g_hash_table_destroy(context_hash);
1859         context_hash = NULL;
1860 }
1861
1862 static int network_probe(struct connman_network *network)
1863 {
1864         struct modem_data *modem = connman_network_get_data(network);
1865
1866         DBG("%s network %p", modem->path, network);
1867
1868         return 0;
1869 }
1870
1871 static void network_remove(struct connman_network *network)
1872 {
1873         struct modem_data *modem = connman_network_get_data(network);
1874
1875         DBG("%s network %p", modem->path, network);
1876 }
1877
1878 static int network_connect(struct connman_network *network)
1879 {
1880         struct modem_data *modem = connman_network_get_data(network);
1881
1882         DBG("%s network %p", modem->path, network);
1883
1884         return context_set_active(modem);
1885 }
1886
1887 static int network_disconnect(struct connman_network *network)
1888 {
1889         struct modem_data *modem = connman_network_get_data(network);
1890
1891         DBG("%s network %p", modem->path, network);
1892
1893         return context_set_inactive(modem);
1894 }
1895
1896 static struct connman_network_driver network_driver = {
1897         .name           = "network",
1898         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
1899         .probe          = network_probe,
1900         .remove         = network_remove,
1901         .connect        = network_connect,
1902         .disconnect     = network_disconnect,
1903 };
1904
1905 static int modem_probe(struct connman_device *device)
1906 {
1907         struct modem_data *modem = connman_device_get_data(device);
1908
1909         DBG("%s device %p", modem->path, device);
1910
1911         return 0;
1912 }
1913
1914 static void modem_remove(struct connman_device *device)
1915 {
1916         struct modem_data *modem = connman_device_get_data(device);
1917
1918         DBG("%s device %p", modem->path, device);
1919 }
1920
1921 static int modem_enable(struct connman_device *device)
1922 {
1923         struct modem_data *modem = connman_device_get_data(device);
1924
1925         DBG("%s device %p", modem->path, device);
1926
1927         return 0;
1928 }
1929
1930 static int modem_disable(struct connman_device *device)
1931 {
1932         struct modem_data *modem = connman_device_get_data(device);
1933
1934         DBG("%s device %p", modem->path, device);
1935
1936         return 0;
1937 }
1938
1939 static struct connman_device_driver modem_driver = {
1940         .name           = "modem",
1941         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
1942         .probe          = modem_probe,
1943         .remove         = modem_remove,
1944         .enable         = modem_enable,
1945         .disable        = modem_disable,
1946 };
1947
1948 static guint watch;
1949 static guint modem_added_watch;
1950 static guint modem_removed_watch;
1951 static guint modem_watch;
1952 static guint cm_watch;
1953 static guint sim_watch;
1954 static guint context_added_watch;
1955 static guint context_removed_watch;
1956 static guint netreg_watch;
1957 static guint context_watch;
1958
1959 static int ofono_init(void)
1960 {
1961         int err;
1962
1963         DBG("");
1964
1965         connection = connman_dbus_get_connection();
1966         if (connection == NULL)
1967                 return -EIO;
1968
1969         watch = g_dbus_add_service_watch(connection,
1970                                         OFONO_SERVICE, ofono_connect,
1971                                         ofono_disconnect, NULL, NULL);
1972
1973         modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1974                                                 OFONO_MANAGER_INTERFACE,
1975                                                 MODEM_ADDED,
1976                                                 modem_added,
1977                                                 NULL, NULL);
1978
1979         modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1980                                                 OFONO_MANAGER_INTERFACE,
1981                                                 MODEM_REMOVED,
1982                                                 modem_removed,
1983                                                 NULL, NULL);
1984
1985         modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1986                                                 OFONO_MODEM_INTERFACE,
1987                                                 PROPERTY_CHANGED,
1988                                                 modem_changed,
1989                                                 NULL, NULL);
1990
1991         cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1992                                                 OFONO_CM_INTERFACE,
1993                                                 PROPERTY_CHANGED,
1994                                                 cm_changed,
1995                                                 NULL, NULL);
1996
1997         sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1998                                                 OFONO_SIM_INTERFACE,
1999                                                 PROPERTY_CHANGED,
2000                                                 sim_changed,
2001                                                 NULL, NULL);
2002
2003         context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2004                                                 OFONO_CM_INTERFACE,
2005                                                 CONTEXT_ADDED,
2006                                                 cm_context_added,
2007                                                 NULL, NULL);
2008
2009         context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2010                                                 OFONO_CM_INTERFACE,
2011                                                 CONTEXT_REMOVED,
2012                                                 cm_context_removed,
2013                                                 NULL, NULL);
2014
2015         context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2016                                                 OFONO_CONTEXT_INTERFACE,
2017                                                 PROPERTY_CHANGED,
2018                                                 context_changed,
2019                                                 NULL, NULL);
2020
2021         netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
2022                                                 OFONO_NETREG_INTERFACE,
2023                                                 PROPERTY_CHANGED,
2024                                                 netreg_changed,
2025                                                 NULL, NULL);
2026
2027
2028         if (watch == 0 || modem_added_watch == 0 || modem_removed_watch == 0 ||
2029                         modem_watch == 0 || cm_watch == 0 || sim_watch == 0 ||
2030                         context_added_watch == 0 ||
2031                         context_removed_watch == 0 ||
2032                         context_watch == 0 || netreg_watch == 0) {
2033                 err = -EIO;
2034                 goto remove;
2035         }
2036
2037         err = connman_network_driver_register(&network_driver);
2038         if (err < 0)
2039                 goto remove;
2040
2041         err = connman_device_driver_register(&modem_driver);
2042         if (err < 0) {
2043                 connman_network_driver_unregister(&network_driver);
2044                 goto remove;
2045         }
2046
2047         return 0;
2048
2049 remove:
2050         g_dbus_remove_watch(connection, netreg_watch);
2051         g_dbus_remove_watch(connection, context_watch);
2052         g_dbus_remove_watch(connection, context_removed_watch);
2053         g_dbus_remove_watch(connection, context_added_watch);
2054         g_dbus_remove_watch(connection, sim_watch);
2055         g_dbus_remove_watch(connection, cm_watch);
2056         g_dbus_remove_watch(connection, modem_watch);
2057         g_dbus_remove_watch(connection, modem_removed_watch);
2058         g_dbus_remove_watch(connection, modem_added_watch);
2059         g_dbus_remove_watch(connection, watch);
2060         dbus_connection_unref(connection);
2061
2062         return err;
2063 }
2064
2065 static void ofono_exit(void)
2066 {
2067         DBG("");
2068
2069         if (modem_hash != NULL) {
2070                 g_hash_table_destroy(modem_hash);
2071                 modem_hash = NULL;
2072         }
2073
2074         if (context_hash != NULL) {
2075                 g_hash_table_destroy(context_hash);
2076                 context_hash = NULL;
2077         }
2078
2079         connman_device_driver_unregister(&modem_driver);
2080         connman_network_driver_unregister(&network_driver);
2081
2082         g_dbus_remove_watch(connection, netreg_watch);
2083         g_dbus_remove_watch(connection, context_watch);
2084         g_dbus_remove_watch(connection, context_removed_watch);
2085         g_dbus_remove_watch(connection, context_added_watch);
2086         g_dbus_remove_watch(connection, sim_watch);
2087         g_dbus_remove_watch(connection, cm_watch);
2088         g_dbus_remove_watch(connection, modem_watch);
2089         g_dbus_remove_watch(connection, modem_added_watch);
2090         g_dbus_remove_watch(connection, modem_removed_watch);
2091         g_dbus_remove_watch(connection, watch);
2092
2093         dbus_connection_unref(connection);
2094 }
2095
2096 CONNMAN_PLUGIN_DEFINE(ofono, "oFono telephony plugin", VERSION,
2097                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ofono_init, ofono_exit)