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