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