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