6e21b4b574da2ffca16cbb765b8df0a5c3097646
[platform/upstream/connman.git] / src / technology.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2012  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 /*
38  * List of devices with no technology associated with them either because of
39  * no compiled in support or the driver is not yet loaded.
40 */
41 static GSList *techless_device_list = NULL;
42 static GHashTable *rfkill_list;
43
44 static connman_bool_t global_offlinemode;
45
46 struct connman_rfkill {
47         unsigned int index;
48         enum connman_service_type type;
49         connman_bool_t softblock;
50         connman_bool_t hardblock;
51 };
52
53 struct connman_technology {
54         int refcount;
55         enum connman_service_type type;
56         char *path;
57         GSList *device_list;
58         connman_bool_t enabled;
59         char *regdom;
60         connman_bool_t connected;
61
62         connman_bool_t tethering;
63         char *tethering_ident;
64         char *tethering_passphrase;
65
66         connman_bool_t enable_persistent; /* Save the tech state */
67
68         GSList *driver_list;
69
70         DBusMessage *pending_reply;
71         guint pending_timeout;
72
73         GSList *scan_pending;
74
75         connman_bool_t rfkill_driven;
76         connman_bool_t softblocked;
77         connman_bool_t hardblocked;
78         connman_bool_t dbus_registered;
79 };
80
81 static GSList *driver_list = NULL;
82
83 static gint compare_priority(gconstpointer a, gconstpointer b)
84 {
85         const struct connman_technology_driver *driver1 = a;
86         const struct connman_technology_driver *driver2 = b;
87
88         return driver2->priority - driver1->priority;
89 }
90
91 static void rfkill_check(gpointer key, gpointer value, gpointer user_data)
92 {
93         struct connman_rfkill *rfkill = value;
94         enum connman_service_type type = GPOINTER_TO_INT(user_data);
95
96         /* Calling _technology_rfkill_add will update the tech. */
97         if (rfkill->type == type)
98                 __connman_technology_add_rfkill(rfkill->index, type,
99                                 rfkill->softblock, rfkill->hardblock);
100 }
101
102 connman_bool_t
103 connman_technology_is_tethering_allowed(enum connman_service_type type)
104 {
105         static char *allowed_default[] = { "wifi", "bluetooth", "gadget",
106                                            NULL };
107         const char *type_str = __connman_service_type2string(type);
108         char **allowed;
109         int i;
110
111         if (type_str == NULL)
112                 return FALSE;
113
114         allowed = connman_setting_get_string_list("AllowedTetheringTechnologies");
115         if (allowed == NULL)
116                 allowed = allowed_default;
117
118         for (i = 0; allowed[i] != NULL; i++) {
119                 if (g_strcmp0(allowed[i], type_str) == 0)
120                         return TRUE;
121         }
122
123         return FALSE;
124 }
125
126 /**
127  * connman_technology_driver_register:
128  * @driver: Technology driver definition
129  *
130  * Register a new technology driver
131  *
132  * Returns: %0 on success
133  */
134 int connman_technology_driver_register(struct connman_technology_driver *driver)
135 {
136         GSList *list;
137         struct connman_device *device;
138         enum connman_service_type type;
139
140         DBG("Registering %s driver", driver->name);
141
142         driver_list = g_slist_insert_sorted(driver_list, driver,
143                                                         compare_priority);
144
145         /*
146          * Check for technology less devices if this driver
147          * can service any of them.
148         */
149         for (list = techless_device_list; list != NULL; list = list->next) {
150                 device = list->data;
151
152                 type = __connman_device_get_service_type(device);
153                 if (type != driver->type)
154                         continue;
155
156                 techless_device_list = g_slist_remove(techless_device_list,
157                                                                 device);
158
159                 __connman_technology_add_device(device);
160         }
161
162         /* Check for orphaned rfkill switches. */
163         g_hash_table_foreach(rfkill_list, rfkill_check,
164                                         GINT_TO_POINTER(driver->type));
165
166         return 0;
167 }
168
169 /**
170  * connman_technology_driver_unregister:
171  * @driver: Technology driver definition
172  *
173  * Remove a previously registered technology driver
174  */
175 void connman_technology_driver_unregister(struct connman_technology_driver *driver)
176 {
177         GSList *list, *tech_drivers;
178         struct connman_technology *technology;
179         struct connman_technology_driver *current;
180
181         DBG("Unregistering driver %p name %s", driver, driver->name);
182
183         for (list = technology_list; list; list = list->next) {
184                 technology = list->data;
185
186                 for (tech_drivers = technology->driver_list;
187                      tech_drivers != NULL;
188                      tech_drivers = g_slist_next(tech_drivers)) {
189
190                         current = tech_drivers->data;
191                         if (driver != current)
192                                 continue;
193
194                         if (driver->remove != NULL)
195                                 driver->remove(technology);
196
197                         technology->driver_list =
198                                 g_slist_remove(technology->driver_list, driver);
199
200                         break;
201                 }
202         }
203
204         driver_list = g_slist_remove(driver_list, driver);
205 }
206
207 static void tethering_changed(struct connman_technology *technology)
208 {
209         connman_bool_t tethering = technology->tethering;
210
211         connman_dbus_property_changed_basic(technology->path,
212                                 CONNMAN_TECHNOLOGY_INTERFACE, "Tethering",
213                                                 DBUS_TYPE_BOOLEAN, &tethering);
214 }
215
216 void connman_technology_tethering_notify(struct connman_technology *technology,
217                                                         connman_bool_t enabled)
218 {
219         GSList *list;
220
221         DBG("technology %p enabled %u", technology, enabled);
222
223         if (technology->tethering == enabled)
224                 return;
225
226         technology->tethering = enabled;
227
228         tethering_changed(technology);
229
230         if (enabled == TRUE)
231                 __connman_tethering_set_enabled();
232         else {
233                 for (list = technology_list; list; list = list->next) {
234                         struct connman_technology *other_tech = list->data;
235                         if (other_tech->tethering == TRUE)
236                                 break;
237                 }
238                 if (list == NULL)
239                         __connman_tethering_set_disabled();
240         }
241 }
242
243 static int set_tethering(struct connman_technology *technology,
244                                 connman_bool_t enabled)
245 {
246         int result = -EOPNOTSUPP;
247         int err;
248         const char *ident, *passphrase, *bridge;
249         GSList *tech_drivers;
250
251         ident = technology->tethering_ident;
252         passphrase = technology->tethering_passphrase;
253
254         __sync_synchronize();
255         if (technology->enabled == FALSE)
256                 return -EACCES;
257
258         bridge = __connman_tethering_get_bridge();
259         if (bridge == NULL)
260                 return -EOPNOTSUPP;
261
262         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI &&
263             (ident == NULL || passphrase == NULL))
264                 return -EINVAL;
265
266         for (tech_drivers = technology->driver_list; tech_drivers != NULL;
267              tech_drivers = g_slist_next(tech_drivers)) {
268                 struct connman_technology_driver *driver = tech_drivers->data;
269
270                 if (driver == NULL || driver->set_tethering == NULL)
271                         continue;
272
273                 err = driver->set_tethering(technology, ident, passphrase,
274                                 bridge, enabled);
275
276                 if (result == -EINPROGRESS)
277                         continue;
278
279                 if (err == -EINPROGRESS || err == 0) {
280                         result = err;
281                         continue;
282                 }
283         }
284
285         return result;
286 }
287
288 void connman_technology_regdom_notify(struct connman_technology *technology,
289                                                         const char *alpha2)
290 {
291         DBG("");
292
293         if (alpha2 == NULL)
294                 connman_error("Failed to set regulatory domain");
295         else
296                 DBG("Regulatory domain set to %s", alpha2);
297
298         g_free(technology->regdom);
299         technology->regdom = g_strdup(alpha2);
300 }
301
302 static int set_regdom_by_device(struct connman_technology *technology,
303                                                         const char *alpha2)
304 {
305         GSList *list;
306
307         for (list = technology->device_list; list; list = list->next) {
308                 struct connman_device *device = list->data;
309
310                 if (connman_device_set_regdom(device, alpha2) != 0)
311                         return -ENOTSUP;
312         }
313
314         return 0;
315 }
316
317 int connman_technology_set_regdom(const char *alpha2)
318 {
319         GSList *list, *tech_drivers;
320
321         for (list = technology_list; list; list = list->next) {
322                 struct connman_technology *technology = list->data;
323
324                 if (set_regdom_by_device(technology, alpha2) != 0) {
325
326                         for (tech_drivers = technology->driver_list;
327                              tech_drivers != NULL;
328                              tech_drivers = g_slist_next(tech_drivers)) {
329
330                                 struct connman_technology_driver *driver =
331                                         tech_drivers->data;
332
333                                 if (driver->set_regdom != NULL)
334                                         driver->set_regdom(technology, alpha2);
335                         }
336                 }
337         }
338
339         return 0;
340 }
341
342 static struct connman_technology *technology_find(enum connman_service_type type)
343 {
344         GSList *list;
345
346         DBG("type %d", type);
347
348         for (list = technology_list; list; list = list->next) {
349                 struct connman_technology *technology = list->data;
350
351                 if (technology->type == type)
352                         return technology;
353         }
354
355         return NULL;
356 }
357
358 connman_bool_t connman_technology_get_wifi_tethering(const char **ssid,
359                                                         const char **psk)
360 {
361         struct connman_technology *technology;
362
363         if (ssid == NULL || psk == NULL)
364                 return FALSE;
365
366         *ssid = *psk = NULL;
367
368         technology = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
369         if (technology == NULL)
370                 return FALSE;
371
372         if (technology->tethering == FALSE)
373                 return FALSE;
374
375         *ssid = technology->tethering_ident;
376         *psk = technology->tethering_passphrase;
377
378         return TRUE;
379 }
380
381 static void free_rfkill(gpointer data)
382 {
383         struct connman_rfkill *rfkill = data;
384
385         g_free(rfkill);
386 }
387
388 static const char *get_name(enum connman_service_type type)
389 {
390         switch (type) {
391         case CONNMAN_SERVICE_TYPE_UNKNOWN:
392         case CONNMAN_SERVICE_TYPE_SYSTEM:
393         case CONNMAN_SERVICE_TYPE_GPS:
394         case CONNMAN_SERVICE_TYPE_VPN:
395         case CONNMAN_SERVICE_TYPE_GADGET:
396                 break;
397         case CONNMAN_SERVICE_TYPE_ETHERNET:
398                 return "Wired";
399         case CONNMAN_SERVICE_TYPE_WIFI:
400                 return "WiFi";
401         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
402                 return "Bluetooth";
403         case CONNMAN_SERVICE_TYPE_CELLULAR:
404                 return "Cellular";
405         }
406
407         return NULL;
408 }
409
410 static void technology_save(struct connman_technology *technology)
411 {
412         GKeyFile *keyfile;
413         gchar *identifier;
414
415         DBG("technology %p", technology);
416
417         keyfile = __connman_storage_load_global();
418         if (keyfile == NULL)
419                 keyfile = g_key_file_new();
420
421         identifier = g_strdup_printf("%s", get_name(technology->type));
422         if (identifier == NULL)
423                 goto done;
424
425         g_key_file_set_boolean(keyfile, identifier, "Enable",
426                                 technology->enable_persistent);
427
428         if (technology->tethering_ident != NULL)
429                 g_key_file_set_string(keyfile, identifier,
430                                         "Tethering.Identifier",
431                                         technology->tethering_ident);
432
433         if (technology->tethering_passphrase != NULL)
434                 g_key_file_set_string(keyfile, identifier,
435                                         "Tethering.Passphrase",
436                                         technology->tethering_passphrase);
437
438 done:
439         g_free(identifier);
440
441         __connman_storage_save_global(keyfile);
442
443         g_key_file_free(keyfile);
444
445         return;
446 }
447
448 static void technology_load(struct connman_technology *technology)
449 {
450         GKeyFile *keyfile;
451         gchar *identifier;
452         GError *error = NULL;
453         connman_bool_t enable;
454
455         DBG("technology %p", technology);
456
457         keyfile = __connman_storage_load_global();
458         /* Fallback on disabling technology if file not found. */
459         if (keyfile == NULL) {
460                 if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET)
461                         /* We enable ethernet by default */
462                         technology->enable_persistent = TRUE;
463                 else
464                         technology->enable_persistent = FALSE;
465                 return;
466         }
467
468         identifier = g_strdup_printf("%s", get_name(technology->type));
469         if (identifier == NULL)
470                 goto done;
471
472         enable = g_key_file_get_boolean(keyfile, identifier, "Enable", &error);
473         if (error == NULL)
474                 technology->enable_persistent = enable;
475         else {
476                 if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET)
477                         technology->enable_persistent = TRUE;
478                 else
479                         technology->enable_persistent = FALSE;
480
481                 technology_save(technology);
482                 g_clear_error(&error);
483         }
484
485         technology->tethering_ident = g_key_file_get_string(keyfile,
486                                 identifier, "Tethering.Identifier", NULL);
487
488         technology->tethering_passphrase = g_key_file_get_string(keyfile,
489                                 identifier, "Tethering.Passphrase", NULL);
490 done:
491         g_free(identifier);
492
493         g_key_file_free(keyfile);
494
495         return;
496 }
497
498 connman_bool_t __connman_technology_get_offlinemode(void)
499 {
500         return global_offlinemode;
501 }
502
503 static void connman_technology_save_offlinemode()
504 {
505         GKeyFile *keyfile;
506
507         keyfile = __connman_storage_load_global();
508         if (keyfile == NULL)
509                 keyfile = g_key_file_new();
510
511         g_key_file_set_boolean(keyfile, "global",
512                                         "OfflineMode", global_offlinemode);
513
514         __connman_storage_save_global(keyfile);
515
516         g_key_file_free(keyfile);
517
518         return;
519 }
520
521 static connman_bool_t connman_technology_load_offlinemode()
522 {
523         GKeyFile *keyfile;
524         GError *error = NULL;
525         connman_bool_t offlinemode;
526
527         /* If there is a error, we enable offlinemode */
528         keyfile = __connman_storage_load_global();
529         if (keyfile == NULL)
530                 return FALSE;
531
532         offlinemode = g_key_file_get_boolean(keyfile, "global",
533                                                 "OfflineMode", &error);
534         if (error != NULL) {
535                 offlinemode = FALSE;
536                 g_clear_error(&error);
537         }
538
539         g_key_file_free(keyfile);
540
541         return offlinemode;
542 }
543
544 static void append_properties(DBusMessageIter *iter,
545                 struct connman_technology *technology)
546 {
547         DBusMessageIter dict;
548         const char *str;
549
550         connman_dbus_dict_open(iter, &dict);
551
552         str = get_name(technology->type);
553         if (str != NULL)
554                 connman_dbus_dict_append_basic(&dict, "Name",
555                                                 DBUS_TYPE_STRING, &str);
556
557         str = __connman_service_type2string(technology->type);
558         if (str != NULL)
559                 connman_dbus_dict_append_basic(&dict, "Type",
560                                                 DBUS_TYPE_STRING, &str);
561
562         __sync_synchronize();
563         connman_dbus_dict_append_basic(&dict, "Powered",
564                                         DBUS_TYPE_BOOLEAN,
565                                         &technology->enabled);
566
567         connman_dbus_dict_append_basic(&dict, "Connected",
568                                         DBUS_TYPE_BOOLEAN,
569                                         &technology->connected);
570
571         connman_dbus_dict_append_basic(&dict, "Tethering",
572                                         DBUS_TYPE_BOOLEAN,
573                                         &technology->tethering);
574
575         if (technology->tethering_ident != NULL)
576                 connman_dbus_dict_append_basic(&dict, "TetheringIdentifier",
577                                         DBUS_TYPE_STRING,
578                                         &technology->tethering_ident);
579
580         if (technology->tethering_passphrase != NULL)
581                 connman_dbus_dict_append_basic(&dict, "TetheringPassphrase",
582                                         DBUS_TYPE_STRING,
583                                         &technology->tethering_passphrase);
584
585         connman_dbus_dict_close(iter, &dict);
586 }
587
588 static void technology_added_signal(struct connman_technology *technology)
589 {
590         DBusMessage *signal;
591         DBusMessageIter iter;
592
593         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
594                         CONNMAN_MANAGER_INTERFACE, "TechnologyAdded");
595         if (signal == NULL)
596                 return;
597
598         dbus_message_iter_init_append(signal, &iter);
599         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
600                                                         &technology->path);
601         append_properties(&iter, technology);
602
603         dbus_connection_send(connection, signal, NULL);
604         dbus_message_unref(signal);
605 }
606
607 static void technology_removed_signal(struct connman_technology *technology)
608 {
609         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
610                         CONNMAN_MANAGER_INTERFACE, "TechnologyRemoved",
611                         DBUS_TYPE_OBJECT_PATH, &technology->path,
612                         DBUS_TYPE_INVALID);
613 }
614
615 static DBusMessage *get_properties(DBusConnection *conn,
616                                         DBusMessage *message, void *user_data)
617 {
618         struct connman_technology *technology = user_data;
619         DBusMessage *reply;
620         DBusMessageIter iter;
621
622         reply = dbus_message_new_method_return(message);
623         if (reply == NULL)
624                 return NULL;
625
626         dbus_message_iter_init_append(reply, &iter);
627         append_properties(&iter, technology);
628
629         return reply;
630 }
631
632 void __connman_technology_list_struct(DBusMessageIter *array)
633 {
634         GSList *list;
635         DBusMessageIter entry;
636
637         for (list = technology_list; list; list = list->next) {
638                 struct connman_technology *technology = list->data;
639
640                 if (technology->path == NULL ||
641                                 (technology->rfkill_driven == TRUE &&
642                                  technology->hardblocked == TRUE))
643                         continue;
644
645                 dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
646                                 NULL, &entry);
647                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
648                                 &technology->path);
649                 append_properties(&entry, technology);
650                 dbus_message_iter_close_container(array, &entry);
651         }
652 }
653
654 static gboolean technology_pending_reply(gpointer user_data)
655 {
656         struct connman_technology *technology = user_data;
657         DBusMessage *reply;
658
659         /* Power request timedout, send ETIMEDOUT. */
660         if (technology->pending_reply != NULL) {
661                 reply = __connman_error_failed(technology->pending_reply, ETIMEDOUT);
662                 if (reply != NULL)
663                         g_dbus_send_message(connection, reply);
664
665                 dbus_message_unref(technology->pending_reply);
666                 technology->pending_reply = NULL;
667                 technology->pending_timeout = 0;
668         }
669
670         return FALSE;
671 }
672
673 static int technology_affect_devices(struct connman_technology *technology,
674                                                 connman_bool_t enable_device)
675 {
676         GSList *list;
677         int err = 0;
678
679         for (list = technology->device_list; list; list = list->next) {
680                 struct connman_device *device = list->data;
681
682                 if (enable_device == TRUE)
683                         err = __connman_device_enable(device);
684                 else
685                         err = __connman_device_disable(device);
686         }
687
688         return err;
689 }
690
691 static int technology_enable(struct connman_technology *technology)
692 {
693         int err = 0;
694         int err_dev;
695
696         DBG("technology %p enable", technology);
697
698         __sync_synchronize();
699         if (technology->enabled == TRUE)
700                 return -EALREADY;
701
702         if (technology->pending_reply != NULL)
703                 return -EBUSY;
704
705         if (technology->rfkill_driven == TRUE)
706                 err = __connman_rfkill_block(technology->type, FALSE);
707
708         err_dev = technology_affect_devices(technology, TRUE);
709
710         if (technology->rfkill_driven == FALSE)
711                 err = err_dev;
712
713         return err;
714 }
715
716 static int technology_disable(struct connman_technology *technology)
717 {
718         int err;
719
720         DBG("technology %p disable", technology);
721
722         __sync_synchronize();
723         if (technology->enabled == FALSE)
724                 return -EALREADY;
725
726         if (technology->pending_reply != NULL)
727                 return -EBUSY;
728
729         if (technology->tethering == TRUE)
730                 set_tethering(technology, FALSE);
731
732         err = technology_affect_devices(technology, FALSE);
733
734         if (technology->rfkill_driven == TRUE)
735                 err = __connman_rfkill_block(technology->type, TRUE);
736
737         return err;
738 }
739
740 static DBusMessage *set_powered(struct connman_technology *technology,
741                                 DBusMessage *msg, connman_bool_t powered)
742 {
743         DBusMessage *reply = NULL;
744         int err = 0;
745
746         if (technology->rfkill_driven && technology->hardblocked == TRUE) {
747                 err = -EACCES;
748                 goto make_reply;
749         }
750
751         if (powered == TRUE)
752                 err = technology_enable(technology);
753         else
754                 err = technology_disable(technology);
755
756         if (err != -EBUSY) {
757                 technology->enable_persistent = powered;
758                 technology_save(technology);
759         }
760
761 make_reply:
762         if (err == -EINPROGRESS) {
763                 technology->pending_reply = dbus_message_ref(msg);
764                 technology->pending_timeout = g_timeout_add_seconds(10,
765                                         technology_pending_reply, technology);
766         } else if (err == -EALREADY) {
767                 if (powered == TRUE)
768                         reply = __connman_error_already_enabled(msg);
769                 else
770                         reply = __connman_error_already_disabled(msg);
771         } else if (err < 0)
772                 reply = __connman_error_failed(msg, -err);
773         else
774                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
775
776         return reply;
777 }
778
779 static DBusMessage *set_property(DBusConnection *conn,
780                                         DBusMessage *msg, void *data)
781 {
782         struct connman_technology *technology = data;
783         DBusMessageIter iter, value;
784         const char *name;
785         int type;
786
787         DBG("conn %p", conn);
788
789         if (dbus_message_iter_init(msg, &iter) == FALSE)
790                 return __connman_error_invalid_arguments(msg);
791
792         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
793                 return __connman_error_invalid_arguments(msg);
794
795         dbus_message_iter_get_basic(&iter, &name);
796         dbus_message_iter_next(&iter);
797
798         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
799                 return __connman_error_invalid_arguments(msg);
800
801         dbus_message_iter_recurse(&iter, &value);
802
803         type = dbus_message_iter_get_arg_type(&value);
804
805         DBG("property %s", name);
806
807         if (g_str_equal(name, "Tethering") == TRUE) {
808                 int err;
809                 connman_bool_t tethering;
810
811                 if (type != DBUS_TYPE_BOOLEAN)
812                         return __connman_error_invalid_arguments(msg);
813
814                 if (connman_technology_is_tethering_allowed(technology->type)
815                                                                 == FALSE) {
816                         DBG("%s tethering not allowed by config file",
817                                 __connman_service_type2string(technology->type));
818                         return __connman_error_not_supported(msg);
819                 }
820
821                 dbus_message_iter_get_basic(&value, &tethering);
822
823                 if (technology->tethering == tethering) {
824                         if (tethering == FALSE)
825                                 return __connman_error_already_disabled(msg);
826                         else
827                                 return __connman_error_already_enabled(msg);
828                 }
829
830                 err = set_tethering(technology, tethering);
831                 if (err < 0)
832                         return __connman_error_failed(msg, -err);
833
834         } else if (g_str_equal(name, "TetheringIdentifier") == TRUE) {
835                 const char *str;
836
837                 dbus_message_iter_get_basic(&value, &str);
838
839                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
840                         return __connman_error_not_supported(msg);
841
842                 if (strlen(str) < 1 || strlen(str) > 32)
843                         return __connman_error_invalid_arguments(msg);
844
845                 if (g_strcmp0(technology->tethering_ident, str) != 0) {
846                         g_free(technology->tethering_ident);
847                         technology->tethering_ident = g_strdup(str);
848                         technology_save(technology);
849
850                         connman_dbus_property_changed_basic(technology->path,
851                                                 CONNMAN_TECHNOLOGY_INTERFACE,
852                                                 "TetheringIdentifier",
853                                                 DBUS_TYPE_STRING,
854                                                 &technology->tethering_ident);
855                 }
856         } else if (g_str_equal(name, "TetheringPassphrase") == TRUE) {
857                 const char *str;
858
859                 dbus_message_iter_get_basic(&value, &str);
860
861                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
862                         return __connman_error_not_supported(msg);
863
864                 if (strlen(str) < 8 || strlen(str) > 63)
865                         return __connman_error_passphrase_required(msg);
866
867                 if (g_strcmp0(technology->tethering_passphrase, str) != 0) {
868                         g_free(technology->tethering_passphrase);
869                         technology->tethering_passphrase = g_strdup(str);
870                         technology_save(technology);
871
872                         connman_dbus_property_changed_basic(technology->path,
873                                         CONNMAN_TECHNOLOGY_INTERFACE,
874                                         "TetheringPassphrase",
875                                         DBUS_TYPE_STRING,
876                                         &technology->tethering_passphrase);
877                 }
878         } else if (g_str_equal(name, "Powered") == TRUE) {
879                 connman_bool_t enable;
880
881                 if (type != DBUS_TYPE_BOOLEAN)
882                         return __connman_error_invalid_arguments(msg);
883
884                 dbus_message_iter_get_basic(&value, &enable);
885
886                 return set_powered(technology, msg, enable);
887         } else
888                 return __connman_error_invalid_property(msg);
889
890         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
891 }
892
893 static void reply_scan_pending(struct connman_technology *technology, int err)
894 {
895         DBusMessage *reply;
896
897         DBG("technology %p err %d", technology, err);
898
899         while (technology->scan_pending != NULL) {
900                 DBusMessage *msg = technology->scan_pending->data;
901
902                 DBG("reply to %s", dbus_message_get_sender(msg));
903
904                 if (err == 0)
905                         reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
906                 else
907                         reply = __connman_error_failed(msg, -err);
908                 g_dbus_send_message(connection, reply);
909                 dbus_message_unref(msg);
910
911                 technology->scan_pending =
912                         g_slist_delete_link(technology->scan_pending,
913                                         technology->scan_pending);
914         }
915 }
916
917 void __connman_technology_scan_started(struct connman_device *device)
918 {
919         DBG("device %p", device);
920 }
921
922 void __connman_technology_scan_stopped(struct connman_device *device)
923 {
924         int count = 0;
925         struct connman_technology *technology;
926         enum connman_service_type type;
927         GSList *list;
928
929         type = __connman_device_get_service_type(device);
930         technology = technology_find(type);
931
932         DBG("technology %p device %p", technology, device);
933
934         if (technology == NULL)
935                 return;
936
937         for (list = technology->device_list; list != NULL; list = list->next) {
938                 struct connman_device *other_device = list->data;
939
940                 if (device == other_device)
941                         continue;
942
943                 if (__connman_device_get_service_type(other_device) != type)
944                         continue;
945
946                 if (connman_device_get_scanning(other_device) == TRUE)
947                         count += 1;
948         }
949
950         if (count == 0)
951                 reply_scan_pending(technology, 0);
952 }
953
954 void __connman_technology_notify_regdom_by_device(struct connman_device *device,
955                                                 int result, const char *alpha2)
956 {
957         connman_bool_t regdom_set = FALSE;
958         struct connman_technology *technology;
959         enum connman_service_type type;
960         GSList *tech_drivers;
961
962         type = __connman_device_get_service_type(device);
963         technology = technology_find(type);
964
965         if (technology == NULL)
966                 return;
967
968         if (result < 0) {
969
970                 for (tech_drivers = technology->driver_list;
971                      tech_drivers != NULL;
972                      tech_drivers = g_slist_next(tech_drivers)) {
973                         struct connman_technology_driver *driver =
974                                 tech_drivers->data;
975
976                         if (driver->set_regdom != NULL) {
977                                 driver->set_regdom(technology, alpha2);
978                                 regdom_set = TRUE;
979                         }
980
981                 }
982
983                 if (regdom_set == FALSE)
984                         alpha2 = NULL;
985         }
986
987         connman_technology_regdom_notify(technology, alpha2);
988 }
989
990 static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data)
991 {
992         struct connman_technology *technology = data;
993         int err;
994
995         DBG ("technology %p request from %s", technology,
996                         dbus_message_get_sender(msg));
997
998         dbus_message_ref(msg);
999         technology->scan_pending =
1000                 g_slist_prepend(technology->scan_pending, msg);
1001
1002         err = __connman_device_request_scan(technology->type);
1003         if (err < 0)
1004                 reply_scan_pending(technology, err);
1005
1006         return NULL;
1007 }
1008
1009 static const GDBusMethodTable technology_methods[] = {
1010         { GDBUS_DEPRECATED_METHOD("GetProperties",
1011                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
1012                         get_properties) },
1013         { GDBUS_ASYNC_METHOD("SetProperty",
1014                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
1015                         NULL, set_property) },
1016         { GDBUS_ASYNC_METHOD("Scan", NULL, NULL, scan) },
1017         { },
1018 };
1019
1020 static const GDBusSignalTable technology_signals[] = {
1021         { GDBUS_SIGNAL("PropertyChanged",
1022                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
1023         { },
1024 };
1025
1026 static gboolean technology_dbus_register(struct connman_technology *technology)
1027 {
1028         if (technology->dbus_registered == TRUE ||
1029                                 (technology->rfkill_driven == TRUE &&
1030                                  technology->hardblocked == TRUE))
1031                 return TRUE;
1032
1033         if (g_dbus_register_interface(connection, technology->path,
1034                                 CONNMAN_TECHNOLOGY_INTERFACE,
1035                                 technology_methods, technology_signals,
1036                                 NULL, technology, NULL) == FALSE) {
1037                 connman_error("Failed to register %s", technology->path);
1038                 return FALSE;
1039         }
1040
1041         technology_added_signal(technology);
1042         technology->dbus_registered = TRUE;
1043
1044         return TRUE;
1045 }
1046
1047 static struct connman_technology *technology_get(enum connman_service_type type)
1048 {
1049         GSList *tech_drivers = NULL;
1050         struct connman_technology_driver *driver;
1051         struct connman_technology *technology;
1052         const char *str;
1053         GSList *list;
1054
1055         DBG("type %d", type);
1056
1057         str = __connman_service_type2string(type);
1058         if (str == NULL)
1059                 return NULL;
1060
1061         technology = technology_find(type);
1062         if (technology != NULL) {
1063                 __sync_fetch_and_add(&technology->refcount, 1);
1064                 return technology;
1065         }
1066
1067         /* First check if we have a driver for this technology type */
1068         for (list = driver_list; list; list = list->next) {
1069                 driver = list->data;
1070
1071                 if (driver->type == type) {
1072                         DBG("technology %p driver %p", technology, driver);
1073                         tech_drivers = g_slist_append(tech_drivers, driver);
1074                 }
1075         }
1076
1077         if (tech_drivers == NULL) {
1078                 DBG("No matching drivers found for %s.",
1079                                 __connman_service_type2string(type));
1080                 return NULL;
1081         }
1082
1083         technology = g_try_new0(struct connman_technology, 1);
1084         if (technology == NULL)
1085                 return NULL;
1086
1087         technology->refcount = 1;
1088
1089         technology->rfkill_driven = FALSE;
1090         technology->softblocked = FALSE;
1091         technology->hardblocked = FALSE;
1092
1093         technology->type = type;
1094         technology->path = g_strdup_printf("%s/technology/%s",
1095                                                         CONNMAN_PATH, str);
1096
1097         technology->device_list = NULL;
1098
1099         technology->pending_reply = NULL;
1100
1101         technology_load(technology);
1102
1103         if (technology_dbus_register(technology) == FALSE) {
1104                 g_free(technology);
1105                 return NULL;
1106         }
1107
1108         technology_list = g_slist_prepend(technology_list, technology);
1109
1110         technology->driver_list = tech_drivers;
1111
1112         for (list = tech_drivers; list != NULL; list = g_slist_next(list)) {
1113                 driver = list->data;
1114
1115                 if (driver->probe != NULL && driver->probe(technology) < 0)
1116                         DBG("Driver probe failed for technology %p",
1117                                         technology);
1118         }
1119
1120         DBG("technology %p", technology);
1121
1122         return technology;
1123 }
1124
1125 static void technology_dbus_unregister(struct connman_technology *technology)
1126 {
1127         if (technology->dbus_registered == FALSE)
1128                 return;
1129
1130         technology_removed_signal(technology);
1131         g_dbus_unregister_interface(connection, technology->path,
1132                 CONNMAN_TECHNOLOGY_INTERFACE);
1133
1134         technology->dbus_registered = FALSE;
1135 }
1136
1137 static void technology_put(struct connman_technology *technology)
1138 {
1139         DBG("technology %p", technology);
1140
1141         if (__sync_sub_and_fetch(&technology->refcount, 1) > 0)
1142                 return;
1143
1144         reply_scan_pending(technology, -EINTR);
1145
1146         while (technology->driver_list != NULL) {
1147                 struct connman_technology_driver *driver;
1148
1149                 driver = technology->driver_list->data;
1150
1151                 if (driver->remove != NULL)
1152                         driver->remove(technology);
1153
1154                 technology->driver_list =
1155                         g_slist_delete_link(technology->driver_list,
1156                                         technology->driver_list);
1157         }
1158
1159         technology_list = g_slist_remove(technology_list, technology);
1160
1161         technology_dbus_unregister(technology);
1162
1163         g_slist_free(technology->device_list);
1164
1165         g_free(technology->path);
1166         g_free(technology->regdom);
1167         g_free(technology->tethering_ident);
1168         g_free(technology->tethering_passphrase);
1169         g_free(technology);
1170 }
1171
1172 void __connman_technology_add_interface(enum connman_service_type type,
1173                                 int index, const char *name, const char *ident)
1174 {
1175         struct connman_technology *technology;
1176         GSList *tech_drivers;
1177         struct connman_technology_driver *driver;
1178
1179         switch (type) {
1180         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1181         case CONNMAN_SERVICE_TYPE_SYSTEM:
1182                 return;
1183         case CONNMAN_SERVICE_TYPE_ETHERNET:
1184         case CONNMAN_SERVICE_TYPE_WIFI:
1185         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1186         case CONNMAN_SERVICE_TYPE_CELLULAR:
1187         case CONNMAN_SERVICE_TYPE_GPS:
1188         case CONNMAN_SERVICE_TYPE_VPN:
1189         case CONNMAN_SERVICE_TYPE_GADGET:
1190                 break;
1191         }
1192
1193         connman_info("Adding interface %s [ %s ]", name,
1194                                 __connman_service_type2string(type));
1195
1196         technology = technology_find(type);
1197
1198         if (technology == NULL)
1199                 return;
1200
1201         for (tech_drivers = technology->driver_list; tech_drivers != NULL;
1202              tech_drivers = g_slist_next(tech_drivers)) {
1203                 driver = tech_drivers->data;
1204
1205                 if(driver->add_interface != NULL)
1206                         driver->add_interface(technology, index, name, ident);
1207         }
1208 }
1209
1210 void __connman_technology_remove_interface(enum connman_service_type type,
1211                                 int index, const char *name, const char *ident)
1212 {
1213         struct connman_technology *technology;
1214         GSList *tech_drivers;
1215         struct connman_technology_driver *driver;
1216
1217         switch (type) {
1218         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1219         case CONNMAN_SERVICE_TYPE_SYSTEM:
1220                 return;
1221         case CONNMAN_SERVICE_TYPE_ETHERNET:
1222         case CONNMAN_SERVICE_TYPE_WIFI:
1223         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1224         case CONNMAN_SERVICE_TYPE_CELLULAR:
1225         case CONNMAN_SERVICE_TYPE_GPS:
1226         case CONNMAN_SERVICE_TYPE_VPN:
1227         case CONNMAN_SERVICE_TYPE_GADGET:
1228                 break;
1229         }
1230
1231         connman_info("Remove interface %s [ %s ]", name,
1232                                 __connman_service_type2string(type));
1233
1234         technology = technology_find(type);
1235
1236         if (technology == NULL)
1237                 return;
1238
1239         for (tech_drivers = technology->driver_list; tech_drivers != NULL;
1240              tech_drivers = g_slist_next(tech_drivers)) {
1241                 driver = tech_drivers->data;
1242
1243                 if(driver->remove_interface != NULL)
1244                         driver->remove_interface(technology, index);
1245         }
1246 }
1247
1248 int __connman_technology_add_device(struct connman_device *device)
1249 {
1250         struct connman_technology *technology;
1251         enum connman_service_type type;
1252
1253         DBG("device %p", device);
1254
1255         type = __connman_device_get_service_type(device);
1256
1257         technology = technology_get(type);
1258         if (technology == NULL) {
1259                 /*
1260                  * Since no driver can be found for this device at the moment we
1261                  * add it to the techless device list.
1262                 */
1263                 techless_device_list = g_slist_prepend(techless_device_list,
1264                                                                 device);
1265
1266                 return -ENXIO;
1267         }
1268
1269         __sync_synchronize();
1270         if (technology->rfkill_driven == TRUE) {
1271                 if (technology->enabled == TRUE)
1272                         __connman_device_enable(device);
1273                 else
1274                         __connman_device_disable(device);
1275
1276                 goto done;
1277         }
1278
1279         if (technology->enable_persistent == TRUE &&
1280                                         global_offlinemode == FALSE) {
1281                 int err = __connman_device_enable(device);
1282                 /*
1283                  * connman_technology_add_device() calls __connman_device_enable()
1284                  * but since the device is already enabled, the calls does not
1285                  * propagate through to connman_technology_enabled via
1286                  * connman_device_set_powered.
1287                  */
1288                 if (err == -EALREADY)
1289                         __connman_technology_enabled(type);
1290         }
1291         /* if technology persistent state is offline */
1292         if (technology->enable_persistent == FALSE)
1293                 __connman_device_disable(device);
1294
1295 done:
1296         technology->device_list = g_slist_prepend(technology->device_list,
1297                                                                 device);
1298
1299         return 0;
1300 }
1301
1302 int __connman_technology_remove_device(struct connman_device *device)
1303 {
1304         struct connman_technology *technology;
1305         enum connman_service_type type;
1306
1307         DBG("device %p", device);
1308
1309         type = __connman_device_get_service_type(device);
1310
1311         technology = technology_find(type);
1312         if (technology == NULL) {
1313                 techless_device_list = g_slist_remove(techless_device_list,
1314                                                                 device);
1315                 return -ENXIO;
1316         }
1317
1318         technology->device_list = g_slist_remove(technology->device_list,
1319                                                                 device);
1320         technology_put(technology);
1321
1322         return 0;
1323 }
1324
1325 static void powered_changed(struct connman_technology *technology)
1326 {
1327         if (technology->dbus_registered == FALSE)
1328                 return;
1329
1330         if (technology->pending_reply != NULL) {
1331                 g_dbus_send_reply(connection,
1332                                 technology->pending_reply, DBUS_TYPE_INVALID);
1333                 dbus_message_unref(technology->pending_reply);
1334                 technology->pending_reply = NULL;
1335
1336                 g_source_remove(technology->pending_timeout);
1337                 technology->pending_timeout = 0;
1338         }
1339
1340         __sync_synchronize();
1341         connman_dbus_property_changed_basic(technology->path,
1342                         CONNMAN_TECHNOLOGY_INTERFACE, "Powered",
1343                         DBUS_TYPE_BOOLEAN, &technology->enabled);
1344 }
1345
1346 static int technology_enabled(struct connman_technology *technology)
1347 {
1348         __sync_synchronize();
1349         if (technology->enabled == TRUE)
1350                 return -EALREADY;
1351
1352         technology->enabled = TRUE;
1353
1354         powered_changed(technology);
1355
1356         return 0;
1357 }
1358
1359 int __connman_technology_enabled(enum connman_service_type type)
1360 {
1361         struct connman_technology *technology;
1362
1363         technology = technology_find(type);
1364         if (technology == NULL)
1365                 return -ENXIO;
1366
1367         if (technology->rfkill_driven == TRUE)
1368                 return 0;
1369
1370         return technology_enabled(technology);
1371 }
1372
1373 static int technology_disabled(struct connman_technology *technology)
1374 {
1375         __sync_synchronize();
1376         if (technology->enabled == FALSE)
1377                 return -EALREADY;
1378
1379         technology->enabled = FALSE;
1380
1381         powered_changed(technology);
1382
1383         return 0;
1384 }
1385
1386 int __connman_technology_disabled(enum connman_service_type type)
1387 {
1388         struct connman_technology *technology;
1389         GSList *list;
1390
1391         technology = technology_find(type);
1392         if (technology == NULL)
1393                 return -ENXIO;
1394
1395         if (technology->rfkill_driven == TRUE)
1396                 return 0;
1397
1398         for (list = technology->device_list; list != NULL; list = list->next) {
1399                 struct connman_device *device = list->data;
1400
1401                 if (connman_device_get_powered(device) == TRUE)
1402                         return 0;
1403         }
1404
1405         return technology_disabled(technology);
1406 }
1407
1408 int __connman_technology_set_offlinemode(connman_bool_t offlinemode)
1409 {
1410         GSList *list;
1411         int err = -EINVAL;
1412
1413         if (global_offlinemode == offlinemode)
1414                 return 0;
1415
1416         DBG("offlinemode %s", offlinemode ? "On" : "Off");
1417
1418         /*
1419          * This is a bit tricky. When you set offlinemode, there is no
1420          * way to differentiate between attempting offline mode and
1421          * resuming offlinemode from last saved profile. We need that
1422          * information in rfkill_update, otherwise it falls back on the
1423          * technology's persistent state. Hence we set the offline mode here
1424          * but save it & call the notifier only if its successful.
1425          */
1426
1427         global_offlinemode = offlinemode;
1428
1429         /* Traverse technology list, enable/disable each technology. */
1430         for (list = technology_list; list; list = list->next) {
1431                 struct connman_technology *technology = list->data;
1432
1433                 if (offlinemode)
1434                         err = technology_disable(technology);
1435
1436                 if (!offlinemode && technology->enable_persistent)
1437                         err = technology_enable(technology);
1438         }
1439
1440         if (err == 0 || err == -EINPROGRESS || err == -EALREADY) {
1441                 connman_technology_save_offlinemode();
1442                 __connman_notifier_offlinemode(offlinemode);
1443         } else
1444                 global_offlinemode = connman_technology_load_offlinemode();
1445
1446         return err;
1447 }
1448
1449 void __connman_technology_set_connected(enum connman_service_type type,
1450                 connman_bool_t connected)
1451 {
1452         struct connman_technology *technology;
1453
1454         technology = technology_find(type);
1455         if (technology == NULL)
1456                 return;
1457
1458         DBG("technology %p connected %d", technology, connected);
1459
1460         technology->connected = connected;
1461
1462         connman_dbus_property_changed_basic(technology->path,
1463                         CONNMAN_TECHNOLOGY_INTERFACE, "Connected",
1464                         DBUS_TYPE_BOOLEAN, &connected);
1465 }
1466
1467 static connman_bool_t technology_apply_rfkill_change(struct connman_technology *technology,
1468                                                 connman_bool_t softblock,
1469                                                 connman_bool_t hardblock,
1470                                                 connman_bool_t new_rfkill)
1471 {
1472         gboolean hardblock_changed = FALSE;
1473         gboolean apply = TRUE;
1474         GList *start, *list;
1475
1476         DBG("technology %p --> %d/%d vs %d/%d",
1477                         technology, softblock, hardblock,
1478                         technology->softblocked, technology->hardblocked);
1479
1480         if (technology->hardblocked == hardblock)
1481                 goto softblock_change;
1482
1483         if (!(new_rfkill == TRUE && hardblock == FALSE)) {
1484                 start = g_hash_table_get_values(rfkill_list);
1485
1486                 for (list = start; list != NULL; list = list->next) {
1487                         struct connman_rfkill *rfkill = list->data;
1488
1489                         if (rfkill->type != technology->type)
1490                                 continue;
1491
1492                         if (rfkill->hardblock != hardblock)
1493                                 apply = FALSE;
1494                 }
1495
1496                 g_list_free(start);
1497         }
1498
1499         if (apply == FALSE)
1500                 goto softblock_change;
1501
1502         technology->hardblocked = hardblock;
1503         hardblock_changed = TRUE;
1504
1505 softblock_change:
1506         if (apply == FALSE && technology->softblocked != softblock)
1507                 apply = TRUE;
1508
1509         if (apply == FALSE)
1510                 return technology->hardblocked;
1511
1512         technology->softblocked = softblock;
1513
1514         if (technology->hardblocked == TRUE ||
1515                                         technology->softblocked == TRUE) {
1516                 if (technology_disabled(technology) != -EALREADY)
1517                         technology_affect_devices(technology, FALSE);
1518         } else if (technology->hardblocked == FALSE &&
1519                                         technology->softblocked == FALSE) {
1520                 if (technology_enabled(technology) != -EALREADY)
1521                         technology_affect_devices(technology, TRUE);
1522         }
1523
1524         if (hardblock_changed == TRUE) {
1525                 if (technology->hardblocked == TRUE) {
1526                         DBG("%s is switched off.", get_name(technology->type));
1527                         technology_dbus_unregister(technology);
1528                 } else
1529                         technology_dbus_register(technology);
1530         }
1531
1532         return technology->hardblocked;
1533 }
1534
1535 int __connman_technology_add_rfkill(unsigned int index,
1536                                         enum connman_service_type type,
1537                                                 connman_bool_t softblock,
1538                                                 connman_bool_t hardblock)
1539 {
1540         struct connman_technology *technology;
1541         struct connman_rfkill *rfkill;
1542
1543         DBG("index %u type %d soft %u hard %u", index, type,
1544                                                         softblock, hardblock);
1545
1546         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1547         if (rfkill != NULL)
1548                 goto done;
1549
1550         rfkill = g_try_new0(struct connman_rfkill, 1);
1551         if (rfkill == NULL)
1552                 return -ENOMEM;
1553
1554         rfkill->index = index;
1555         rfkill->type = type;
1556         rfkill->softblock = softblock;
1557         rfkill->hardblock = hardblock;
1558
1559         g_hash_table_insert(rfkill_list, GINT_TO_POINTER(index), rfkill);
1560
1561 done:
1562         technology = technology_get(type);
1563         /* If there is no driver for this type, ignore it. */
1564         if (technology == NULL)
1565                 return -ENXIO;
1566
1567         technology->rfkill_driven = TRUE;
1568
1569         /* If hardblocked, there is no need to handle softblocked state */
1570         if (technology_apply_rfkill_change(technology,
1571                                 softblock, hardblock, TRUE) == TRUE)
1572                 return 0;
1573
1574         /*
1575          * Depending on softblocked state we unblock/block according to
1576          * offlinemode and persistente state.
1577          */
1578         if (technology->softblocked == TRUE &&
1579                                 global_offlinemode == FALSE &&
1580                                 technology->enable_persistent == TRUE)
1581                 return __connman_rfkill_block(type, FALSE);
1582         else if (technology->softblocked == FALSE &&
1583                         (global_offlinemode == TRUE ||
1584                                 technology->enable_persistent == FALSE))
1585                 return __connman_rfkill_block(type, TRUE);
1586
1587         return 0;
1588 }
1589
1590 int __connman_technology_update_rfkill(unsigned int index,
1591                                         enum connman_service_type type,
1592                                                 connman_bool_t softblock,
1593                                                 connman_bool_t hardblock)
1594 {
1595         struct connman_technology *technology;
1596         struct connman_rfkill *rfkill;
1597
1598         DBG("index %u soft %u hard %u", index, softblock, hardblock);
1599
1600         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1601         if (rfkill == NULL)
1602                 return -ENXIO;
1603
1604         if (rfkill->softblock == softblock &&
1605                                 rfkill->hardblock == hardblock)
1606                 return 0;
1607
1608         rfkill->softblock = softblock;
1609         rfkill->hardblock = hardblock;
1610
1611         technology = technology_find(type);
1612         /* If there is no driver for this type, ignore it. */
1613         if (technology == NULL)
1614                 return -ENXIO;
1615
1616         /* If hardblocked, there is no need to handle softblocked state */
1617         if (technology_apply_rfkill_change(technology,
1618                                 softblock, hardblock, FALSE) == TRUE)
1619                 return 0;
1620
1621         if (global_offlinemode == TRUE)
1622                 return 0;
1623
1624         /*
1625          * Depending on softblocked state we unblock/block according to
1626          * persistent state.
1627          */
1628         if (technology->softblocked == TRUE &&
1629                                 technology->enable_persistent == TRUE)
1630                 return __connman_rfkill_block(type, FALSE);
1631         else if (technology->softblocked == FALSE &&
1632                                 technology->enable_persistent == FALSE)
1633                 return __connman_rfkill_block(type, TRUE);
1634
1635         return 0;
1636 }
1637
1638 int __connman_technology_remove_rfkill(unsigned int index,
1639                                         enum connman_service_type type)
1640 {
1641         struct connman_technology *technology;
1642         struct connman_rfkill *rfkill;
1643
1644         DBG("index %u", index);
1645
1646         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
1647         if (rfkill == NULL)
1648                 return -ENXIO;
1649
1650         g_hash_table_remove(rfkill_list, GINT_TO_POINTER(index));
1651
1652         technology = technology_find(type);
1653         if (technology == NULL)
1654                 return -ENXIO;
1655
1656         technology_apply_rfkill_change(technology,
1657                 technology->softblocked, !technology->hardblocked, FALSE);
1658
1659         technology_put(technology);
1660
1661         return 0;
1662 }
1663
1664 int __connman_technology_init(void)
1665 {
1666         DBG("");
1667
1668         connection = connman_dbus_get_connection();
1669
1670         rfkill_list = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1671                                                         NULL, free_rfkill);
1672
1673         global_offlinemode = connman_technology_load_offlinemode();
1674
1675         /* This will create settings file if it is missing */
1676         connman_technology_save_offlinemode();
1677
1678         return 0;
1679 }
1680
1681 void __connman_technology_cleanup(void)
1682 {
1683         DBG("");
1684
1685         g_hash_table_destroy(rfkill_list);
1686
1687         dbus_connection_unref(connection);
1688 }