Merge "Add support for ipv6" into tizen
[platform/upstream/connman.git] / plugins / telephony.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2011-2013  Samsung Electronics Co., Ltd. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22
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/device.h>
36 #include <connman/network.h>
37 #include <connman/ipconfig.h>
38 #include <connman/dbus.h>
39 #include <connman/inet.h>
40 #include <connman/technology.h>
41 #include <connman/log.h>
42
43 #define PS_DBUS_SERVICE                         "com.tcore.ps"
44
45 #define PS_MASTER_INTERFACE             PS_DBUS_SERVICE ".master"
46 #define PS_MODEM_INTERFACE              PS_DBUS_SERVICE ".modem"
47 #define PS_SERVICE_INTERFACE            PS_DBUS_SERVICE ".service"
48 #define PS_CONTEXT_INTERFACE            PS_DBUS_SERVICE ".context"
49
50 /* methods */
51 #define GET_MODEMS                      "GetModems"
52 #define GET_SERVICES                    "GetServices"
53 #define GET_CONTEXTS                    "GetContexts"
54 #define ACTIVATE_CONTEXT                "Activate"
55 #define DEACTIVATE_CONTEXT              "Deactivate"
56 #define GET_PROPERTIES                  "GetProperties"
57 #define SET_PROPERTY                    "SetProperties"
58
59 /* signals */
60 #define MODEM_ADDED                     "ModemAdded"
61 #define MODEM_REMOVED                   "ModemRemoved"
62 #define SERVICE_ADDED                   "ServiceAdded"
63 #define SERVICE_REMOVED                 "ServiceRemoved"
64 #define CONTEXT_ADDED                   "ContextAdded"
65 #define CONTEXT_REMOVED                 "ContextRemoved"
66 #define PROPERTY_CHANGED                "PropertyChanged"
67
68 #define TIMEOUT 40000
69
70 #define STRING2BOOL(a)  ((g_str_equal(a, "TRUE")) ?  (TRUE):(FALSE))
71
72 static DBusConnection *connection;
73 static GHashTable       *modem_hash;
74 static GHashTable       *service_hash;
75 static GHashTable       *network_hash;
76
77 struct telephony_service {
78         char *path;
79
80         gpointer p_modem;
81         char *act;
82         gboolean roaming; /* global roaming state */
83         gboolean ps_attached; /* packet service is available */
84 };
85
86 struct telephony_modem {
87         char *path;
88
89         char *operator;
90         gboolean powered;
91         gboolean sim_init;
92         gboolean flight_mode;
93         gboolean data_allowed;
94         gboolean roaming_allowed;
95
96         struct connman_device *device;
97         struct telephony_service *s_service;
98 };
99
100 struct telephony_network {
101         char *path;
102         struct connman_network *network;
103
104         enum connman_ipconfig_method ipv4_method;
105         struct connman_ipaddress *ipv4_address;
106
107         enum connman_ipconfig_method ipv6_method;
108         struct connman_ipaddress *ipv6_address;
109 };
110
111 /* function prototype */
112 static void telephony_connect(DBusConnection *connection, void *user_data);
113 static void telephony_disconnect(DBusConnection *connection, void *user_data);
114 static void __remove_modem(gpointer data);
115 static void __remove_service(gpointer data);
116 static void __remove_network(gpointer data);
117
118 static int __modem_probe(struct connman_device *device);
119 static void __modem_remove(struct connman_device *device);
120 static int __modem_enable(struct connman_device *device);
121 static int __modem_disable(struct connman_device *device);
122
123 static int __network_probe(struct connman_network *network);
124 static void __network_remove(struct connman_network *network);
125 static int __network_connect(struct connman_network *network);
126 static int __network_disconnect(struct connman_network *network);
127
128
129 /* dbus request and reply */
130 static int __dbus_request(const char *path, const char *interface,
131                         const char *method,
132                         DBusPendingCallNotifyFunction notify, void *user_data,
133                         DBusFreeFunction free_function, int type, ...);
134
135 static int __request_get_modems(void);
136 static void __response_get_modems(DBusPendingCall *call, void *user_data);
137 static int __request_get_services(const char *path);
138 static void __response_get_services(DBusPendingCall *call, void *user_data);
139 static int __request_get_contexts(struct telephony_modem *modem);
140 static void __response_get_contexts(DBusPendingCall *call, void *user_data);
141 static int __request_network_activate(struct connman_network *network);
142 static void __response_network_activate(DBusPendingCall *call, void *user_data);
143 static int __request_network_deactivate(struct connman_network *network);
144
145 /* telephony internal function */
146 static void __add_modem(const char *path, DBusMessageIter *prop);
147 static void __add_service(struct telephony_modem *modem,
148                         const char *service_path, DBusMessageIter *prop);
149 static void __add_connman_device(const char *modem_path, const char *operator);
150 static void __remove_connman_device(struct telephony_modem *modem);
151 static void __remove_connman_networks(struct connman_device *device);
152 static void __set_device_powered(struct telephony_modem *modem,
153                                         gboolean powered);
154 static int __check_device_powered(const char *path, gboolean online);
155 static gboolean __check_network_available(struct connman_network *network);
156 static void __create_service(struct connman_network *network);
157 static int __add_context(struct connman_device *device, const char *path,
158                                                         DBusMessageIter *prop);
159 static gboolean __set_network_ipconfig(struct telephony_network *network,
160                                                         DBusMessageIter *dict);
161 static void __set_network_connected(struct telephony_network *network,
162                                                         gboolean connected);
163 static char *__get_ident(const char *path);
164
165 /* signal handler */
166 static gboolean __changed_modem(DBusConnection *connection,
167                                 DBusMessage *message, void *user_data);
168 static gboolean __added_modem(DBusConnection *connection,
169                                 DBusMessage *message, void *user_data);
170 static gboolean __removed_modem(DBusConnection *connection,
171                                 DBusMessage *message, void *user_data);
172 static gboolean __changed_service(DBusConnection *connection,
173                                 DBusMessage *message, void *user_data);
174 static gboolean __added_service(DBusConnection *connection,
175                                 DBusMessage *message, void *user_data);
176 static gboolean __removed_service(DBusConnection *connection,
177                                 DBusMessage *message, void *user_data);
178 static gboolean __changed_context(DBusConnection *connection,
179                                 DBusMessage *message, void *user_data);
180 static gboolean __added_context(DBusConnection *connection,
181                                 DBusMessage *message, void *user_data);
182 static gboolean __removed_context(DBusConnection *connection,
183                                 DBusMessage *message, void *user_data);
184
185 /* device driver */
186 static struct connman_device_driver modem_driver = {
187         .name           = "device",
188         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
189         .probe          = __modem_probe,
190         .remove         = __modem_remove,
191         .enable         = __modem_enable,
192         .disable        = __modem_disable,
193 };
194
195 /* network driver */
196 static struct connman_network_driver network_driver = {
197         .name           = "network",
198         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
199         .probe          = __network_probe,
200         .remove         = __network_remove,
201         .connect        = __network_connect,
202         .disconnect     = __network_disconnect,
203 };
204
205 static int tech_probe(struct connman_technology *technology)
206 {
207         return 0;
208 }
209
210 static void tech_remove(struct connman_technology *technology)
211 {
212 }
213
214 static struct connman_technology_driver tech_driver = {
215         .name           = "cellular",
216         .type           = CONNMAN_SERVICE_TYPE_CELLULAR,
217         .probe          = tech_probe,
218         .remove         = tech_remove,
219 };
220
221 /* local function */
222 static void telephony_connect(DBusConnection *connection, void *user_data)
223 {
224         DBG("connection %p", connection);
225         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
226                                                 g_free, __remove_modem);
227         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
228                                                 g_free, __remove_service);
229         network_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
230                                                 g_free, __remove_network);
231         __request_get_modems();
232         return;
233 }
234
235 static void telephony_disconnect(DBusConnection *connection, void *user_data)
236 {
237         DBG("connection %p", connection);
238
239         if (modem_hash != NULL) {
240                 g_hash_table_destroy(modem_hash);
241                 modem_hash = NULL;
242         }
243
244         if (network_hash != NULL) {
245                 g_hash_table_destroy(network_hash);
246                 network_hash = NULL;
247         }
248
249         return;
250 }
251
252 static void __remove_modem(gpointer data)
253 {
254         struct telephony_modem *modem = data;
255
256         __remove_connman_device(modem);
257
258         g_free(modem->path);
259         g_free(modem->operator);
260         g_free(modem);
261 }
262
263 static void __remove_service(gpointer data)
264 {
265         struct telephony_service *service = data;
266
267         g_free(service->path);
268         g_free(service->act);
269         g_free(service);
270 }
271
272 static void __remove_network(gpointer data)
273 {
274         struct telephony_network *info = data;
275         struct connman_device *device;
276
277         device = connman_network_get_device(info->network);
278         if (device != NULL)
279                 connman_device_remove_network(device, info->network);
280
281         connman_network_unref(info->network);
282
283         g_free(info->path);
284         connman_ipaddress_free(info->ipv4_address);
285         connman_ipaddress_free(info->ipv6_address);
286         g_free(info);
287 }
288
289 static int __modem_probe(struct connman_device *device)
290 {
291         DBG("device %p", device);
292         return 0;
293 }
294
295 static void __modem_remove(struct connman_device *device)
296 {
297         DBG("device %p", device);
298 }
299
300 static int __modem_enable(struct connman_device *device)
301 {
302         const char *path = connman_device_get_string(device, "Path");
303         DBG("device %p, path, %s", device, path);
304
305         return __check_device_powered(path, TRUE);
306 }
307
308 static int __modem_disable(struct connman_device *device)
309 {
310         const char *path = connman_device_get_string(device, "Path");
311         DBG("device %p, path, %s", device, path);
312
313         return __check_device_powered(path, FALSE);
314 }
315
316 static int __network_probe(struct connman_network *network)
317 {
318         DBG("network_prove network(%p)", network);
319         return 0;
320 }
321
322 static int __network_connect(struct connman_network *network)
323 {
324         struct connman_device *device;
325         struct telephony_modem *modem;
326         struct telephony_service *service;
327
328         DBG("network %p", network);
329
330         device = connman_network_get_device(network);
331         if (device == NULL)
332                 return -ENODEV;
333
334         modem = connman_device_get_data(device);
335         if (modem == NULL)
336                 return -ENODEV;
337
338         service = modem->s_service;
339         if (service == NULL)
340                 return -ENOLINK;
341
342         if (modem->powered == FALSE)
343                 return -ENOLINK;
344
345         if (modem->data_allowed == FALSE || service->ps_attached == FALSE)
346                 return -ENOLINK;
347
348         return __request_network_activate(network);
349 }
350
351 static int __network_disconnect(struct connman_network *network)
352 {
353         DBG("network %p", network);
354
355         if (connman_network_get_index(network) < 0)
356                 return -ENOTCONN;
357
358         connman_network_set_associating(network, FALSE);
359
360         return __request_network_deactivate(network);
361 }
362
363 static void __network_remove(struct connman_network *network)
364 {
365         char const *path = connman_network_get_string(network, "Path");
366         DBG("network %p path %s", network, path);
367
368         g_hash_table_remove(network_hash, path);
369         return;
370 }
371
372 static int __dbus_request(const char *path, const char *interface,
373                         const char *method,
374                         DBusPendingCallNotifyFunction notify, void *user_data,
375                         DBusFreeFunction free_function, int type, ...)
376 {
377         DBusMessage *message;
378         DBusPendingCall *call;
379         dbus_bool_t ok;
380         va_list va;
381
382         DBG("Telephony request path %s %s.%s", path, interface, method);
383
384         if (path == NULL)
385                 return -EINVAL;
386
387         message = dbus_message_new_method_call(PS_DBUS_SERVICE, path,
388                                                 interface, method);
389         if (message == NULL)
390                 return -ENOMEM;
391
392         dbus_message_set_auto_start(message, FALSE);
393
394         va_start(va, type);
395         ok = dbus_message_append_args_valist(message, type, va);
396         va_end(va);
397
398         if (!ok)
399                 return -ENOMEM;
400
401         if (dbus_connection_send_with_reply(connection, message,
402                                                 &call, TIMEOUT) == FALSE) {
403                 connman_error("Failed to call %s.%s", interface, method);
404                 dbus_message_unref(message);
405                 return -EINVAL;
406         }
407
408         if (call == NULL) {
409                 connman_error("D-Bus connection not available");
410                 dbus_message_unref(message);
411                 return -EINVAL;
412         }
413
414         dbus_pending_call_set_notify(call, notify, user_data, free_function);
415
416         dbus_message_unref(message);
417
418         return -EINPROGRESS;
419 }
420
421 static int __request_get_modems(void)
422 {
423         DBG("request get modem");
424         /* call connect master */
425         return __dbus_request("/", PS_MASTER_INTERFACE, GET_MODEMS,
426                         __response_get_modems, NULL, NULL, DBUS_TYPE_INVALID);
427 }
428
429 static void __response_get_modems(DBusPendingCall *call, void *user_data)
430 {
431         DBusMessage *reply;
432         DBusError error;
433         DBusMessageIter args, dict;
434
435         DBG("");
436
437         reply = dbus_pending_call_steal_reply(call);
438
439         dbus_error_init(&error);
440
441         if (dbus_set_error_from_message(&error, reply)) {
442                 connman_error("GetModems() %s %s", error.name, error.message);
443                 dbus_error_free(&error);
444                 goto done;
445         }
446
447         DBG("message signature (%s)", dbus_message_get_signature(reply));
448
449         if (dbus_message_iter_init(reply, &args) == FALSE)
450                 goto done;
451
452         dbus_message_iter_recurse(&args, &dict);
453
454         while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
455                 DBusMessageIter entry, property;
456                 const char *modem_path;
457
458                 dbus_message_iter_recurse(&dict, &entry);
459                 dbus_message_iter_get_basic(&entry, &modem_path);
460                 DBG("modem path (%s)", modem_path);
461
462                 dbus_message_iter_next(&entry);
463                 dbus_message_iter_recurse(&entry, &property);
464
465                 __add_modem(modem_path, &property);
466
467                 dbus_message_iter_next(&dict);
468         }
469
470 done:
471         dbus_message_unref(reply);
472         dbus_pending_call_unref(call);
473         return;
474 }
475
476 static int __request_get_services(const char *path)
477 {
478         DBG("request get service");
479         return __dbus_request(path, PS_MODEM_INTERFACE, GET_SERVICES,
480                                 __response_get_services, g_strdup(path),
481                                 g_free, DBUS_TYPE_INVALID);
482 }
483
484 static void __response_get_services(DBusPendingCall *call, void *user_data)
485 {
486         DBusMessage *reply;
487         DBusError error;
488         DBusMessageIter args, dict;
489
490         const char *path = user_data;
491         struct telephony_modem *modem;
492
493         modem = g_hash_table_lookup(modem_hash, path);
494         if (modem == NULL)
495                 return;
496         if (modem->device == NULL)
497                 return;
498
499         DBG("");
500
501         reply = dbus_pending_call_steal_reply(call);
502
503         dbus_error_init(&error);
504
505         if (dbus_set_error_from_message(&error, reply)) {
506                 connman_error("GetServices() %s %s", error.name, error.message);
507                 dbus_error_free(&error);
508                 goto done;
509         }
510
511         DBG("message signature (%s)", dbus_message_get_signature(reply));
512
513         if (dbus_message_iter_init(reply, &args) == FALSE)
514                 goto done;
515
516         dbus_message_iter_recurse(&args, &dict);
517
518         while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
519                 DBusMessageIter entry, property;
520                 const char *service_path;
521
522                 dbus_message_iter_recurse(&dict, &entry);
523                 dbus_message_iter_get_basic(&entry, &service_path);
524                 DBG("service path (%s)", service_path);
525
526                 dbus_message_iter_next(&entry);
527                 dbus_message_iter_recurse(&entry, &property);
528
529                 __add_service(modem, service_path, &property);
530
531                 dbus_message_iter_next(&dict);
532         }
533
534 done:
535         dbus_message_unref(reply);
536         dbus_pending_call_unref(call);
537         return;
538 }
539
540 static int __request_get_contexts(struct telephony_modem *modem)
541 {
542         DBG("request get contexts");
543         return __dbus_request(modem->s_service->path,
544                                 PS_SERVICE_INTERFACE, GET_CONTEXTS,
545                                 __response_get_contexts, g_strdup(modem->path),
546                                 g_free, DBUS_TYPE_INVALID);
547 }
548
549 static void __response_get_contexts(DBusPendingCall *call, void *user_data)
550 {
551         DBusError error;
552         DBusMessage *reply;
553         DBusMessageIter args, dict;
554
555         const char *path = user_data;
556         struct telephony_modem *modem;
557
558         DBG("");
559
560         modem = g_hash_table_lookup(modem_hash, path);
561         if (modem == NULL)
562                 return;
563         if (modem->s_service == NULL)
564                         return;
565         if (modem->device == NULL)
566                 return;
567
568         reply = dbus_pending_call_steal_reply(call);
569
570         dbus_error_init(&error);
571
572         if (dbus_set_error_from_message(&error, reply)) {
573                 connman_error("GetContexts() %s %s", error.name, error.message);
574                 dbus_error_free(&error);
575                 goto done;
576         }
577
578         DBG("message signature (%s)", dbus_message_get_signature(reply));
579
580         if (dbus_message_iter_init(reply, &args) == FALSE)
581                 goto done;
582
583         dbus_message_iter_recurse(&args, &dict);
584
585         while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
586                 DBusMessageIter entry, property;
587                 const char *context_path;
588
589                 dbus_message_iter_recurse(&dict, &entry);
590                 dbus_message_iter_get_basic(&entry, &context_path);
591                 DBG("context path (%s)", context_path);
592
593                 dbus_message_iter_next(&entry);
594                 dbus_message_iter_recurse(&entry, &property);
595
596                 __add_context(modem->device, context_path, &property);
597
598                 dbus_message_iter_next(&dict);
599         }
600
601 done:
602         dbus_message_unref(reply);
603         dbus_pending_call_unref(call);
604         return;
605 }
606
607 static int __request_network_activate(struct connman_network *network)
608 {
609         DBG("request network activate");
610
611         const char *path = connman_network_get_string(network, "Path");
612         DBG("network %p, path %s", network, path);
613
614         return __dbus_request(path, PS_CONTEXT_INTERFACE, ACTIVATE_CONTEXT,
615                         __response_network_activate,
616                         g_strdup(path), NULL, DBUS_TYPE_INVALID);
617 }
618
619 static void __response_network_activate(DBusPendingCall *call, void *user_data)
620 {
621         DBG("network activation response");
622
623         DBusError error;
624         DBusMessage *reply;
625
626         struct telephony_network *info;
627         const char *path = user_data;
628
629         info = g_hash_table_lookup(network_hash, path);
630         reply = dbus_pending_call_steal_reply(call);
631
632         if (info == NULL)
633                 goto done;
634
635         if (!__check_network_available(info->network)) {
636                 g_hash_table_remove(network_hash, path);
637                 goto done;
638         }
639
640         dbus_error_init(&error);
641         if (dbus_set_error_from_message(&error, reply)) {
642                 connman_error("connection activate() %s %s",
643                                         error.name, error.message);
644
645                 if (connman_network_get_index(info->network) < 0)
646                         connman_network_set_error(info->network,
647                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
648
649                 dbus_error_free(&error);
650                 goto done;
651         }
652
653 done:
654         dbus_message_unref(reply);
655         dbus_pending_call_unref(call);
656         return;
657 }
658
659 static int __request_network_deactivate(struct connman_network *network)
660 {
661         DBG("request network deactivate");
662
663         const char *path = connman_network_get_string(network, "Path");
664         DBG("network %p, path %s", network, path);
665
666         return __dbus_request(path, PS_CONTEXT_INTERFACE, DEACTIVATE_CONTEXT,
667                 NULL, NULL, NULL, DBUS_TYPE_INVALID);
668 }
669
670 static void __add_modem(const char *path, DBusMessageIter *prop)
671 {
672         struct telephony_modem *modem;
673
674         modem = g_hash_table_lookup(modem_hash, path);
675         if (modem != NULL)
676                 return;
677
678         modem = (struct telephony_modem *)malloc(
679                                         sizeof(struct telephony_modem));
680         memset(modem, 0, sizeof(struct telephony_modem));
681
682         modem->path = g_strdup(path);
683         modem->device = NULL;
684         modem->s_service = NULL;
685
686         g_hash_table_insert(modem_hash, g_strdup(path), modem);
687
688         while (dbus_message_iter_get_arg_type(prop) != DBUS_TYPE_INVALID) {
689                 DBusMessageIter entry;
690                 const char *key, *tmp;
691
692                 dbus_message_iter_recurse(prop, &entry);
693                 dbus_message_iter_get_basic(&entry, &key);
694
695                 dbus_message_iter_next(&entry);
696                 dbus_message_iter_get_basic(&entry, &tmp);
697
698                 DBG("key (%s) value(%s)", key, tmp);
699
700                 if (g_str_equal(key, "powered") == TRUE) {
701                         modem->powered = STRING2BOOL(tmp);
702                 } else if (g_str_equal(key, "operator") == TRUE) {
703                         modem->operator = g_strdup(tmp);
704                 } else if (g_str_equal(key, "sim_init") == TRUE) {
705                         modem->sim_init = STRING2BOOL(tmp);
706                 } else if (g_str_equal(key, "flight_mode") == TRUE) {
707                         modem->flight_mode = STRING2BOOL(tmp);
708                 } else if (g_str_equal(key, "roaming_allowed") == TRUE) {
709                         modem->roaming_allowed = STRING2BOOL(tmp);
710                 } else if (g_str_equal(key, "data_allowed") == TRUE) {
711                         modem->data_allowed = STRING2BOOL(tmp);
712                 }
713                 dbus_message_iter_next(prop);
714         }
715
716         __add_connman_device(path, modem->operator);
717         __set_device_powered(modem, modem->powered);
718
719         if (modem->powered != TRUE) {
720                 DBG("modem is not powered");
721                 return;
722         }
723
724         __request_get_services(modem->path);
725
726         return;
727 }
728
729 static void __add_service(struct telephony_modem *modem,
730                                 const char *service_path, DBusMessageIter *prop)
731 {
732         struct telephony_service *service;
733
734         if (modem->s_service != NULL)
735                 return;
736
737         service = (struct telephony_service *)g_try_malloc(
738                                         sizeof(struct telephony_service));
739         if (service == NULL)
740                 return;
741
742         memset(service, 0, sizeof(struct telephony_service));
743
744         service->path = g_strdup(service_path);
745         service->p_modem = modem;
746         g_hash_table_insert(service_hash, g_strdup(service_path), service);
747
748         while (dbus_message_iter_get_arg_type(prop) != DBUS_TYPE_INVALID) {
749                 DBusMessageIter entry;
750                 const char *key, *tmp;
751
752                 dbus_message_iter_recurse(prop, &entry);
753                 dbus_message_iter_get_basic(&entry, &key);
754
755                 dbus_message_iter_next(&entry);
756                 dbus_message_iter_get_basic(&entry, &tmp);
757
758                 DBG("key (%s) value(%s)", key, tmp);
759
760                 if (g_str_equal(key, "roaming") == TRUE) {
761                         service->roaming = STRING2BOOL(tmp);
762                 } else if (g_str_equal(key, "act") == TRUE) {
763                         service->act = g_strdup(tmp);
764                 } else if (g_str_equal(key, "ps_attached") == TRUE) {
765                         service->ps_attached = STRING2BOOL(tmp);
766                 }
767
768                 dbus_message_iter_next(prop);
769         }
770
771         modem->s_service = service;
772         __request_get_contexts(modem);
773
774         return;
775 }
776
777 static void __add_connman_device(const char *modem_path, const char *operator)
778 {
779         struct telephony_modem *modem;
780         struct connman_device *device;
781
782         DBG("path %s operator %s", modem_path, operator);
783
784         if (modem_path == NULL)
785                 return;
786
787         if (operator == NULL)
788                 return;
789
790         modem = g_hash_table_lookup(modem_hash, modem_path);
791         if (modem == NULL)
792                 return;
793
794         if (modem->device) {
795                 if (!g_strcmp0(operator,
796                                 connman_device_get_ident(modem->device)))
797                         return;
798
799                 __remove_connman_device(modem);
800         }
801
802         if (strlen(operator) == 0)
803                 return;
804
805         device = connman_device_create(operator, CONNMAN_DEVICE_TYPE_CELLULAR);
806         if (device == NULL)
807                 return;
808
809         connman_device_set_ident(device, operator);
810         connman_device_set_string(device, "Path", modem_path);
811         connman_device_set_data(device, modem);
812
813         if (connman_device_register(device) < 0) {
814                 connman_error("Failed to register cellular device");
815                 connman_device_unref(device);
816                 return;
817         }
818
819         modem->device = device;
820
821         return;
822 }
823
824 static void __remove_connman_device(struct telephony_modem *modem)
825 {
826         DBG("modem %p path %s device %p", modem, modem->path, modem->device);
827
828         if (modem->device == NULL)
829                 return;
830
831         __remove_connman_networks(modem->device);
832
833         connman_device_unregister(modem->device);
834         connman_device_unref(modem->device);
835
836         modem->device = NULL;
837
838         return;
839 }
840
841 static void __remove_connman_networks(struct connman_device *device)
842 {
843         GHashTableIter iter;
844         gpointer key, value;
845         GSList *info_list = NULL;
846         GSList *list;
847
848         if (network_hash == NULL)
849                 return;
850
851         g_hash_table_iter_init(&iter, network_hash);
852
853         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
854                 struct telephony_network *info = value;
855
856                 if (connman_network_get_device(info->network) != device)
857                         continue;
858
859                 info_list = g_slist_append(info_list, info);
860         }
861
862         for (list = info_list; list != NULL; list = list->next) {
863                 struct telephony_network *info = list->data;
864                 connman_device_remove_network(device, info->network);
865         }
866
867         g_slist_free(info_list);
868 }
869
870 static void __set_device_powered(struct telephony_modem *modem,
871                                         gboolean powered)
872 {
873         DBG("set modem(%s) powered(%d)", modem->path, powered);
874
875         if (modem->device)
876                 connman_device_set_powered(modem->device, powered);
877
878         return;
879 }
880
881 static int __check_device_powered(const char *path, gboolean powered)
882 {
883         struct telephony_modem *modem = g_hash_table_lookup(modem_hash, path);
884
885         if (modem == NULL)
886                 return -ENODEV;
887
888         DBG("check modem (%s) powered (%d)", modem->path, modem->powered);
889
890         if (modem->powered == powered)
891                 return -EALREADY;
892
893         return 0;
894 }
895
896 static gboolean __check_network_available(struct connman_network *network)
897 {
898         if (network == NULL || connman_network_get_device(network) == NULL) {
899                 DBG("Modem or network was removed");
900                 return FALSE;
901         }
902
903         return TRUE;
904 }
905
906 static int __add_context(struct connman_device *device, const char *path,
907                                 DBusMessageIter *prop)
908 {
909         char *ident;
910         gboolean active = FALSE;
911
912         struct telephony_modem *modem = connman_device_get_data(device);
913         struct connman_network *network;
914         struct telephony_network *info;
915
916         DBG("modem %p device %p path %s", modem, device, path);
917
918         ident = __get_ident(path);
919
920         network = connman_device_get_network(device, ident);
921         if (network != NULL)
922                 return -EALREADY;
923
924         info = g_hash_table_lookup(network_hash, path);
925         if (info != NULL) {
926                 DBG("path %p already exists with device %p", path,
927                         connman_network_get_device(info->network));
928
929                 if (connman_network_get_device(info->network))
930                         return -EALREADY;
931
932                 g_hash_table_remove(network_hash, path);
933         }
934
935         network = connman_network_create(ident, CONNMAN_NETWORK_TYPE_CELLULAR);
936         if (network == NULL)
937                 return -ENOMEM;
938
939         info = (struct telephony_network *)g_try_malloc(
940                                         sizeof(struct telephony_network));
941         if (info == NULL) {
942                 connman_network_unref(network);
943                 return -ENOMEM;
944         }
945
946         memset(info, 0, sizeof(struct telephony_network));
947
948         info->path = g_strdup(path);
949
950         connman_ipaddress_clear(info->ipv4_address);
951         connman_ipaddress_clear(info->ipv6_address);
952         info->network = network;
953
954         connman_network_set_string(network, "Path", path);
955         connman_network_set_name(network, path);
956
957         __create_service(network);
958
959         g_hash_table_insert(network_hash, g_strdup(path), info);
960
961         connman_network_set_available(network, TRUE);
962         connman_network_set_index(network, -1);
963         connman_network_set_bool(network, "Roaming", modem->s_service->roaming);
964
965         if (connman_device_add_network(device, network) != 0) {
966                 g_hash_table_remove(network_hash, path);
967                 return -EIO;
968         }
969
970         active = __set_network_ipconfig(info, prop);
971
972         if (active && (connman_network_get_connecting(network) ||
973                                 connman_network_get_associating(network)))
974                 __set_network_connected(info, active);
975
976         return 0;
977 }
978
979 static void __create_service(struct connman_network *network)
980 {
981         const char *path;
982         char *group;
983
984         DBG("");
985
986         path = connman_network_get_string(network, "Path");
987
988         group = __get_ident(path);
989
990         connman_network_set_group(network, group);
991 }
992
993 static gboolean __set_network_ipconfig(struct telephony_network *network,
994                                         DBusMessageIter *dict)
995 {
996         DBG("set network info");
997
998         gboolean active = FALSE;
999         char *dev_name = NULL, *proxy_addr = NULL;
1000         char *ipv4_addr = NULL, *ipv4_gw = NULL, *ipv4_netmask = NULL,
1001                                         *ipv4_dns1 = NULL, *ipv4_dns2 = NULL;
1002         char *ipv6_addr = NULL, *ipv6_gw = NULL, *ipv6_netmask = NULL,
1003                                         *ipv6_dns1 = NULL, *ipv6_dns2 = NULL;
1004         int index;
1005         int dns_flag = 0;
1006
1007         while (dbus_message_iter_get_arg_type(dict) != DBUS_TYPE_INVALID) {
1008                 DBusMessageIter entry;
1009                 const char *key, *tmp;
1010
1011                 dbus_message_iter_recurse(dict, &entry);
1012                 dbus_message_iter_get_basic(&entry, &key);
1013
1014                 dbus_message_iter_next(&entry);
1015
1016                 DBG("key (%s)", key);
1017
1018                 if (g_str_equal(key, "dev_name") == TRUE) {
1019                         dbus_message_iter_get_basic(&entry, &dev_name);
1020                         DBG("dev_name (%s)", dev_name);
1021                 } else if (g_str_equal(key, "proxy") == TRUE) {
1022                         dbus_message_iter_get_basic(&entry, &proxy_addr);
1023                 } else if (g_str_equal(key, "ipv4_address") == TRUE) {
1024                         dbus_message_iter_get_basic(&entry, &ipv4_addr);
1025                         DBG("ipv4 address (%s)", ipv4_addr);
1026                 } else if (g_str_equal(key, "ipv4_gateway") == TRUE) {
1027                         dbus_message_iter_get_basic(&entry, &ipv4_gw);
1028                 } else if (g_str_equal(key, "ipv4_netmask") == TRUE) {
1029                         dbus_message_iter_get_basic(&entry, &ipv4_netmask);
1030                 } else if (g_str_equal(key, "ipv4_dns1") == TRUE) {
1031                         dbus_message_iter_get_basic(&entry, &ipv4_dns1);
1032                 } else if (g_str_equal(key, "ipv4_dns2") == TRUE) {
1033                         dbus_message_iter_get_basic(&entry, &ipv4_dns2);
1034                 } else if (g_str_equal(key, "ipv6_address") == TRUE) {
1035                         dbus_message_iter_get_basic(&entry, &ipv6_addr);
1036                         DBG("ipv6 address (%s)", ipv6_addr);
1037                 } else if (g_str_equal(key, "ipv6_gateway") == TRUE) {
1038                         dbus_message_iter_get_basic(&entry, &ipv6_gw);
1039                 } else if (g_str_equal(key, "ipv6_netmask") == TRUE) {
1040                         dbus_message_iter_get_basic(&entry, &ipv6_netmask);
1041                 } else if (g_str_equal(key, "ipv6_dns1") == TRUE) {
1042                         dbus_message_iter_get_basic(&entry, &ipv6_dns1);
1043                 } else if (g_str_equal(key, "ipv6_dns2") == TRUE) {
1044                         dbus_message_iter_get_basic(&entry, &ipv6_dns2);
1045                 } else if (g_str_equal(key, "active") == TRUE) {
1046                         dbus_message_iter_get_basic(&entry, &tmp);
1047                         DBG("active (%s)", tmp);
1048                         active = STRING2BOOL(tmp);
1049                 }
1050
1051                 dbus_message_iter_next(dict);
1052         }
1053
1054         /* interface index set */
1055         if (dev_name == NULL)
1056                 dev_name = "";
1057
1058         if (!g_str_equal(dev_name, "")) {
1059                 index = connman_inet_ifindex(dev_name);
1060                 DBG("interface %s, index %d", dev_name, index);
1061                 connman_network_set_index(network->network, index);
1062         }
1063
1064         /* proxy set */
1065         if (proxy_addr == NULL)
1066                 proxy_addr = "";
1067
1068         DBG("proxy (%s) is set", proxy_addr);
1069         connman_network_set_proxy(network->network, proxy_addr);
1070
1071         /* ipv4 set */
1072         if (ipv4_addr == NULL)
1073                 ipv4_addr = "0.0.0.0";
1074
1075         if (g_str_equal(ipv4_addr, "0.0.0.0")) {
1076                 network->ipv4_method = CONNMAN_IPCONFIG_METHOD_OFF;
1077         } else {
1078                 network->ipv4_method = CONNMAN_IPCONFIG_METHOD_FIXED;
1079                 network->ipv4_address =
1080                         connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4);
1081                 if (network->ipv4_address == NULL)
1082                         return FALSE;
1083
1084                 connman_ipaddress_set_ipv4(network->ipv4_address, ipv4_addr,
1085                                                 ipv4_netmask, ipv4_gw);
1086
1087                 if (ipv4_dns1 == NULL)
1088                         ipv4_dns1 = "0.0.0.0";
1089                 if (ipv4_dns2 == NULL)
1090                         ipv4_dns2 = "0.0.0.0";
1091
1092                 if (g_str_equal(ipv4_dns1, "0.0.0.0"))
1093                         dns_flag += 1;
1094
1095                 if (g_str_equal(ipv4_dns2, "0.0.0.0"))
1096                         dns_flag += 2;
1097
1098                 gchar *nameservers = NULL;
1099
1100                 switch (dns_flag) {
1101                 case 0:
1102                         nameservers = g_strdup_printf("%s %s", ipv4_dns1,
1103                                                                 ipv4_dns2);
1104                         break;
1105                 case 1:
1106                         nameservers = g_strdup_printf("%s", ipv4_dns2);
1107                         break;
1108                 case 2:
1109                         nameservers = g_strdup_printf("%s", ipv4_dns1);
1110                 }
1111
1112                 connman_network_set_nameservers(network->network, nameservers);
1113                 g_free(nameservers);
1114         }
1115
1116         /* ipv6 set */
1117         if (ipv6_addr == NULL)
1118                 ipv6_addr = "::";
1119
1120         if (g_str_equal(ipv6_addr, "::")) {
1121                 network->ipv6_method = CONNMAN_IPCONFIG_METHOD_OFF;
1122         } else {
1123                 network->ipv6_method = CONNMAN_IPCONFIG_METHOD_FIXED;
1124                 unsigned char prefix_length = 64;
1125                 network->ipv6_address =
1126                         connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV6);
1127                 if (network->ipv6_address == NULL)
1128                         return FALSE;
1129
1130                 connman_ipaddress_set_ipv6(network->ipv6_address, ipv6_addr,
1131                                                 prefix_length, ipv6_gw);
1132
1133                 dns_flag = 0;
1134
1135                 if (ipv6_dns1 == NULL)
1136                         ipv6_dns1 = "::";
1137                 if (ipv6_dns2 == NULL)
1138                         ipv6_dns2 = "::";
1139
1140                 if (g_str_equal(ipv6_dns1, "::"))
1141                         dns_flag += 1;
1142
1143                 if (g_str_equal(ipv6_dns2, "::"))
1144                         dns_flag += 2;
1145
1146                 gchar *nameservers = NULL;
1147
1148                 switch (dns_flag) {
1149                 case 0:
1150                         nameservers = g_strdup_printf("%s %s", ipv6_dns1,
1151                                                                 ipv6_dns2);
1152                         break;
1153                 case 1:
1154                         nameservers = g_strdup_printf("%s", ipv6_dns2);
1155                         break;
1156                 case 2:
1157                         nameservers = g_strdup_printf("%s", ipv6_dns1);
1158                 }
1159
1160                 connman_network_set_nameservers(network->network, nameservers);
1161                 g_free(nameservers);
1162         }
1163
1164         if (active)
1165                 connman_network_set_associating(network->network, TRUE);
1166
1167         return active;
1168 }
1169
1170 static void __set_network_connected(struct telephony_network *network,
1171                                         gboolean connected)
1172 {
1173         gboolean setip = FALSE;
1174
1175         DBG("network %p connected %d", network, connected);
1176
1177         switch (network->ipv4_method) {
1178         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1179         case CONNMAN_IPCONFIG_METHOD_OFF:
1180         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1181         case CONNMAN_IPCONFIG_METHOD_AUTO:
1182                 setip = TRUE;
1183                 break;
1184
1185         case CONNMAN_IPCONFIG_METHOD_FIXED:
1186                 connman_network_set_ipv4_method(network->network,
1187                                                         network->ipv4_method);
1188                 connman_network_set_ipaddress(network->network,
1189                                                         network->ipv4_address);
1190                 setip = TRUE;
1191                 break;
1192
1193         case CONNMAN_IPCONFIG_METHOD_DHCP:
1194                 connman_network_set_ipv4_method(network->network,
1195                                                         network->ipv4_method);
1196                 setip = TRUE;
1197                 break;
1198         }
1199
1200         switch (network->ipv6_method) {
1201         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1202         case CONNMAN_IPCONFIG_METHOD_OFF:
1203         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1204         case CONNMAN_IPCONFIG_METHOD_DHCP:
1205                 break;
1206         case CONNMAN_IPCONFIG_METHOD_AUTO:
1207                 connman_network_set_ipv6_method(network->network,
1208                                                         network->ipv6_method);
1209                 setip = TRUE;
1210                 break;
1211
1212         case CONNMAN_IPCONFIG_METHOD_FIXED:
1213                 connman_network_set_ipv6_method(network->network,
1214                                                         network->ipv6_method);
1215                 connman_network_set_ipaddress(network->network,
1216                                                         network->ipv6_address);
1217                 setip = TRUE;
1218                 break;
1219         }
1220
1221         if (setip == TRUE)
1222                 connman_network_set_connected(network->network, connected);
1223
1224         return;
1225 }
1226
1227 static char *__get_ident(const char *path)
1228 {
1229         char *pos;
1230
1231         if (*path != '/')
1232                 return NULL;
1233
1234         pos = strrchr(path, '/');
1235         if (pos == NULL)
1236                 return NULL;
1237
1238         return pos + 1;
1239 }
1240
1241 static gboolean __changed_modem(DBusConnection *connection,
1242                                 DBusMessage *message, void *user_data)
1243 {
1244         DBG("modem changed signal");
1245
1246         DBusMessageIter args, dict;
1247         const char *path = dbus_message_get_path(message);
1248         struct telephony_modem *modem;
1249
1250         DBG("modem path %s", path);
1251
1252         modem = g_hash_table_lookup(modem_hash, path);
1253         if (modem == NULL) {
1254                 DBG("modem object does not exists");
1255                 return TRUE;
1256         }
1257
1258         DBG("message signature (%s)", dbus_message_get_signature(message));
1259
1260         if (dbus_message_iter_init(message, &args) == FALSE) {
1261                 DBG("error to read message");
1262                 return TRUE;
1263         }
1264
1265         dbus_message_iter_recurse(&args, &dict);
1266
1267         while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
1268                 DBusMessageIter entry;
1269                 const char *key, *tmp;
1270
1271                 dbus_message_iter_recurse(&dict, &entry);
1272                 dbus_message_iter_get_basic(&entry, &key);
1273
1274                 dbus_message_iter_next(&entry);
1275                 dbus_message_iter_get_basic(&entry, &tmp);
1276
1277                 DBG("key(%s), value(%s)", key, tmp);
1278
1279                 if (g_str_equal(key, "powered") == TRUE) {
1280                         modem->powered = STRING2BOOL(tmp);
1281                 } else if (g_str_equal(key, "operator") == TRUE) {
1282                         modem->operator = g_strdup(tmp);
1283                 } else if (g_str_equal(key, "sim_init") == TRUE) {
1284                         modem->sim_init = STRING2BOOL(tmp);
1285                 } else if (g_str_equal(key, "flight_mode") == TRUE) {
1286                         modem->flight_mode = STRING2BOOL(tmp);
1287                 } else if (g_str_equal(key, "roaming_allowed") == TRUE) {
1288                         modem->roaming_allowed = STRING2BOOL(tmp);
1289                 } else if (g_str_equal(key, "data_allowed") == TRUE) {
1290                         modem->data_allowed = STRING2BOOL(tmp);
1291                 }
1292
1293                 dbus_message_iter_next(&dict);
1294         }
1295
1296         if (modem->device == NULL)
1297                 __add_connman_device(path, modem->operator);
1298
1299         __set_device_powered(modem, modem->powered);
1300
1301         if (modem->powered != TRUE) {
1302                 DBG("modem is not powered");
1303                 return TRUE;
1304         }
1305
1306         if (!modem->s_service) {
1307                 __request_get_services(modem->path);
1308                 return TRUE;
1309         }
1310
1311         if (modem->flight_mode || !modem->data_allowed) {
1312                 DBG("modem(%s) flight mode(%d) data allowed(%d)",
1313                         modem->path, modem->flight_mode, modem->data_allowed);
1314                 return TRUE;
1315         }
1316
1317         return TRUE;
1318 }
1319
1320 static gboolean __added_modem(DBusConnection *connection,
1321                                 DBusMessage *message, void *user_data)
1322 {
1323         DBG("modem added signal");
1324
1325         const char *modem_path = NULL;
1326         DBusMessageIter args, dict, tmp;
1327
1328         DBG("message signature (%s)", dbus_message_get_signature(message));
1329         if (dbus_message_iter_init(message, &args) == FALSE) {
1330                 DBG("error to read message");
1331                 return TRUE;
1332         }
1333
1334         dbus_message_iter_recurse(&args, &dict);
1335         memcpy(&tmp, &dict, sizeof(struct DBusMessageIter));
1336
1337         while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) {
1338                 DBusMessageIter entry;
1339                 const char *key, *value;
1340
1341                 dbus_message_iter_recurse(&tmp, &entry);
1342                 dbus_message_iter_get_basic(&entry, &key);
1343
1344                 dbus_message_iter_next(&entry);
1345                 dbus_message_iter_get_basic(&entry, &value);
1346
1347                 DBG("key (%s) value(%s)", key, value);
1348
1349                 if (g_str_equal(key, "path") == TRUE)
1350                         modem_path = g_strdup(value);
1351
1352                 dbus_message_iter_next(&tmp);
1353         }
1354
1355         if (modem_path != NULL)
1356                 __add_modem(modem_path, &dict);
1357
1358         return TRUE;
1359 }
1360
1361 static gboolean __removed_modem(DBusConnection *connection,
1362                                         DBusMessage *message, void *user_data)
1363 {
1364         DBG("modem removed signal");
1365
1366         DBusMessageIter iter;
1367         const char *modem_path;
1368
1369         if (dbus_message_iter_init(message, &iter) == FALSE) {
1370                 DBG("error to read message");
1371                 return TRUE;
1372         }
1373
1374         dbus_message_iter_get_basic(&iter, &modem_path);
1375         g_hash_table_remove(modem_hash, modem_path);
1376
1377         return TRUE;
1378 }
1379
1380 static gboolean __changed_service(DBusConnection *connection,
1381                                         DBusMessage *message, void *user_data)
1382 {
1383         DBG("service changed signal");
1384
1385         DBusMessageIter args, dict;
1386         const char *service_path = dbus_message_get_path(message);
1387         struct telephony_modem *modem;
1388         struct telephony_service *s_service;
1389         gboolean roaming_option = TRUE;
1390
1391         DBG("service path %s", service_path);
1392
1393         s_service = g_hash_table_lookup(service_hash, service_path);
1394         if (s_service == NULL) {
1395                 DBG("service object does not exists");
1396                 return TRUE;
1397         }
1398
1399         modem = s_service->p_modem;
1400         if (modem == NULL) {
1401                 DBG("modem object does not exists");
1402                 return TRUE;
1403         }
1404
1405         DBG("message signature (%s)", dbus_message_get_signature(message));
1406
1407         if (dbus_message_iter_init(message, &args) == FALSE) {
1408                 DBG("error to read message");
1409                 return TRUE;
1410         }
1411
1412         dbus_message_iter_recurse(&args, &dict);
1413
1414         while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
1415                 DBusMessageIter entry;
1416                 const char *key, *tmp;
1417
1418                 dbus_message_iter_recurse(&dict, &entry);
1419                 dbus_message_iter_get_basic(&entry, &key);
1420
1421                 dbus_message_iter_next(&entry);
1422                 dbus_message_iter_get_basic(&entry, &tmp);
1423
1424                 DBG("key(%s), value(%s)", key, tmp);
1425
1426                 if (g_str_equal(key, "roaming") == TRUE) {
1427                         s_service->roaming = STRING2BOOL(tmp);
1428                 } else if (g_str_equal(key, "act") == TRUE) {
1429                         s_service->act = g_strdup(tmp);
1430                 } else if (g_str_equal(key, "ps_attached") == TRUE) {
1431                         s_service->ps_attached = STRING2BOOL(tmp);
1432                 }
1433
1434                 dbus_message_iter_next(&dict);
1435         }
1436
1437         roaming_option &= (!s_service->roaming && !modem->roaming_allowed)
1438                                 || modem->roaming_allowed;
1439
1440         return TRUE;
1441 }
1442
1443
1444 static gboolean __added_service(DBusConnection *connection,
1445                                 DBusMessage *message, void *user_data)
1446 {
1447         DBG("service added signal");
1448
1449         const char *path = dbus_message_get_path(message);
1450         const char *service_path = NULL;
1451         DBusMessageIter args, dict, tmp;
1452         struct telephony_modem *modem;
1453
1454         modem = g_hash_table_lookup(modem_hash, path);
1455         if (modem == NULL || modem->device == NULL)
1456                 return TRUE;
1457
1458         DBG("message signature (%s)", dbus_message_get_signature(message));
1459         if (dbus_message_iter_init(message, &args) == FALSE) {
1460                 DBG("error to read message");
1461                 return TRUE;
1462         }
1463
1464         dbus_message_iter_recurse(&args, &dict);
1465         memcpy(&tmp, &dict, sizeof(struct DBusMessageIter));
1466
1467         while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) {
1468                 DBusMessageIter entry;
1469                 const char *key, *value;
1470
1471                 dbus_message_iter_recurse(&tmp, &entry);
1472                 dbus_message_iter_get_basic(&entry, &key);
1473
1474                 dbus_message_iter_next(&entry);
1475                 dbus_message_iter_get_basic(&entry, &value);
1476
1477                 DBG("key (%s) value(%s)", key, value);
1478
1479                 if (g_str_equal(key, "path") == TRUE) {
1480                         service_path = g_strdup(value);
1481                 }
1482
1483                 dbus_message_iter_next(&tmp);
1484         }
1485
1486         if (service_path != NULL)
1487                 __add_service(modem, service_path, &dict);
1488
1489         return TRUE;
1490 }
1491
1492 static gboolean __removed_service(DBusConnection *connection,
1493                                         DBusMessage *message, void *user_data)
1494 {
1495         DBG("service removed signal");
1496
1497         DBusMessageIter iter;
1498         const char *service_path;
1499
1500         if (dbus_message_iter_init(message, &iter) == FALSE) {
1501                 DBG("error to read message");
1502                 return TRUE;
1503         }
1504
1505         dbus_message_iter_get_basic(&iter, &service_path);
1506         g_hash_table_remove(service_hash, service_path);
1507
1508         return TRUE;
1509 }
1510
1511 static gboolean __changed_context(DBusConnection *connection,
1512                                         DBusMessage *message, void *user_data)
1513 {
1514         DBG("network changed signal");
1515
1516         gboolean active = FALSE;
1517         const char *path = dbus_message_get_path(message);
1518         struct telephony_network *info;
1519         DBusMessageIter args, dict;
1520
1521         DBG("path %s", path);
1522         info = g_hash_table_lookup(network_hash, path);
1523         if (info == NULL)
1524                 return TRUE;
1525
1526         if (!__check_network_available(info->network)) {
1527                 g_hash_table_remove(network_hash, path);
1528                 return TRUE;
1529         }
1530
1531         if (dbus_message_iter_init(message, &args) == FALSE) {
1532                 DBG("error to read message");
1533                 return TRUE;
1534         }
1535
1536         dbus_message_iter_recurse(&args, &dict);
1537
1538         active = __set_network_ipconfig(info, &dict);
1539
1540         if (active == FALSE)
1541                 __set_network_connected(info, active);
1542         else if ((connman_network_get_connecting(info->network) ||
1543                         connman_network_get_associating(info->network)))
1544                 __set_network_connected(info, active);
1545
1546         return TRUE;
1547 }
1548
1549 static gboolean __added_context(DBusConnection *connection,
1550                                         DBusMessage *message, void *user_data)
1551 {
1552         DBG("network added signal");
1553
1554         DBusMessageIter args, dict, tmp;
1555         const char *path = dbus_message_get_path(message);
1556         const char *network_path = NULL;
1557         struct telephony_service *service = NULL;
1558         struct telephony_modem *modem = NULL;
1559
1560         service = g_hash_table_lookup(service_hash, path);
1561         if (service == NULL || service->p_modem == NULL)
1562                 return TRUE;
1563
1564         modem = service->p_modem;
1565         if (modem == NULL || modem->device == NULL)
1566                 return TRUE;
1567
1568         DBG("message signature (%s)", dbus_message_get_signature(message));
1569         if (dbus_message_iter_init(message, &args) == FALSE) {
1570                 DBG("error to read message");
1571                 return TRUE;
1572         }
1573
1574         dbus_message_iter_recurse(&args, &dict);
1575         memcpy(&tmp, &dict, sizeof(struct DBusMessageIter));
1576
1577         while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) {
1578                 DBusMessageIter entry;
1579                 const char *key, *value;
1580
1581                 dbus_message_iter_recurse(&tmp, &entry);
1582                 dbus_message_iter_get_basic(&entry, &key);
1583
1584                 dbus_message_iter_next(&entry);
1585                 dbus_message_iter_get_basic(&entry, &value);
1586
1587                 DBG("key (%s) value(%s)", key, value);
1588
1589                 if (g_str_equal(key, "path") == TRUE)
1590                         network_path = g_strdup(value);
1591
1592                 dbus_message_iter_next(&tmp);
1593         }
1594
1595         if (network_path != NULL)
1596                 __add_context(modem->device, network_path, &dict);
1597
1598         return TRUE;
1599 }
1600
1601 static gboolean __removed_context(DBusConnection *connection,
1602                                         DBusMessage *message, void *user_data)
1603 {
1604         DBG("network removed signal");
1605
1606         DBusMessageIter iter;
1607         const char *path = dbus_message_get_path(message);
1608         const char *network_path = NULL;
1609         struct telephony_service *service = NULL;
1610
1611         service = g_hash_table_lookup(service_hash, path);
1612         if (service == NULL || service->p_modem == NULL)
1613                 return TRUE;
1614
1615         if (dbus_message_iter_init(message, &iter) == FALSE) {
1616                 DBG("error to read message");
1617                 return TRUE;
1618         }
1619
1620         dbus_message_iter_get_basic(&iter, &network_path);
1621         g_hash_table_remove(network_hash, network_path);
1622
1623         return TRUE;
1624 }
1625
1626 /* telephony initialization */
1627 static guint watch;
1628 static guint modem_watch;
1629 static guint modem_added_watch;
1630 static guint modem_removed_watch;
1631 static guint service_watch;
1632 static guint service_added_watch;
1633 static guint service_removed_watch;
1634 static guint context_watch;
1635 static guint context_added_watch;
1636 static guint context_removed_watch;
1637
1638 static int telephony_init(void)
1639 {
1640         DBG("telephony plugin");
1641         int err;
1642
1643         connection = connman_dbus_get_connection();
1644         if (connection == NULL)
1645                 return -EIO;
1646
1647         /* telephony watch */
1648         watch = g_dbus_add_service_watch(connection, PS_DBUS_SERVICE,
1649                                         telephony_connect, telephony_disconnect,
1650                                         NULL, NULL);
1651
1652         modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1653                                                 PS_MODEM_INTERFACE,
1654                                                 PROPERTY_CHANGED,
1655                                                 __changed_modem, NULL, NULL);
1656
1657         modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1658                                                 PS_MASTER_INTERFACE,
1659                                                 MODEM_ADDED, __added_modem,
1660                                                 NULL, NULL);
1661
1662         modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1663                                                 PS_MASTER_INTERFACE,
1664                                                 MODEM_REMOVED, __removed_modem,
1665                                                 NULL, NULL);
1666
1667         service_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1668                                                 PS_SERVICE_INTERFACE,
1669                                                 PROPERTY_CHANGED,
1670                                                 __changed_service,
1671                                                 NULL, NULL);
1672
1673         service_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1674                                                 PS_MODEM_INTERFACE,
1675                                                 SERVICE_ADDED, __added_service,
1676                                                 NULL, NULL);
1677
1678         service_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1679                                                 PS_MODEM_INTERFACE,
1680                                                 SERVICE_REMOVED,
1681                                                 __removed_service,
1682                                                 NULL, NULL);
1683
1684         context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1685                                                 PS_CONTEXT_INTERFACE,
1686                                                 PROPERTY_CHANGED,
1687                                                 __changed_context,
1688                                                 NULL, NULL);
1689
1690         context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1691                                                 PS_SERVICE_INTERFACE,
1692                                                 CONTEXT_ADDED, __added_context,
1693                                                 NULL, NULL);
1694
1695         context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1696                                                 PS_SERVICE_INTERFACE,
1697                                                 CONTEXT_REMOVED,
1698                                                 __removed_context,
1699                                                 NULL, NULL);
1700
1701         if (watch == 0 || modem_watch == 0 || modem_added_watch == 0
1702                         || modem_removed_watch == 0 || service_watch == 0
1703                         || service_added_watch == 0 || context_watch == 0
1704                         || service_removed_watch == 0
1705                         || context_added_watch == 0
1706                         || context_removed_watch == 0) {
1707                 err = -EIO;
1708                 goto remove;
1709         }
1710
1711         err = connman_network_driver_register(&network_driver);
1712         if (err < 0)
1713                 goto remove;
1714
1715         err = connman_device_driver_register(&modem_driver);
1716         if (err < 0) {
1717                 connman_network_driver_unregister(&network_driver);
1718                 goto remove;
1719         }
1720
1721         err = connman_technology_driver_register(&tech_driver);
1722         if (err < 0) {
1723                 connman_device_driver_unregister(&modem_driver);
1724                 connman_network_driver_unregister(&network_driver);
1725                 goto remove;
1726         }
1727
1728         return 0;
1729
1730 remove:
1731         g_dbus_remove_watch(connection, watch);
1732         g_dbus_remove_watch(connection, modem_watch);
1733         g_dbus_remove_watch(connection, modem_added_watch);
1734         g_dbus_remove_watch(connection, modem_removed_watch);
1735         g_dbus_remove_watch(connection, service_watch);
1736         g_dbus_remove_watch(connection, service_added_watch);
1737         g_dbus_remove_watch(connection, service_removed_watch);
1738         g_dbus_remove_watch(connection, context_watch);
1739         g_dbus_remove_watch(connection, context_added_watch);
1740         g_dbus_remove_watch(connection, context_removed_watch);
1741
1742         dbus_connection_unref(connection);
1743         return err;
1744 }
1745
1746 static void telephony_exit(void)
1747 {
1748         g_dbus_remove_watch(connection, watch);
1749         g_dbus_remove_watch(connection, modem_watch);
1750         g_dbus_remove_watch(connection, modem_added_watch);
1751         g_dbus_remove_watch(connection, modem_removed_watch);
1752         g_dbus_remove_watch(connection, service_watch);
1753         g_dbus_remove_watch(connection, service_added_watch);
1754         g_dbus_remove_watch(connection, service_removed_watch);
1755         g_dbus_remove_watch(connection, context_watch);
1756         g_dbus_remove_watch(connection, context_added_watch);
1757         g_dbus_remove_watch(connection, context_removed_watch);
1758
1759         telephony_disconnect(connection, NULL);
1760
1761         connman_device_driver_unregister(&modem_driver);
1762         connman_network_driver_unregister(&network_driver);
1763
1764         dbus_connection_unref(connection);
1765 }
1766
1767 CONNMAN_PLUGIN_DEFINE(telephony, "Samsung Telephony Framework plug-in", VERSION,
1768                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, telephony_init, telephony_exit)