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