technology: return a reply even if there are no devices in the technology list.
[platform/upstream/connman.git] / src / technology.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <string.h>
28
29 #include <gdbus.h>
30
31 #include "connman.h"
32
33 static DBusConnection *connection;
34
35 static GSList *technology_list = NULL;
36
37 static connman_bool_t global_offlinemode;
38
39 struct connman_rfkill {
40         unsigned int index;
41         enum connman_service_type type;
42         connman_bool_t softblock;
43         connman_bool_t hardblock;
44 };
45
46 enum connman_technology_state {
47         CONNMAN_TECHNOLOGY_STATE_UNKNOWN   = 0,
48         CONNMAN_TECHNOLOGY_STATE_OFFLINE   = 1,
49         CONNMAN_TECHNOLOGY_STATE_ENABLED   = 2,
50         CONNMAN_TECHNOLOGY_STATE_CONNECTED = 3,
51 };
52
53 struct connman_technology {
54         int refcount;
55         enum connman_service_type type;
56         enum connman_technology_state state;
57         char *path;
58         GHashTable *rfkill_list;
59         GSList *device_list;
60         int enabled;
61         char *regdom;
62
63         connman_bool_t tethering;
64         char *tethering_ident;
65         char *tethering_passphrase;
66
67         connman_bool_t enable_persistent; /* Save the tech state */
68
69         struct connman_technology_driver *driver;
70         void *driver_data;
71
72         DBusMessage *pending_reply;
73         guint pending_timeout;
74 };
75
76 static GSList *driver_list = NULL;
77
78 static gint compare_priority(gconstpointer a, gconstpointer b)
79 {
80         const struct connman_technology_driver *driver1 = a;
81         const struct connman_technology_driver *driver2 = b;
82
83         return driver2->priority - driver1->priority;
84 }
85
86 /**
87  * connman_technology_driver_register:
88  * @driver: Technology driver definition
89  *
90  * Register a new technology driver
91  *
92  * Returns: %0 on success
93  */
94 int connman_technology_driver_register(struct connman_technology_driver *driver)
95 {
96         GSList *list;
97         struct connman_technology *technology;
98
99         DBG("driver %p name %s", driver, driver->name);
100
101         driver_list = g_slist_insert_sorted(driver_list, driver,
102                                                         compare_priority);
103
104         for (list = technology_list; list; list = list->next) {
105                 technology = list->data;
106
107                 if (technology->driver != NULL)
108                         continue;
109
110                 if (technology->type == driver->type)
111                         technology->driver = driver;
112         }
113
114         return 0;
115 }
116
117 /**
118  * connman_technology_driver_unregister:
119  * @driver: Technology driver definition
120  *
121  * Remove a previously registered technology driver
122  */
123 void connman_technology_driver_unregister(struct connman_technology_driver *driver)
124 {
125         GSList *list;
126         struct connman_technology *technology;
127
128         DBG("driver %p name %s", driver, driver->name);
129
130         for (list = technology_list; list; list = list->next) {
131                 technology = list->data;
132
133                 if (technology->driver == NULL)
134                         continue;
135
136                 if (technology->type == driver->type) {
137                         technology->driver->remove(technology);
138                         technology->driver = NULL;
139                 }
140         }
141
142         driver_list = g_slist_remove(driver_list, driver);
143 }
144
145 static void tethering_changed(struct connman_technology *technology)
146 {
147         connman_bool_t tethering = technology->tethering;
148
149         connman_dbus_property_changed_basic(technology->path,
150                                 CONNMAN_TECHNOLOGY_INTERFACE, "Tethering",
151                                                 DBUS_TYPE_BOOLEAN, &tethering);
152 }
153
154 void connman_technology_tethering_notify(struct connman_technology *technology,
155                                                         connman_bool_t enabled)
156 {
157         GSList *list;
158
159         DBG("technology %p enabled %u", technology, enabled);
160
161         if (technology->tethering == enabled)
162                 return;
163
164         technology->tethering = enabled;
165
166         tethering_changed(technology);
167
168         if (enabled == TRUE)
169                 __connman_tethering_set_enabled();
170         else {
171                 for (list = technology_list; list; list = list->next) {
172                         struct connman_technology *other_tech = list->data;
173                         if (other_tech->tethering == TRUE)
174                                 break;
175                 }
176                 if (list == NULL)
177                         __connman_tethering_set_disabled();
178         }
179 }
180
181 static int set_tethering(struct connman_technology *technology,
182                                 connman_bool_t enabled)
183 {
184         const char *ident, *passphrase, *bridge;
185
186         ident = technology->tethering_ident;
187         passphrase = technology->tethering_passphrase;
188
189         if (technology->driver == NULL ||
190                         technology->driver->set_tethering == NULL)
191                 return -EOPNOTSUPP;
192
193         bridge = __connman_tethering_get_bridge();
194         if (bridge == NULL)
195                 return -EOPNOTSUPP;
196
197         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI &&
198             (ident == NULL || passphrase == NULL))
199                 return -EINVAL;
200
201         return technology->driver->set_tethering(technology, ident, passphrase,
202                                                         bridge, enabled);
203 }
204
205 void connman_technology_regdom_notify(struct connman_technology *technology,
206                                                         const char *alpha2)
207 {
208         DBG("");
209
210         if (alpha2 == NULL)
211                 connman_error("Failed to set regulatory domain");
212         else
213                 DBG("Regulatory domain set to %s", alpha2);
214
215         g_free(technology->regdom);
216         technology->regdom = g_strdup(alpha2);
217 }
218
219 int connman_technology_set_regdom(const char *alpha2)
220 {
221         GSList *list;
222
223         for (list = technology_list; list; list = list->next) {
224                 struct connman_technology *technology = list->data;
225
226                 if (technology->driver == NULL)
227                         continue;
228
229                 if (technology->driver->set_regdom)
230                         technology->driver->set_regdom(technology, alpha2);
231         }
232
233         return 0;
234 }
235
236 static void free_rfkill(gpointer data)
237 {
238         struct connman_rfkill *rfkill = data;
239
240         g_free(rfkill);
241 }
242
243 static const char *state2string(enum connman_technology_state state)
244 {
245         switch (state) {
246         case CONNMAN_TECHNOLOGY_STATE_UNKNOWN:
247                 break;
248         case CONNMAN_TECHNOLOGY_STATE_OFFLINE:
249                 return "offline";
250         case CONNMAN_TECHNOLOGY_STATE_ENABLED:
251                 return "enabled";
252         case CONNMAN_TECHNOLOGY_STATE_CONNECTED:
253                 return "connected";
254         }
255
256         return NULL;
257 }
258
259 static void state_changed(struct connman_technology *technology)
260 {
261         const char *str;
262
263         str = state2string(technology->state);
264         if (str == NULL)
265                 return;
266
267         connman_dbus_property_changed_basic(technology->path,
268                                 CONNMAN_TECHNOLOGY_INTERFACE, "State",
269                                                 DBUS_TYPE_STRING, &str);
270 }
271
272 static const char *get_name(enum connman_service_type type)
273 {
274         switch (type) {
275         case CONNMAN_SERVICE_TYPE_UNKNOWN:
276         case CONNMAN_SERVICE_TYPE_SYSTEM:
277         case CONNMAN_SERVICE_TYPE_GPS:
278         case CONNMAN_SERVICE_TYPE_VPN:
279         case CONNMAN_SERVICE_TYPE_GADGET:
280                 break;
281         case CONNMAN_SERVICE_TYPE_ETHERNET:
282                 return "Wired";
283         case CONNMAN_SERVICE_TYPE_WIFI:
284                 return "WiFi";
285         case CONNMAN_SERVICE_TYPE_WIMAX:
286                 return "WiMAX";
287         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
288                 return "Bluetooth";
289         case CONNMAN_SERVICE_TYPE_CELLULAR:
290                 return "Cellular";
291         }
292
293         return NULL;
294 }
295
296 static void load_state(struct connman_technology *technology)
297 {
298         GKeyFile *keyfile;
299         gchar *identifier;
300         GError *error = NULL;
301         connman_bool_t enable;
302
303         DBG("technology %p", technology);
304
305         keyfile = __connman_storage_load_global();
306         /* Fallback on disabling technology if file not found. */
307         if (keyfile == NULL) {
308                 technology->enable_persistent = FALSE;
309                 return;
310         }
311
312         identifier = g_strdup_printf("%s", get_name(technology->type));
313         if (identifier == NULL)
314                 goto done;
315
316         enable = g_key_file_get_boolean(keyfile, identifier, "Enable", &error);
317         if (error == NULL)
318                 technology->enable_persistent = enable;
319         else {
320                 technology->enable_persistent = FALSE;
321                 g_clear_error(&error);
322         }
323 done:
324         g_free(identifier);
325
326         g_key_file_free(keyfile);
327
328         return;
329 }
330
331 static void save_state(struct connman_technology *technology)
332 {
333         GKeyFile *keyfile;
334         gchar *identifier;
335
336         DBG("technology %p", technology);
337
338         keyfile = __connman_storage_load_global();
339         if (keyfile == NULL)
340                 keyfile = g_key_file_new();
341
342         identifier = g_strdup_printf("%s", get_name(technology->type));
343         if (identifier == NULL)
344                 goto done;
345
346         g_key_file_set_boolean(keyfile, identifier, "Enable",
347                                 technology->enable_persistent);
348
349 done:
350         g_free(identifier);
351
352         __connman_storage_save_global(keyfile);
353
354         g_key_file_free(keyfile);
355
356         return;
357 }
358
359 connman_bool_t __connman_technology_get_offlinemode(void)
360 {
361         return global_offlinemode;
362 }
363
364 static void connman_technology_save_offlinemode()
365 {
366         GKeyFile *keyfile;
367
368         keyfile = __connman_storage_load_global();
369         if (keyfile == NULL)
370                 keyfile = g_key_file_new();
371
372         g_key_file_set_boolean(keyfile, "global",
373                                         "OfflineMode", global_offlinemode);
374
375         __connman_storage_save_global(keyfile);
376
377         g_key_file_free(keyfile);
378
379         return;
380 }
381
382 static connman_bool_t connman_technology_load_offlinemode()
383 {
384         GKeyFile *keyfile;
385         GError *error = NULL;
386         connman_bool_t offlinemode;
387
388         /* If there is a error, we enable offlinemode */
389         keyfile = __connman_storage_load_global();
390         if (keyfile == NULL)
391                 return TRUE;
392
393         offlinemode = g_key_file_get_boolean(keyfile, "global",
394                                                 "OfflineMode", &error);
395         if (error != NULL) {
396                 offlinemode = TRUE;
397                 g_clear_error(&error);
398         }
399
400         g_key_file_free(keyfile);
401
402         return offlinemode;
403 }
404
405 static void append_properties(DBusMessageIter *iter,
406                 struct connman_technology *technology)
407 {
408         DBusMessageIter dict;
409         const char *str;
410
411         connman_dbus_dict_open(iter, &dict);
412
413         str = state2string(technology->state);
414         if (str != NULL)
415                 connman_dbus_dict_append_basic(&dict, "State",
416                                                 DBUS_TYPE_STRING, &str);
417
418         str = get_name(technology->type);
419         if (str != NULL)
420                 connman_dbus_dict_append_basic(&dict, "Name",
421                                                 DBUS_TYPE_STRING, &str);
422
423         str = __connman_service_type2string(technology->type);
424         if (str != NULL)
425                 connman_dbus_dict_append_basic(&dict, "Type",
426                                                 DBUS_TYPE_STRING, &str);
427
428         connman_dbus_dict_append_basic(&dict, "Tethering",
429                                         DBUS_TYPE_BOOLEAN,
430                                         &technology->tethering);
431
432         if (technology->tethering_ident != NULL)
433                 connman_dbus_dict_append_basic(&dict, "TetheringIdentifier",
434                                                 DBUS_TYPE_STRING,
435                                                 &technology->tethering_ident);
436
437         if (technology->tethering_passphrase != NULL)
438                 connman_dbus_dict_append_basic(&dict, "TetheringPassphrase",
439                                                 DBUS_TYPE_STRING,
440                                                 &technology->tethering_passphrase);
441
442         connman_dbus_dict_close(iter, &dict);
443 }
444
445 static void technology_added_signal(struct connman_technology *technology)
446 {
447         DBusMessage *signal;
448         DBusMessageIter iter;
449
450         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
451                         CONNMAN_MANAGER_INTERFACE, "TechnologyAdded");
452         if (signal == NULL)
453                 return;
454
455         dbus_message_iter_init_append(signal, &iter);
456         append_properties(&iter, technology);
457
458         dbus_connection_send(connection, signal, NULL);
459         dbus_message_unref(signal);
460 }
461
462 static void technology_removed_signal(struct connman_technology *technology)
463 {
464         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
465                         CONNMAN_MANAGER_INTERFACE, "TechnologyRemoved",
466                         DBUS_TYPE_OBJECT_PATH, technology->path);
467 }
468
469 static DBusMessage *get_properties(DBusConnection *conn,
470                                         DBusMessage *message, void *user_data)
471 {
472         struct connman_technology *technology = user_data;
473         DBusMessage *reply;
474         DBusMessageIter iter;
475
476         reply = dbus_message_new_method_return(message);
477         if (reply == NULL)
478                 return NULL;
479
480         dbus_message_iter_init_append(reply, &iter);
481         append_properties(&iter, technology);
482
483         return reply;
484 }
485
486 void __connman_technology_list_struct(DBusMessageIter *array)
487 {
488         GSList *list;
489         DBusMessageIter entry;
490
491         for (list = technology_list; list; list = list->next) {
492                 struct connman_technology *technology = list->data;
493
494                 if (technology->path == NULL)
495                         continue;
496
497                 dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
498                                 NULL, &entry);
499                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
500                                 &technology->path);
501                 append_properties(&entry, technology);
502                 dbus_message_iter_close_container(array, &entry);
503         }
504 }
505
506 static DBusMessage *set_property(DBusConnection *conn,
507                                         DBusMessage *msg, void *data)
508 {
509         struct connman_technology *technology = data;
510         DBusMessageIter iter, value;
511         const char *name;
512         int type;
513
514         DBG("conn %p", conn);
515
516         if (dbus_message_iter_init(msg, &iter) == FALSE)
517                 return __connman_error_invalid_arguments(msg);
518
519         dbus_message_iter_get_basic(&iter, &name);
520         dbus_message_iter_next(&iter);
521         dbus_message_iter_recurse(&iter, &value);
522
523         type = dbus_message_iter_get_arg_type(&value);
524
525         DBG("property %s", name);
526
527         if (g_str_equal(name, "Tethering") == TRUE) {
528                 int err;
529                 connman_bool_t tethering;
530
531                 if (type != DBUS_TYPE_BOOLEAN)
532                         return __connman_error_invalid_arguments(msg);
533
534                 dbus_message_iter_get_basic(&value, &tethering);
535
536                 if (technology->tethering == tethering)
537                         return __connman_error_in_progress(msg);
538
539                 err = set_tethering(technology, tethering);
540                 if (err < 0)
541                         return __connman_error_failed(msg, -err);
542
543         } else if (g_str_equal(name, "TetheringIdentifier") == TRUE) {
544                 const char *str;
545
546                 dbus_message_iter_get_basic(&value, &str);
547
548                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
549                         return __connman_error_not_supported(msg);
550
551                 technology->tethering_ident = g_strdup(str);
552         } else if (g_str_equal(name, "TetheringPassphrase") == TRUE) {
553                 const char *str;
554
555                 dbus_message_iter_get_basic(&value, &str);
556
557                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
558                         return __connman_error_not_supported(msg);
559
560                 if (strlen(str) < 8)
561                         return __connman_error_invalid_arguments(msg);
562
563                 technology->tethering_passphrase = g_strdup(str);
564         } else
565                 return __connman_error_invalid_property(msg);
566
567         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
568 }
569
570 static GDBusMethodTable technology_methods[] = {
571         { "GetProperties", "",   "a{sv}", get_properties },
572         { "SetProperty",   "sv", "",      set_property   },
573         { },
574 };
575
576 static GDBusSignalTable technology_signals[] = {
577         { "PropertyChanged", "sv" },
578         { },
579 };
580
581 static struct connman_technology *technology_find(enum connman_service_type type)
582 {
583         GSList *list;
584
585         DBG("type %d", type);
586
587         for (list = technology_list; list; list = list->next) {
588                 struct connman_technology *technology = list->data;
589
590                 if (technology->type == type)
591                         return technology;
592         }
593
594         return NULL;
595 }
596
597 static struct connman_technology *technology_get(enum connman_service_type type)
598 {
599         struct connman_technology *technology;
600         const char *str;
601         GSList *list;
602
603         DBG("type %d", type);
604
605         technology = technology_find(type);
606         if (technology != NULL) {
607                 __sync_fetch_and_add(&technology->refcount, 1);
608                 goto done;
609         }
610
611         str = __connman_service_type2string(type);
612         if (str == NULL)
613                 return NULL;
614
615         technology = g_try_new0(struct connman_technology, 1);
616         if (technology == NULL)
617                 return NULL;
618
619         technology->refcount = 1;
620
621         technology->type = type;
622         technology->path = g_strdup_printf("%s/technology/%s",
623                                                         CONNMAN_PATH, str);
624
625         technology->rfkill_list = g_hash_table_new_full(g_int_hash, g_int_equal,
626                                                         NULL, free_rfkill);
627         technology->device_list = NULL;
628
629         technology->pending_reply = NULL;
630         technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
631
632         load_state(technology);
633
634         if (g_dbus_register_interface(connection, technology->path,
635                                         CONNMAN_TECHNOLOGY_INTERFACE,
636                                         technology_methods, technology_signals,
637                                         NULL, technology, NULL) == FALSE) {
638                 connman_error("Failed to register %s", technology->path);
639                 g_free(technology);
640                 return NULL;
641         }
642
643         technology_list = g_slist_append(technology_list, technology);
644
645         technology_added_signal(technology);
646
647         if (technology->driver != NULL)
648                 goto done;
649
650         for (list = driver_list; list; list = list->next) {
651                 struct connman_technology_driver *driver = list->data;
652
653                 DBG("driver %p name %s", driver, driver->name);
654
655                 if (driver->type != technology->type)
656                         continue;
657
658                 if (driver->probe(technology) == 0) {
659                         technology->driver = driver;
660                         break;
661                 }
662         }
663
664 done:
665         DBG("technology %p", technology);
666
667         return technology;
668 }
669
670 static void technology_put(struct connman_technology *technology)
671 {
672         DBG("technology %p", technology);
673
674         if (__sync_fetch_and_sub(&technology->refcount, 1) != 1)
675                 return;
676
677         if (technology->driver) {
678                 technology->driver->remove(technology);
679                 technology->driver = NULL;
680         }
681
682         technology_list = g_slist_remove(technology_list, technology);
683
684         technology_removed_signal(technology);
685
686         g_dbus_unregister_interface(connection, technology->path,
687                                                 CONNMAN_TECHNOLOGY_INTERFACE);
688
689         g_slist_free(technology->device_list);
690         g_hash_table_destroy(technology->rfkill_list);
691
692         g_free(technology->path);
693         g_free(technology->regdom);
694         g_free(technology);
695 }
696
697 void __connman_technology_add_interface(enum connman_service_type type,
698                                 int index, const char *name, const char *ident)
699 {
700         struct connman_technology *technology;
701
702         switch (type) {
703         case CONNMAN_SERVICE_TYPE_UNKNOWN:
704         case CONNMAN_SERVICE_TYPE_SYSTEM:
705                 return;
706         case CONNMAN_SERVICE_TYPE_ETHERNET:
707         case CONNMAN_SERVICE_TYPE_WIFI:
708         case CONNMAN_SERVICE_TYPE_WIMAX:
709         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
710         case CONNMAN_SERVICE_TYPE_CELLULAR:
711         case CONNMAN_SERVICE_TYPE_GPS:
712         case CONNMAN_SERVICE_TYPE_VPN:
713         case CONNMAN_SERVICE_TYPE_GADGET:
714                 break;
715         }
716
717         connman_info("Create interface %s [ %s ]", name,
718                                 __connman_service_type2string(type));
719
720         technology = technology_get(type);
721
722         if (technology == NULL || technology->driver == NULL
723                         || technology->driver->add_interface == NULL)
724                 return;
725
726         technology->driver->add_interface(technology,
727                                         index, name, ident);
728 }
729
730 void __connman_technology_remove_interface(enum connman_service_type type,
731                                 int index, const char *name, const char *ident)
732 {
733         struct connman_technology *technology;
734
735         switch (type) {
736         case CONNMAN_SERVICE_TYPE_UNKNOWN:
737         case CONNMAN_SERVICE_TYPE_SYSTEM:
738                 return;
739         case CONNMAN_SERVICE_TYPE_ETHERNET:
740         case CONNMAN_SERVICE_TYPE_WIFI:
741         case CONNMAN_SERVICE_TYPE_WIMAX:
742         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
743         case CONNMAN_SERVICE_TYPE_CELLULAR:
744         case CONNMAN_SERVICE_TYPE_GPS:
745         case CONNMAN_SERVICE_TYPE_VPN:
746         case CONNMAN_SERVICE_TYPE_GADGET:
747                 break;
748         }
749
750         connman_info("Remove interface %s [ %s ]", name,
751                                 __connman_service_type2string(type));
752
753         technology = technology_find(type);
754
755         if (technology == NULL || technology->driver == NULL)
756                 return;
757
758         if (technology->driver->remove_interface)
759                 technology->driver->remove_interface(technology, index);
760
761         technology_put(technology);
762 }
763
764 int __connman_technology_add_device(struct connman_device *device)
765 {
766         struct connman_technology *technology;
767         enum connman_service_type type;
768
769         DBG("device %p", device);
770
771         type = __connman_device_get_service_type(device);
772         __connman_notifier_register(type);
773
774         technology = technology_get(type);
775         if (technology == NULL)
776                 return -ENXIO;
777
778         if (technology->enable_persistent && !global_offlinemode)
779                 __connman_device_enable(device);
780         /* if technology persistent state is offline */
781         if (!technology->enable_persistent)
782                 __connman_device_disable(device);
783
784         technology->device_list = g_slist_append(technology->device_list,
785                                                                 device);
786
787         return 0;
788 }
789
790 int __connman_technology_remove_device(struct connman_device *device)
791 {
792         struct connman_technology *technology;
793         enum connman_service_type type;
794
795         DBG("device %p", device);
796
797         type = __connman_device_get_service_type(device);
798         __connman_notifier_unregister(type);
799
800         technology = technology_find(type);
801         if (technology == NULL)
802                 return -ENXIO;
803
804         technology->device_list = g_slist_remove(technology->device_list,
805                                                                 device);
806         if (technology->device_list == NULL) {
807                 technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
808                 state_changed(technology);
809         }
810
811         return 0;
812 }
813
814 static gboolean technology_pending_reply(gpointer user_data)
815 {
816         struct connman_technology *technology = user_data;
817         DBusMessage *reply;
818
819         /* Power request timedout, send ETIMEDOUT. */
820         if (technology->pending_reply != NULL) {
821                 reply = __connman_error_failed(technology->pending_reply, ETIMEDOUT);
822                 if (reply != NULL)
823                         g_dbus_send_message(connection, reply);
824
825                 dbus_message_unref(technology->pending_reply);
826                 technology->pending_reply = NULL;
827                 technology->pending_timeout = 0;
828         }
829
830         return FALSE;
831 }
832
833 int __connman_technology_enabled(enum connman_service_type type)
834 {
835         struct connman_technology *technology;
836
837         technology = technology_find(type);
838         if (technology == NULL)
839                 return -ENXIO;
840
841         if (__sync_fetch_and_add(&technology->enabled, 1) == 0) {
842                 __connman_notifier_enable(type);
843                 technology->state = CONNMAN_TECHNOLOGY_STATE_ENABLED;
844                 state_changed(technology);
845         }
846
847         if (technology->pending_reply != NULL) {
848                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
849                 dbus_message_unref(technology->pending_reply);
850                 g_source_remove(technology->pending_timeout);
851                 technology->pending_reply = NULL;
852                 technology->pending_timeout = 0;
853         }
854
855         return 0;
856 }
857
858 int __connman_technology_enable(enum connman_service_type type, DBusMessage *msg)
859 {
860         struct connman_technology *technology;
861         GSList *list;
862         int err = 0;
863         int ret = -ENODEV;
864         DBusMessage *reply;
865
866         DBG("type %d enable", type);
867
868         technology = technology_find(type);
869         if (technology == NULL) {
870                 err = -ENXIO;
871                 goto done;
872         }
873
874         if (technology->pending_reply != NULL) {
875                 err = -EBUSY;
876                 goto done;
877         }
878
879         if (msg != NULL) {
880                 /*
881                  * This is a bit of a trick. When msg is not NULL it means
882                  * thats technology_enable was invoked from the manager API. Hence we save
883                  * the state here.
884                  */
885                 technology->enable_persistent = TRUE;
886                 save_state(technology);
887         }
888
889         __connman_rfkill_block(technology->type, FALSE);
890
891         /*
892          * An empty device list means that devices in the technology
893          * were rfkill blocked. The unblock above will enable the devs.
894          */
895         if (technology->device_list == NULL) {
896                 ret = 0;
897                 goto done;
898         }
899
900         for (list = technology->device_list; list; list = list->next) {
901                 struct connman_device *device = list->data;
902
903                 err = __connman_device_enable(device);
904                 /*
905                  * err = 0 : Device was enabled right away.
906                  * If atleast one device gets enabled, we consider
907                  * the technology to be enabled.
908                  */
909                 if (err == 0)
910                         ret = 0;
911         }
912
913 done:
914         if (ret == 0) {
915                 if (msg != NULL)
916                         g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID);
917                 return ret;
918         }
919
920         if (msg != NULL) {
921                 if (err == -EINPROGRESS) {
922                         technology->pending_reply = dbus_message_ref(msg);
923                         technology->pending_timeout = g_timeout_add_seconds(10,
924                                         technology_pending_reply, technology);
925                 } else {
926                         reply = __connman_error_failed(msg, -err);
927                         if (reply != NULL)
928                                 g_dbus_send_message(connection, reply);
929                 }
930         }
931
932         return err;
933 }
934
935 int __connman_technology_disabled(enum connman_service_type type)
936 {
937         struct connman_technology *technology;
938
939         technology = technology_find(type);
940         if (technology == NULL)
941                 return -ENXIO;
942
943         if (technology->pending_reply != NULL) {
944                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
945                 dbus_message_unref(technology->pending_reply);
946                 g_source_remove(technology->pending_timeout);
947                 technology->pending_reply = NULL;
948                 technology->pending_timeout = 0;
949         }
950
951         if (__sync_fetch_and_sub(&technology->enabled, 1) != 1)
952                 return 0;
953
954         __connman_notifier_disable(type);
955         technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
956         state_changed(technology);
957
958         return 0;
959 }
960
961 int __connman_technology_disable(enum connman_service_type type, DBusMessage *msg)
962 {
963         struct connman_technology *technology;
964         GSList *list;
965         int err = 0;
966         int ret = -ENODEV;
967         DBusMessage *reply;
968
969         DBG("type %d disable", type);
970
971         technology = technology_find(type);
972         if (technology == NULL) {
973                 err = -ENXIO;
974                 goto done;
975         }
976
977         if (technology->pending_reply != NULL) {
978                 err = -EBUSY;
979                 goto done;
980         }
981
982         if (technology->tethering == TRUE)
983                 set_tethering(technology, FALSE);
984
985         if (msg != NULL) {
986                 technology->enable_persistent = FALSE;
987                 save_state(technology);
988         }
989
990         __connman_rfkill_block(technology->type, TRUE);
991
992         for (list = technology->device_list; list; list = list->next) {
993                 struct connman_device *device = list->data;
994
995                 err = __connman_device_disable(device);
996                 if (err == 0)
997                         ret = 0;
998         }
999
1000 done:
1001         if (ret == 0) {
1002                 if (msg != NULL)
1003                         g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID);
1004                 return ret;
1005         }
1006
1007         if (msg != NULL) {
1008                 if (err == -EINPROGRESS) {
1009                         technology->pending_reply = dbus_message_ref(msg);
1010                         technology->pending_timeout = g_timeout_add_seconds(10,
1011                                         technology_pending_reply, technology);
1012                 } else {
1013                         reply = __connman_error_failed(msg, -err);
1014                         if (reply != NULL)
1015                                 g_dbus_send_message(connection, reply);
1016                 }
1017         }
1018
1019         return err;
1020 }
1021
1022 int __connman_technology_set_offlinemode(connman_bool_t offlinemode)
1023 {
1024         GSList *list;
1025         int err = -EINVAL;
1026
1027         if (global_offlinemode == offlinemode)
1028                 return 0;
1029
1030         DBG("offlinemode %s", offlinemode ? "On" : "Off");
1031
1032         /*
1033          * This is a bit tricky. When you set offlinemode, there is no
1034          * way to differentiate between attempting offline mode and
1035          * resuming offlinemode from last saved profile. We need that
1036          * information in rfkill_update, otherwise it falls back on the
1037          * technology's persistent state. Hence we set the offline mode here
1038          * but save it & call the notifier only if its successful.
1039          */
1040
1041         global_offlinemode = offlinemode;
1042
1043         /* Traverse technology list, enable/disable each technology. */
1044         for (list = technology_list; list; list = list->next) {
1045                 struct connman_technology *technology = list->data;
1046
1047                 if (offlinemode)
1048                         err = __connman_technology_disable(technology->type, NULL);
1049
1050                 if (!offlinemode && technology->enable_persistent)
1051                         err = __connman_technology_enable(technology->type, NULL);
1052         }
1053
1054         if (err == 0 || err == -EINPROGRESS || err == -EALREADY) {
1055                 connman_technology_save_offlinemode();
1056                 __connman_notifier_offlinemode(offlinemode);
1057         } else
1058                 global_offlinemode = connman_technology_load_offlinemode();
1059
1060         return err;
1061 }
1062
1063 int __connman_technology_add_rfkill(unsigned int index,
1064                                         enum connman_service_type type,
1065                                                 connman_bool_t softblock,
1066                                                 connman_bool_t hardblock)
1067 {
1068         struct connman_technology *technology;
1069         struct connman_rfkill *rfkill;
1070
1071         DBG("index %u type %d soft %u hard %u", index, type,
1072                                                         softblock, hardblock);
1073
1074         technology = technology_get(type);
1075         if (technology == NULL)
1076                 return -ENXIO;
1077
1078         rfkill = g_try_new0(struct connman_rfkill, 1);
1079         if (rfkill == NULL)
1080                 return -ENOMEM;
1081
1082         __connman_notifier_register(type);
1083
1084         rfkill->index = index;
1085         rfkill->type = type;
1086         rfkill->softblock = softblock;
1087         rfkill->hardblock = hardblock;
1088
1089         g_hash_table_replace(technology->rfkill_list, &rfkill->index, rfkill);
1090
1091         if (hardblock) {
1092                 DBG("%s is switched off.", get_name(type));
1093                 return 0;
1094         }
1095
1096         /*
1097          * If Offline mode is on, we softblock the device if it isnt already.
1098          * If Offline mode is off, we rely on the persistent state of tech.
1099          */
1100         if (global_offlinemode) {
1101                 if (!softblock)
1102                         return __connman_rfkill_block(type, TRUE);
1103         } else {
1104                 if (technology->enable_persistent && softblock)
1105                         return __connman_rfkill_block(type, FALSE);
1106                 /* if technology persistent state is offline */
1107                 if (!technology->enable_persistent && !softblock)
1108                         return __connman_rfkill_block(type, TRUE);
1109         }
1110
1111         return 0;
1112 }
1113
1114 int __connman_technology_update_rfkill(unsigned int index,
1115                                         enum connman_service_type type,
1116                                                 connman_bool_t softblock,
1117                                                 connman_bool_t hardblock)
1118 {
1119         struct connman_technology *technology;
1120         struct connman_rfkill *rfkill;
1121
1122         DBG("index %u soft %u hard %u", index, softblock, hardblock);
1123
1124         technology = technology_find(type);
1125         if (technology == NULL)
1126                 return -ENXIO;
1127
1128         rfkill = g_hash_table_lookup(technology->rfkill_list, &index);
1129         if (rfkill == NULL)
1130                 return -ENXIO;
1131
1132         if (rfkill->softblock == softblock &&
1133                 rfkill->hardblock == hardblock)
1134                 return 0;
1135
1136         rfkill->softblock = softblock;
1137         rfkill->hardblock = hardblock;
1138
1139         if (hardblock) {
1140                 DBG("%s is switched off.", get_name(type));
1141                 return 0;
1142         }
1143
1144         if (!global_offlinemode) {
1145                 if (technology->enable_persistent && softblock)
1146                         return __connman_rfkill_block(type, FALSE);
1147                 if (!technology->enable_persistent && !softblock)
1148                         return __connman_rfkill_block(type, TRUE);
1149         }
1150
1151         return 0;
1152 }
1153
1154 int __connman_technology_remove_rfkill(unsigned int index,
1155                                         enum connman_service_type type)
1156 {
1157         struct connman_technology *technology;
1158         struct connman_rfkill *rfkill;
1159
1160         DBG("index %u", index);
1161
1162         technology = technology_find(type);
1163         if (technology == NULL)
1164                 return -ENXIO;
1165
1166         rfkill = g_hash_table_lookup(technology->rfkill_list, &index);
1167         if (rfkill == NULL)
1168                 return -ENXIO;
1169
1170         g_hash_table_remove(technology->rfkill_list, &index);
1171
1172         technology_put(technology);
1173
1174         return 0;
1175 }
1176
1177 int __connman_technology_init(void)
1178 {
1179         DBG("");
1180
1181         connection = connman_dbus_get_connection();
1182
1183         global_offlinemode = connman_technology_load_offlinemode();
1184
1185         return 0;
1186 }
1187
1188 void __connman_technology_cleanup(void)
1189 {
1190         DBG("");
1191
1192         dbus_connection_unref(connection);
1193 }