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