storage: Remove technology state load/save methods from storage module
[framework/connectivity/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         gint 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         gint 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         DBG("technology %p enabled %u", technology, enabled);
158
159         if (technology->tethering == enabled)
160                 return;
161
162         technology->tethering = enabled;
163
164         tethering_changed(technology);
165
166         if (enabled == TRUE)
167                 __connman_tethering_set_enabled();
168         else
169                 __connman_tethering_set_disabled();
170 }
171
172 static int set_tethering(struct connman_technology *technology,
173                                 const char *bridge, connman_bool_t enabled)
174 {
175         const char *ident, *passphrase;
176
177         ident = technology->tethering_ident;
178         passphrase = technology->tethering_passphrase;
179
180         if (technology->driver == NULL ||
181                         technology->driver->set_tethering == NULL)
182                 return -EOPNOTSUPP;
183
184         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI &&
185             (ident == NULL || passphrase == NULL))
186                 return -EINVAL;
187
188         return technology->driver->set_tethering(technology, ident, passphrase,
189                                                         bridge, enabled);
190 }
191
192 void connman_technology_regdom_notify(struct connman_technology *technology,
193                                                         const char *alpha2)
194 {
195         DBG("");
196
197         if (alpha2 == NULL)
198                 connman_error("Failed to set regulatory domain");
199         else
200                 DBG("Regulatory domain set to %s", alpha2);
201
202         g_free(technology->regdom);
203         technology->regdom = g_strdup(alpha2);
204 }
205
206 int connman_technology_set_regdom(const char *alpha2)
207 {
208         GSList *list;
209
210         for (list = technology_list; list; list = list->next) {
211                 struct connman_technology *technology = list->data;
212
213                 if (technology->driver == NULL)
214                         continue;
215
216                 if (technology->driver->set_regdom)
217                         technology->driver->set_regdom(technology, alpha2);
218         }
219
220         return 0;
221 }
222
223 static void free_rfkill(gpointer data)
224 {
225         struct connman_rfkill *rfkill = data;
226
227         g_free(rfkill);
228 }
229
230 void __connman_technology_list(DBusMessageIter *iter, void *user_data)
231 {
232         GSList *list;
233
234         for (list = technology_list; list; list = list->next) {
235                 struct connman_technology *technology = list->data;
236
237                 if (technology->path == NULL)
238                         continue;
239
240                 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
241                                                         &technology->path);
242         }
243 }
244
245 static void technologies_changed(void)
246 {
247         connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
248                         CONNMAN_MANAGER_INTERFACE, "Technologies",
249                         DBUS_TYPE_OBJECT_PATH, __connman_technology_list, NULL);
250 }
251
252 static const char *state2string(enum connman_technology_state state)
253 {
254         switch (state) {
255         case CONNMAN_TECHNOLOGY_STATE_UNKNOWN:
256                 break;
257         case CONNMAN_TECHNOLOGY_STATE_OFFLINE:
258                 return "offline";
259         case CONNMAN_TECHNOLOGY_STATE_ENABLED:
260                 return "enabled";
261         case CONNMAN_TECHNOLOGY_STATE_CONNECTED:
262                 return "connected";
263         }
264
265         return NULL;
266 }
267
268 static void state_changed(struct connman_technology *technology)
269 {
270         const char *str;
271
272         str = state2string(technology->state);
273         if (str == NULL)
274                 return;
275
276         connman_dbus_property_changed_basic(technology->path,
277                                 CONNMAN_TECHNOLOGY_INTERFACE, "State",
278                                                 DBUS_TYPE_STRING, &str);
279 }
280
281 static const char *get_name(enum connman_service_type type)
282 {
283         switch (type) {
284         case CONNMAN_SERVICE_TYPE_UNKNOWN:
285         case CONNMAN_SERVICE_TYPE_SYSTEM:
286         case CONNMAN_SERVICE_TYPE_GPS:
287         case CONNMAN_SERVICE_TYPE_VPN:
288         case CONNMAN_SERVICE_TYPE_GADGET:
289                 break;
290         case CONNMAN_SERVICE_TYPE_ETHERNET:
291                 return "Wired";
292         case CONNMAN_SERVICE_TYPE_WIFI:
293                 return "WiFi";
294         case CONNMAN_SERVICE_TYPE_WIMAX:
295                 return "WiMAX";
296         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
297                 return "Bluetooth";
298         case CONNMAN_SERVICE_TYPE_CELLULAR:
299                 return "3G";
300         }
301
302         return NULL;
303 }
304
305 static int load_state(struct connman_technology *technology)
306 {
307         GKeyFile *keyfile;
308         gchar *identifier;
309         GError *error = NULL;
310         connman_bool_t enable;
311
312         DBG("technology %p", technology);
313
314         keyfile = __connman_storage_open_profile("default");
315         if (keyfile == NULL)
316                 return 0;
317
318         identifier = g_strdup_printf("%s", get_name(technology->type));
319         if (identifier == NULL)
320                 goto done;
321
322         enable = g_key_file_get_boolean(keyfile, identifier, "Enable", &error);
323         if (error == NULL)
324                 technology->enable_persistent = enable;
325         else
326                 technology->enable_persistent = FALSE;
327
328         g_clear_error(&error);
329 done:
330         g_free(identifier);
331
332         __connman_storage_close_profile("default", keyfile, FALSE);
333
334         return 0;
335 }
336
337 static int save_state(struct connman_technology *technology)
338 {
339         GKeyFile *keyfile;
340         gchar *identifier;
341
342         DBG("technology %p", technology);
343
344         keyfile = __connman_storage_open_profile("default");
345         if (keyfile == NULL)
346                 return 0;
347
348         identifier = g_strdup_printf("%s", get_name(technology->type));
349         if (identifier == NULL)
350                 goto done;
351
352         g_key_file_set_boolean(keyfile, identifier, "Enable",
353                                 technology->enable_persistent);
354
355 done:
356         g_free(identifier);
357
358         __connman_storage_close_profile("default", keyfile, TRUE);
359
360         return 0;
361 }
362
363 connman_bool_t __connman_technology_get_offlinemode(void)
364 {
365         return global_offlinemode;
366 }
367
368 static int connman_technology_save_offlinemode()
369 {
370         GKeyFile *keyfile;
371
372         keyfile = __connman_storage_open_profile("default");
373         if (keyfile == NULL)
374                 return -EIO;
375
376         g_key_file_set_boolean(keyfile, "global",
377                                         "OfflineMode", global_offlinemode);
378
379         __connman_storage_close_profile("default", keyfile, TRUE);
380
381         return 0;
382 }
383
384 static connman_bool_t connman_technology_load_offlinemode()
385 {
386         GKeyFile *keyfile;
387         GError *error = NULL;
388         connman_bool_t offlinemode;
389
390         /* If there is a error, we enable offlinemode */
391         keyfile = __connman_storage_open_profile("default");
392         if (keyfile == NULL)
393                 return TRUE;
394
395         offlinemode = g_key_file_get_boolean(keyfile, "global",
396                                                 "OfflineMode", &error);
397         if (error != NULL) {
398                 offlinemode = TRUE;
399                 g_clear_error(&error);
400         }
401         __connman_storage_close_profile("default", keyfile, FALSE);
402
403         return offlinemode;
404 }
405
406 static DBusMessage *get_properties(DBusConnection *conn,
407                                         DBusMessage *message, void *user_data)
408 {
409         struct connman_technology *technology = user_data;
410         DBusMessage *reply;
411         DBusMessageIter array, dict;
412         const char *str;
413
414         reply = dbus_message_new_method_return(message);
415         if (reply == NULL)
416                 return NULL;
417
418         dbus_message_iter_init_append(reply, &array);
419
420         connman_dbus_dict_open(&array, &dict);
421
422         str = state2string(technology->state);
423         if (str != NULL)
424                 connman_dbus_dict_append_basic(&dict, "State",
425                                                 DBUS_TYPE_STRING, &str);
426
427         str = get_name(technology->type);
428         if (str != NULL)
429                 connman_dbus_dict_append_basic(&dict, "Name",
430                                                 DBUS_TYPE_STRING, &str);
431
432         str = __connman_service_type2string(technology->type);
433         if (str != NULL)
434                 connman_dbus_dict_append_basic(&dict, "Type",
435                                                 DBUS_TYPE_STRING, &str);
436
437         connman_dbus_dict_append_basic(&dict, "Tethering",
438                                         DBUS_TYPE_BOOLEAN,
439                                         &technology->tethering);
440
441         if (technology->tethering_ident != NULL)
442                 connman_dbus_dict_append_basic(&dict, "TetheringIdentifier",
443                                                 DBUS_TYPE_STRING,
444                                                 &technology->tethering_ident);
445
446         if (technology->tethering_passphrase != NULL)
447                 connman_dbus_dict_append_basic(&dict, "TetheringPassphrase",
448                                                 DBUS_TYPE_STRING,
449                                                 &technology->tethering_passphrase);
450
451         connman_dbus_dict_close(&array, &dict);
452
453         return reply;
454 }
455
456 static DBusMessage *set_property(DBusConnection *conn,
457                                         DBusMessage *msg, void *data)
458 {
459         struct connman_technology *technology = data;
460         DBusMessageIter iter, value;
461         const char *name;
462         int type;
463
464         DBG("conn %p", conn);
465
466         if (dbus_message_iter_init(msg, &iter) == FALSE)
467                 return __connman_error_invalid_arguments(msg);
468
469         dbus_message_iter_get_basic(&iter, &name);
470         dbus_message_iter_next(&iter);
471         dbus_message_iter_recurse(&iter, &value);
472
473         type = dbus_message_iter_get_arg_type(&value);
474
475         DBG("property %s", name);
476
477         if (g_str_equal(name, "Tethering") == TRUE) {
478                 int err;
479                 connman_bool_t tethering;
480                 const char *bridge;
481
482                 if (type != DBUS_TYPE_BOOLEAN)
483                         return __connman_error_invalid_arguments(msg);
484
485                 dbus_message_iter_get_basic(&value, &tethering);
486
487                 if (technology->tethering == tethering)
488                         return __connman_error_in_progress(msg);
489
490                 bridge = __connman_tethering_get_bridge();
491                 if (bridge == NULL)
492                         return __connman_error_not_supported(msg);
493
494                 err = set_tethering(technology, bridge, tethering);
495                 if (err < 0)
496                         return __connman_error_failed(msg, -err);
497
498         } else if (g_str_equal(name, "TetheringIdentifier") == TRUE) {
499                 const char *str;
500
501                 dbus_message_iter_get_basic(&value, &str);
502
503                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
504                         return __connman_error_not_supported(msg);
505
506                 technology->tethering_ident = g_strdup(str);
507         } else if (g_str_equal(name, "TetheringPassphrase") == TRUE) {
508                 const char *str;
509
510                 dbus_message_iter_get_basic(&value, &str);
511
512                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
513                         return __connman_error_not_supported(msg);
514
515                 if (strlen(str) < 8)
516                         return __connman_error_invalid_arguments(msg);
517
518                 technology->tethering_passphrase = g_strdup(str);
519         } else
520                 return __connman_error_invalid_property(msg);
521
522         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
523 }
524
525 static GDBusMethodTable technology_methods[] = {
526         { "GetProperties", "",   "a{sv}", get_properties },
527         { "SetProperty",   "sv", "",      set_property   },
528         { },
529 };
530
531 static GDBusSignalTable technology_signals[] = {
532         { "PropertyChanged", "sv" },
533         { },
534 };
535
536 static struct connman_technology *technology_find(enum connman_service_type type)
537 {
538         GSList *list;
539
540         DBG("type %d", type);
541
542         for (list = technology_list; list; list = list->next) {
543                 struct connman_technology *technology = list->data;
544
545                 if (technology->type == type)
546                         return technology;
547         }
548
549         return NULL;
550 }
551
552 static struct connman_technology *technology_get(enum connman_service_type type)
553 {
554         struct connman_technology *technology;
555         const char *str;
556         GSList *list;
557
558         DBG("type %d", type);
559
560         technology = technology_find(type);
561         if (technology != NULL) {
562                 g_atomic_int_inc(&technology->refcount);
563                 goto done;
564         }
565
566         str = __connman_service_type2string(type);
567         if (str == NULL)
568                 return NULL;
569
570         technology = g_try_new0(struct connman_technology, 1);
571         if (technology == NULL)
572                 return NULL;
573
574         technology->refcount = 1;
575
576         technology->type = type;
577         technology->path = g_strdup_printf("%s/technology/%s",
578                                                         CONNMAN_PATH, str);
579
580         technology->rfkill_list = g_hash_table_new_full(g_int_hash, g_int_equal,
581                                                         NULL, free_rfkill);
582         technology->device_list = NULL;
583
584         technology->pending_reply = NULL;
585         technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
586
587         load_state(technology);
588
589         if (g_dbus_register_interface(connection, technology->path,
590                                         CONNMAN_TECHNOLOGY_INTERFACE,
591                                         technology_methods, technology_signals,
592                                         NULL, technology, NULL) == FALSE) {
593                 connman_error("Failed to register %s", technology->path);
594                 g_free(technology);
595                 return NULL;
596         }
597
598         technology_list = g_slist_append(technology_list, technology);
599
600         technologies_changed();
601
602         if (technology->driver != NULL)
603                 goto done;
604
605         for (list = driver_list; list; list = list->next) {
606                 struct connman_technology_driver *driver = list->data;
607
608                 DBG("driver %p name %s", driver, driver->name);
609
610                 if (driver->type != technology->type)
611                         continue;
612
613                 if (driver->probe(technology) == 0) {
614                         technology->driver = driver;
615                         break;
616                 }
617         }
618
619 done:
620         DBG("technology %p", technology);
621
622         return technology;
623 }
624
625 static void technology_put(struct connman_technology *technology)
626 {
627         DBG("technology %p", technology);
628
629         if (g_atomic_int_dec_and_test(&technology->refcount) == FALSE)
630                 return;
631
632         if (technology->driver) {
633                 technology->driver->remove(technology);
634                 technology->driver = NULL;
635         }
636
637         technology_list = g_slist_remove(technology_list, technology);
638
639         technologies_changed();
640
641         g_dbus_unregister_interface(connection, technology->path,
642                                                 CONNMAN_TECHNOLOGY_INTERFACE);
643
644         g_slist_free(technology->device_list);
645         g_hash_table_destroy(technology->rfkill_list);
646
647         g_free(technology->path);
648         g_free(technology->regdom);
649         g_free(technology);
650 }
651
652 void __connman_technology_add_interface(enum connman_service_type type,
653                                 int index, const char *name, const char *ident)
654 {
655         struct connman_technology *technology;
656
657         switch (type) {
658         case CONNMAN_SERVICE_TYPE_UNKNOWN:
659         case CONNMAN_SERVICE_TYPE_SYSTEM:
660                 return;
661         case CONNMAN_SERVICE_TYPE_ETHERNET:
662         case CONNMAN_SERVICE_TYPE_WIFI:
663         case CONNMAN_SERVICE_TYPE_WIMAX:
664         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
665         case CONNMAN_SERVICE_TYPE_CELLULAR:
666         case CONNMAN_SERVICE_TYPE_GPS:
667         case CONNMAN_SERVICE_TYPE_VPN:
668         case CONNMAN_SERVICE_TYPE_GADGET:
669                 break;
670         }
671
672         connman_info("Create interface %s [ %s ]", name,
673                                 __connman_service_type2string(type));
674
675         technology = technology_get(type);
676
677         if (technology == NULL || technology->driver == NULL
678                         || technology->driver->add_interface == NULL)
679                 return;
680
681         technology->driver->add_interface(technology,
682                                         index, name, ident);
683 }
684
685 void __connman_technology_remove_interface(enum connman_service_type type,
686                                 int index, const char *name, const char *ident)
687 {
688         struct connman_technology *technology;
689
690         switch (type) {
691         case CONNMAN_SERVICE_TYPE_UNKNOWN:
692         case CONNMAN_SERVICE_TYPE_SYSTEM:
693                 return;
694         case CONNMAN_SERVICE_TYPE_ETHERNET:
695         case CONNMAN_SERVICE_TYPE_WIFI:
696         case CONNMAN_SERVICE_TYPE_WIMAX:
697         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
698         case CONNMAN_SERVICE_TYPE_CELLULAR:
699         case CONNMAN_SERVICE_TYPE_GPS:
700         case CONNMAN_SERVICE_TYPE_VPN:
701         case CONNMAN_SERVICE_TYPE_GADGET:
702                 break;
703         }
704
705         connman_info("Remove interface %s [ %s ]", name,
706                                 __connman_service_type2string(type));
707
708         technology = technology_find(type);
709
710         if (technology == NULL || technology->driver == NULL)
711                 return;
712
713         if (technology->driver->remove_interface)
714                 technology->driver->remove_interface(technology, index);
715
716         technology_put(technology);
717 }
718
719 int __connman_technology_add_device(struct connman_device *device)
720 {
721         struct connman_technology *technology;
722         enum connman_service_type type;
723
724         DBG("device %p", device);
725
726         type = __connman_device_get_service_type(device);
727         __connman_notifier_register(type);
728
729         technology = technology_get(type);
730         if (technology == NULL)
731                 return -ENXIO;
732
733         if (technology->enable_persistent && !global_offlinemode)
734                 __connman_device_enable(device);
735         /* if technology persistent state is offline */
736         if (!technology->enable_persistent)
737                 __connman_device_disable(device);
738
739         technology->device_list = g_slist_append(technology->device_list,
740                                                                 device);
741
742         return 0;
743 }
744
745 int __connman_technology_remove_device(struct connman_device *device)
746 {
747         struct connman_technology *technology;
748         enum connman_service_type type;
749
750         DBG("device %p", device);
751
752         type = __connman_device_get_service_type(device);
753         __connman_notifier_unregister(type);
754
755         technology = technology_find(type);
756         if (technology == NULL)
757                 return -ENXIO;
758
759         technology->device_list = g_slist_remove(technology->device_list,
760                                                                 device);
761         if (technology->device_list == NULL) {
762                 technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
763                 state_changed(technology);
764         }
765
766         return 0;
767 }
768
769 static gboolean technology_pending_reply(gpointer user_data)
770 {
771         struct connman_technology *technology = user_data;
772         DBusMessage *reply;
773
774         /* Power request timedout, send ETIMEDOUT. */
775         if (technology->pending_reply != NULL) {
776                 reply = __connman_error_failed(technology->pending_reply, ETIMEDOUT);
777                 if (reply != NULL)
778                         g_dbus_send_message(connection, reply);
779
780                 dbus_message_unref(technology->pending_reply);
781                 technology->pending_reply = NULL;
782                 technology->pending_timeout = 0;
783         }
784
785         return FALSE;
786 }
787
788 int __connman_technology_enabled(enum connman_service_type type)
789 {
790         struct connman_technology *technology;
791
792         technology = technology_find(type);
793         if (technology == NULL)
794                 return -ENXIO;
795
796         if (g_atomic_int_exchange_and_add(&technology->enabled, 1) == 0) {
797                 __connman_notifier_enable(type);
798                 technology->state = CONNMAN_TECHNOLOGY_STATE_ENABLED;
799                 state_changed(technology);
800         }
801
802         if (technology->pending_reply != NULL) {
803                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
804                 dbus_message_unref(technology->pending_reply);
805                 technology->pending_reply = NULL;
806                 technology->pending_timeout = 0;
807         }
808
809         return 0;
810 }
811
812 int __connman_technology_enable(enum connman_service_type type, DBusMessage *msg)
813 {
814         struct connman_technology *technology;
815         GSList *list;
816         int err = 0;
817         int ret = -ENODEV;
818         DBusMessage *reply;
819
820         DBG("type %d enable", type);
821
822         technology = technology_find(type);
823         if (technology == NULL) {
824                 err = -ENXIO;
825                 goto done;
826         }
827
828         if (technology->pending_reply != NULL) {
829                 err = -EBUSY;
830                 goto done;
831         }
832
833         if (msg != NULL) {
834                 technology->pending_reply = dbus_message_ref(msg);
835                 /*
836                  * This is a bit of a trick. When msg is not NULL it means
837                  * thats technology_enable was invoked from the manager API. Hence we save
838                  * the state here.
839                  */
840                 technology->enable_persistent = TRUE;
841                 save_state(technology);
842         }
843
844         __connman_rfkill_block(technology->type, FALSE);
845
846         for (list = technology->device_list; list; list = list->next) {
847                 struct connman_device *device = list->data;
848
849                 err = __connman_device_enable(device);
850                 /*
851                  * err = 0 : Device was enabled right away.
852                  * If atleast one device gets enabled, we consider
853                  * the technology to be enabled.
854                  */
855                 if (err == 0)
856                         ret = 0;
857         }
858
859 done:
860         if (ret == 0)
861                 return ret;
862
863         if (msg != NULL) {
864                 if (err == -EINPROGRESS)
865                         technology->pending_timeout = g_timeout_add_seconds(10,
866                                         technology_pending_reply, technology);
867                 else {
868                         reply = __connman_error_failed(msg, -err);
869                         if (reply != NULL)
870                                 g_dbus_send_message(connection, reply);
871                 }
872         }
873
874         return err;
875 }
876
877 int __connman_technology_disabled(enum connman_service_type type)
878 {
879         struct connman_technology *technology;
880
881         technology = technology_find(type);
882         if (technology == NULL)
883                 return -ENXIO;
884
885         if (technology->pending_reply != NULL) {
886                 g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
887                 dbus_message_unref(technology->pending_reply);
888                 technology->pending_reply = NULL;
889         }
890
891         if (g_atomic_int_dec_and_test(&technology->enabled) == TRUE) {
892                 __connman_notifier_disable(type);
893                 technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
894                 state_changed(technology);
895         }
896
897         return 0;
898 }
899
900 int __connman_technology_disable(enum connman_service_type type, DBusMessage *msg)
901 {
902         struct connman_technology *technology;
903         GSList *list;
904         int err = 0;
905         int ret = -ENODEV;
906         DBusMessage *reply;
907
908         DBG("type %d disable", type);
909
910         technology = technology_find(type);
911         if (technology == NULL) {
912                 err = -ENXIO;
913                 goto done;
914         }
915
916         if (technology->pending_reply != NULL) {
917                 err = -EBUSY;
918                 goto done;
919         }
920
921         if (msg != NULL) {
922                 technology->pending_reply = dbus_message_ref(msg);
923                 technology->enable_persistent = FALSE;
924                 save_state(technology);
925         }
926
927         __connman_rfkill_block(technology->type, TRUE);
928
929         for (list = technology->device_list; list; list = list->next) {
930                 struct connman_device *device = list->data;
931
932                 err = __connman_device_disable(device);
933                 if (err == 0)
934                         ret = 0;
935         }
936
937 done:
938         if (ret == 0)
939                 return ret;
940
941         if (msg != NULL) {
942                 if (err == -EINPROGRESS)
943                         technology->pending_timeout = g_timeout_add_seconds(10,
944                                         technology_pending_reply, technology);
945                 else {
946                         reply = __connman_error_failed(msg, -err);
947                         if (reply != NULL)
948                                 g_dbus_send_message(connection, reply);
949                 }
950         }
951
952         return err;
953 }
954
955 int __connman_technology_set_offlinemode(connman_bool_t offlinemode)
956 {
957         GSList *list;
958         int err = -EINVAL;
959
960         if (global_offlinemode == offlinemode)
961                 return 0;
962
963         DBG("offlinemode %s", offlinemode ? "On" : "Off");
964
965         /*
966          * This is a bit tricky. When you set offlinemode, there is no
967          * way to differentiate between attempting offline mode and
968          * resuming offlinemode from last saved profile. We need that
969          * information in rfkill_update, otherwise it falls back on the
970          * technology's persistent state. Hence we set the offline mode here
971          * but save it & call the notifier only if its successful.
972          */
973
974         global_offlinemode = offlinemode;
975
976         /* Traverse technology list, enable/disable each technology. */
977         for (list = technology_list; list; list = list->next) {
978                 struct connman_technology *technology = list->data;
979
980                 if (offlinemode)
981                         err = __connman_technology_disable(technology->type, NULL);
982
983                 if (!offlinemode && technology->enable_persistent)
984                         err = __connman_technology_enable(technology->type, NULL);
985         }
986
987         if (err == 0 || err == -EINPROGRESS || err == -EALREADY) {
988                 connman_technology_save_offlinemode();
989                 __connman_notifier_offlinemode(offlinemode);
990         } else
991                 global_offlinemode = connman_technology_load_offlinemode();
992
993         return err;
994 }
995
996 int __connman_technology_add_rfkill(unsigned int index,
997                                         enum connman_service_type type,
998                                                 connman_bool_t softblock,
999                                                 connman_bool_t hardblock)
1000 {
1001         struct connman_technology *technology;
1002         struct connman_rfkill *rfkill;
1003
1004         DBG("index %u type %d soft %u hard %u", index, type,
1005                                                         softblock, hardblock);
1006
1007         technology = technology_get(type);
1008         if (technology == NULL)
1009                 return -ENXIO;
1010
1011         rfkill = g_try_new0(struct connman_rfkill, 1);
1012         if (rfkill == NULL)
1013                 return -ENOMEM;
1014
1015         rfkill->index = index;
1016         rfkill->type = type;
1017         rfkill->softblock = softblock;
1018         rfkill->hardblock = hardblock;
1019
1020         g_hash_table_replace(technology->rfkill_list, &rfkill->index, rfkill);
1021
1022         if (hardblock) {
1023                 DBG("%s is switched off.", get_name(type));
1024                 return 0;
1025         }
1026
1027         /*
1028          * If Offline mode is on, we softblock the device if it isnt already.
1029          * If Offline mode is off, we rely on the persistent state of tech.
1030          */
1031         if (global_offlinemode) {
1032                 if (!softblock)
1033                         return __connman_rfkill_block(type, TRUE);
1034         } else {
1035                 if (technology->enable_persistent && softblock)
1036                         return __connman_rfkill_block(type, FALSE);
1037                 /* if technology persistent state is offline */
1038                 if (!technology->enable_persistent && !softblock)
1039                         return __connman_rfkill_block(type, TRUE);
1040         }
1041
1042         return 0;
1043 }
1044
1045 int __connman_technology_update_rfkill(unsigned int index,
1046                                         enum connman_service_type type,
1047                                                 connman_bool_t softblock,
1048                                                 connman_bool_t hardblock)
1049 {
1050         struct connman_technology *technology;
1051         struct connman_rfkill *rfkill;
1052
1053         DBG("index %u soft %u hard %u", index, softblock, hardblock);
1054
1055         technology = technology_find(type);
1056         if (technology == NULL)
1057                 return -ENXIO;
1058
1059         rfkill = g_hash_table_lookup(technology->rfkill_list, &index);
1060         if (rfkill == NULL)
1061                 return -ENXIO;
1062
1063         if (rfkill->softblock == softblock &&
1064                 rfkill->hardblock == hardblock)
1065                 return 0;
1066
1067         rfkill->softblock = softblock;
1068         rfkill->hardblock = hardblock;
1069
1070         if (hardblock) {
1071                 DBG("%s is switched off.", get_name(type));
1072                 return 0;
1073         }
1074
1075         if (!global_offlinemode) {
1076                 if (technology->enable_persistent && softblock)
1077                         return __connman_rfkill_block(type, FALSE);
1078                 if (!technology->enable_persistent && !softblock)
1079                         return __connman_rfkill_block(type, TRUE);
1080         }
1081
1082         return 0;
1083 }
1084
1085 int __connman_technology_remove_rfkill(unsigned int index,
1086                                         enum connman_service_type type)
1087 {
1088         struct connman_technology *technology;
1089         struct connman_rfkill *rfkill;
1090
1091         DBG("index %u", index);
1092
1093         technology = technology_find(type);
1094         if (technology == NULL)
1095                 return -ENXIO;
1096
1097         rfkill = g_hash_table_lookup(technology->rfkill_list, &index);
1098         if (rfkill == NULL)
1099                 return -ENXIO;
1100
1101         g_hash_table_remove(technology->rfkill_list, &index);
1102
1103         technology_put(technology);
1104
1105         return 0;
1106 }
1107
1108 int __connman_technology_init(void)
1109 {
1110         DBG("");
1111
1112         connection = connman_dbus_get_connection();
1113
1114         global_offlinemode = connman_technology_load_offlinemode();
1115
1116         return 0;
1117 }
1118
1119 void __connman_technology_cleanup(void)
1120 {
1121         DBG("");
1122
1123         dbus_connection_unref(connection);
1124 }