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