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