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