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