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