Merge tag 'upstream/1.40' 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 #if defined TIZEN_EXT
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <net/if.h>
32 #endif
33
34 #include <gdbus.h>
35
36 #include "connman.h"
37
38 static DBusConnection *connection;
39
40 static GSList *technology_list = NULL;
41
42 /*
43  * List of devices with no technology associated with them either because of
44  * no compiled in support or the driver is not yet loaded.
45 */
46 static GSList *techless_device_list = NULL;
47 static GHashTable *rfkill_list;
48
49 static bool global_offlinemode;
50
51 #if defined TIZEN_EXT
52 struct connman_scan_pending {
53         char *ifname;
54         connman_scan_type_e scan_type;
55         DBusMessage *msg;
56 };
57
58 struct connman_bssid_pending {
59         char *ifname;
60         unsigned char bssid[6];
61 };
62 #endif
63
64 struct connman_rfkill {
65         unsigned int index;
66         enum connman_service_type type;
67         bool softblock;
68         bool hardblock;
69 };
70
71 struct connman_technology {
72         int refcount;
73         enum connman_service_type type;
74         char *path;
75         GSList *device_list;
76         bool enabled;
77         char *regdom;
78         bool connected;
79
80         bool tethering;
81         bool tethering_persistent; /* Tells the save status, needed
82                                               * as offline mode might set
83                                               * tethering OFF.
84                                               */
85         char *tethering_ident;
86         char *tethering_passphrase;
87
88         bool enable_persistent; /* Save the tech state */
89
90         GSList *driver_list;
91
92         DBusMessage *pending_reply;
93         guint pending_timeout;
94
95         GSList *scan_pending;
96
97         bool rfkill_driven;
98         bool softblocked;
99         bool hardblocked;
100         bool dbus_registered;
101 #if defined TIZEN_EXT
102         char **enabled_devices;
103         unsigned int mac_policy;
104         unsigned int preassoc_mac_policy;
105         unsigned int random_mac_lifetime;
106 #endif
107 #if defined TIZEN_EXT_WIFI_MESH
108         DBusMessage *mesh_dbus_msg;
109 #endif
110 };
111
112 static GSList *driver_list = NULL;
113
114 static int technology_enabled(struct connman_technology *technology);
115 static int technology_disabled(struct connman_technology *technology);
116
117 static gint compare_priority(gconstpointer a, gconstpointer b)
118 {
119         const struct connman_technology_driver *driver1 = a;
120         const struct connman_technology_driver *driver2 = b;
121
122         return driver2->priority - driver1->priority;
123 }
124
125 static void rfkill_check(gpointer key, gpointer value, gpointer user_data)
126 {
127         struct connman_rfkill *rfkill = value;
128         enum connman_service_type type = GPOINTER_TO_INT(user_data);
129
130         /* Calling _technology_add_rfkill will update the tech. */
131         if (rfkill->type == type)
132                 __connman_technology_add_rfkill(rfkill->index, type,
133                                 rfkill->softblock, rfkill->hardblock);
134 }
135
136 bool
137 connman_technology_is_tethering_allowed(enum connman_service_type type)
138 {
139         static char *allowed_default[] = { "wifi", "bluetooth", "gadget",
140                                            NULL };
141         const char *type_str = __connman_service_type2string(type);
142         char **allowed;
143         int i;
144
145         if (!type_str)
146                 return false;
147
148         allowed = connman_setting_get_string_list("TetheringTechnologies");
149         if (!allowed)
150                 allowed = allowed_default;
151
152         for (i = 0; allowed[i]; i++) {
153                 if (g_strcmp0(allowed[i], type_str) == 0)
154                         return true;
155         }
156
157         return false;
158 }
159
160 static const char *get_name(enum connman_service_type type)
161 {
162         switch (type) {
163         case CONNMAN_SERVICE_TYPE_UNKNOWN:
164         case CONNMAN_SERVICE_TYPE_SYSTEM:
165         case CONNMAN_SERVICE_TYPE_GPS:
166         case CONNMAN_SERVICE_TYPE_VPN:
167                 break;
168         case CONNMAN_SERVICE_TYPE_GADGET:
169                 return "Gadget";
170         case CONNMAN_SERVICE_TYPE_ETHERNET:
171                 return "Wired";
172         case CONNMAN_SERVICE_TYPE_WIFI:
173                 return "WiFi";
174         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
175                 return "Bluetooth";
176         case CONNMAN_SERVICE_TYPE_CELLULAR:
177                 return "Cellular";
178         case CONNMAN_SERVICE_TYPE_P2P:
179                 return "P2P";
180 #if defined TIZEN_EXT_WIFI_MESH
181         case CONNMAN_SERVICE_TYPE_MESH:
182                 return "Mesh";
183 #endif
184         }
185
186         return NULL;
187 }
188
189 static void technology_save(struct connman_technology *technology)
190 {
191         GKeyFile *keyfile;
192         gchar *identifier;
193         const char *name = get_name(technology->type);
194
195         DBG("technology %p type %d name %s", technology, technology->type,
196                                                                         name);
197         if (!name)
198                 return;
199
200         keyfile = __connman_storage_load_global();
201         if (!keyfile)
202                 keyfile = g_key_file_new();
203
204         identifier = g_strdup_printf("%s", name);
205         if (!identifier)
206                 goto done;
207
208         g_key_file_set_boolean(keyfile, identifier, "Enable",
209                                 technology->enable_persistent);
210
211         g_key_file_set_boolean(keyfile, identifier, "Tethering",
212                                 technology->tethering_persistent);
213
214         if (technology->tethering_ident)
215                 g_key_file_set_string(keyfile, identifier,
216                                         "Tethering.Identifier",
217                                         technology->tethering_ident);
218
219         if (technology->tethering_passphrase) {
220                 char *enc = g_strescape(technology->tethering_passphrase, NULL);
221                 g_key_file_set_string(keyfile, identifier,
222                                         "Tethering.Passphrase", enc);
223                 g_free(enc);
224         }
225
226 #ifdef TIZEN_EXT
227         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI) {
228                 g_key_file_set_uint64(keyfile, identifier, "MacPolicy",
229                                         technology->mac_policy);
230
231                 g_key_file_set_uint64(keyfile, identifier, "PreassocMacPolicy",
232                                         technology->preassoc_mac_policy);
233
234                 g_key_file_set_uint64(keyfile, identifier, "RandomMacLifetime",
235                                         technology->random_mac_lifetime);
236         }
237 #endif /* TIZEN_EXT */
238
239 done:
240         g_free(identifier);
241
242         __connman_storage_save_global(keyfile);
243
244         g_key_file_free(keyfile);
245 }
246
247 static void tethering_changed(struct connman_technology *technology)
248 {
249         dbus_bool_t tethering = technology->tethering;
250
251         connman_dbus_property_changed_basic(technology->path,
252                                 CONNMAN_TECHNOLOGY_INTERFACE, "Tethering",
253                                                 DBUS_TYPE_BOOLEAN, &tethering);
254
255         technology_save(technology);
256 }
257
258 int connman_technology_tethering_notify(struct connman_technology *technology,
259                                                         bool enabled)
260 {
261         int err;
262
263         DBG("technology %p enabled %u", technology, enabled);
264
265         if (technology->tethering == enabled)
266                 return -EALREADY;
267
268         if (enabled) {
269                 err = __connman_tethering_set_enabled();
270                 if (err < 0)
271                         return err;
272         } else
273                 __connman_tethering_set_disabled();
274
275         technology->tethering = enabled;
276         tethering_changed(technology);
277
278         return 0;
279 }
280
281 static int set_tethering(struct connman_technology *technology,
282                                 bool enabled)
283 {
284         int result = -EOPNOTSUPP;
285         int err;
286         const char *ident, *passphrase, *bridge;
287         GSList *tech_drivers;
288
289         ident = technology->tethering_ident;
290         passphrase = technology->tethering_passphrase;
291
292         __sync_synchronize();
293         if (!technology->enabled)
294                 return -EACCES;
295
296         bridge = __connman_tethering_get_bridge();
297         if (!bridge)
298                 return -EOPNOTSUPP;
299
300         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI &&
301             (!ident || !passphrase))
302                 return -EINVAL;
303
304         for (tech_drivers = technology->driver_list; tech_drivers;
305              tech_drivers = g_slist_next(tech_drivers)) {
306                 struct connman_technology_driver *driver = tech_drivers->data;
307
308                 if (!driver || !driver->set_tethering)
309                         continue;
310
311                 err = driver->set_tethering(technology, ident, passphrase,
312                                 bridge, enabled);
313
314                 if (result == -EINPROGRESS)
315                         continue;
316
317                 if (err == -EINPROGRESS || err == 0)
318                         result = err;
319         }
320
321         return result;
322 }
323
324 void connman_technology_regdom_notify(struct connman_technology *technology,
325                                                         const char *alpha2)
326 {
327         DBG("");
328
329         if (!alpha2)
330                 connman_error("Failed to set regulatory domain");
331         else
332                 DBG("Regulatory domain set to %s", alpha2);
333
334         g_free(technology->regdom);
335         technology->regdom = g_strdup(alpha2);
336 }
337
338 static int set_regdom_by_device(struct connman_technology *technology,
339                                                         const char *alpha2)
340 {
341         GSList *list;
342
343         for (list = technology->device_list; list; list = list->next) {
344                 struct connman_device *device = list->data;
345
346                 if (connman_device_set_regdom(device, alpha2) != 0)
347                         return -ENOTSUP;
348         }
349
350         return 0;
351 }
352
353 int connman_technology_set_regdom(const char *alpha2)
354 {
355         GSList *list, *tech_drivers;
356
357         for (list = technology_list; list; list = list->next) {
358                 struct connman_technology *technology = list->data;
359
360                 if (set_regdom_by_device(technology, alpha2) != 0) {
361
362                         for (tech_drivers = technology->driver_list;
363                              tech_drivers;
364                              tech_drivers = g_slist_next(tech_drivers)) {
365
366                                 struct connman_technology_driver *driver =
367                                         tech_drivers->data;
368
369                                 if (driver->set_regdom)
370                                         driver->set_regdom(technology, alpha2);
371                         }
372                 }
373         }
374
375         return 0;
376 }
377
378 static struct connman_technology *technology_find(enum connman_service_type type)
379 {
380         GSList *list;
381
382         DBG("type %d", type);
383
384         for (list = technology_list; list; list = list->next) {
385                 struct connman_technology *technology = list->data;
386
387                 if (technology->type == type)
388                         return technology;
389         }
390
391         return NULL;
392 }
393
394 enum connman_service_type connman_technology_get_type
395                                 (struct connman_technology *technology)
396 {
397         if (!technology)
398                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
399
400         return technology->type;
401 }
402
403 bool connman_technology_get_wifi_tethering(const char **ssid,
404                                                         const char **psk)
405 {
406         struct connman_technology *technology;
407
408         if (!ssid || !psk)
409                 return false;
410
411         *ssid = *psk = NULL;
412
413         technology = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
414         if (!technology)
415                 return false;
416
417         if (!technology->tethering)
418                 return false;
419
420         *ssid = technology->tethering_ident;
421         *psk = technology->tethering_passphrase;
422
423         return true;
424 }
425
426 #if defined TIZEN_EXT
427 const char *connman_techonology_get_path(enum connman_service_type type)
428 {
429         struct connman_technology *technology = technology_find(type);
430
431         if (!technology)
432                 return NULL;
433
434         return technology->path;
435 }
436 #endif
437
438 static void free_rfkill(gpointer data)
439 {
440         struct connman_rfkill *rfkill = data;
441
442         g_free(rfkill);
443 }
444
445 static void technology_load(struct connman_technology *technology)
446 {
447         GKeyFile *keyfile;
448         gchar *identifier;
449         GError *error = NULL;
450         bool enable, need_saving = false;
451         char *enc;
452
453         DBG("technology %p", technology);
454
455         keyfile = __connman_storage_load_global();
456         /* Fallback on disabling technology if file not found. */
457         if (!keyfile) {
458                 if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET)
459                         /* We enable ethernet by default */
460                         technology->enable_persistent = true;
461                 else
462                         technology->enable_persistent = false;
463                 return;
464         }
465
466         identifier = g_strdup_printf("%s", get_name(technology->type));
467         if (!identifier)
468                 goto done;
469
470 #ifdef TIZEN_EXT
471         gsize length;
472         technology->enabled_devices = g_key_file_get_string_list(keyfile,
473                         identifier, "Enable.Devices", &length, NULL);
474         if (technology->enabled_devices && length == 0) {
475                 g_strfreev(technology->enabled_devices);
476                 technology->enabled_devices = NULL;
477         }
478 #endif
479
480         enable = g_key_file_get_boolean(keyfile, identifier, "Enable", &error);
481         if (!error)
482                 technology->enable_persistent = enable;
483         else {
484                 if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET)
485                         technology->enable_persistent = true;
486                 else
487                         technology->enable_persistent = false;
488
489                 need_saving = true;
490                 g_clear_error(&error);
491         }
492
493         enable = g_key_file_get_boolean(keyfile, identifier,
494                                         "Tethering", &error);
495         if (!error)
496                 technology->tethering_persistent = enable;
497         else {
498                 need_saving = true;
499                 g_clear_error(&error);
500         }
501
502         if (need_saving)
503                 technology_save(technology);
504
505         technology->tethering_ident = g_key_file_get_string(keyfile,
506                                 identifier, "Tethering.Identifier", NULL);
507
508         enc = g_key_file_get_string(keyfile,
509                                 identifier, "Tethering.Passphrase", NULL);
510         if (enc)
511                 technology->tethering_passphrase = g_strcompress(enc);
512 #ifdef TIZEN_EXT
513         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI) {
514                 unsigned int val = 0;
515
516                 val = g_key_file_get_uint64(keyfile,
517                                 identifier, "MacPolicy", NULL);
518                 if (val <= 2)
519                         technology->mac_policy = val;
520                 else
521                         technology->mac_policy = 0;
522
523                 val = g_key_file_get_uint64(keyfile,
524                                 identifier, "PreassocMacPolicy", NULL);
525                 if (val <= 2)
526                         technology->preassoc_mac_policy = val;
527                 else
528                         technology->preassoc_mac_policy = 0;
529
530                 val = g_key_file_get_uint64(keyfile,
531                                 identifier, "RandomMacLifetime", NULL);
532                 if (val > 0)
533                         technology->random_mac_lifetime = val;
534                 else
535                         technology->random_mac_lifetime = 60;
536         }
537 #endif /* TIZEN_EXT */
538
539 done:
540         g_free(identifier);
541
542         g_key_file_free(keyfile);
543 }
544
545 bool __connman_technology_get_offlinemode(void)
546 {
547         return global_offlinemode;
548 }
549
550 static void connman_technology_save_offlinemode(void)
551 {
552         GKeyFile *keyfile;
553         GError *error = NULL;
554         bool offlinemode;
555
556         keyfile = __connman_storage_load_global();
557
558         if (!keyfile) {
559                 keyfile = g_key_file_new();
560                 g_key_file_set_boolean(keyfile, "global",
561                                         "OfflineMode", global_offlinemode);
562
563                 __connman_storage_save_global(keyfile);
564         }
565         else {
566                 offlinemode = g_key_file_get_boolean(keyfile, "global",
567                                                 "OfflineMode", &error);
568
569                 if (error || offlinemode != global_offlinemode) {
570                         g_key_file_set_boolean(keyfile, "global",
571                                         "OfflineMode", global_offlinemode);
572                         if (error)
573                                 g_clear_error(&error);
574
575                         __connman_storage_save_global(keyfile);
576                 }
577         }
578
579         g_key_file_free(keyfile);
580 }
581
582 static bool connman_technology_load_offlinemode(void)
583 {
584         GKeyFile *keyfile;
585         GError *error = NULL;
586         bool offlinemode;
587
588         /* If there is a error, we enable offlinemode */
589         keyfile = __connman_storage_load_global();
590         if (!keyfile)
591                 return false;
592
593         offlinemode = g_key_file_get_boolean(keyfile, "global",
594                                                 "OfflineMode", &error);
595         if (error) {
596                 offlinemode = false;
597                 g_clear_error(&error);
598         }
599
600         g_key_file_free(keyfile);
601
602         return offlinemode;
603 }
604
605 #if defined TIZEN_EXT
606 static void append_devices(DBusMessageIter *iter, void *user_data)
607 {
608         GSList *list;
609         dbus_bool_t val;
610         struct connman_technology *technology = user_data;
611
612         for (list = technology->device_list; list; list = list->next) {
613                 struct connman_device *device = list->data;
614
615                 const char *str = connman_device_get_string(device, "Interface");
616                 struct connman_network *network = connman_device_get_default_network(device);
617                 struct connman_service *service = connman_service_lookup_from_network(network);
618
619                 connman_dbus_dict_append_basic(iter, "Ifname",
620                                 DBUS_TYPE_STRING, &str);
621
622                 val = connman_device_get_powered(device);
623                 connman_dbus_dict_append_basic(iter, "Powered",
624                                 DBUS_TYPE_BOOLEAN, &val);
625
626                 if (__connman_service_is_connected_state(service, CONNMAN_IPCONFIG_TYPE_IPV4) ||
627                                 __connman_service_is_connected_state(service, CONNMAN_IPCONFIG_TYPE_IPV6))
628                         val = TRUE;
629                 else
630                         val = FALSE;
631
632                 connman_dbus_dict_append_basic(iter, "Connected",
633                                 DBUS_TYPE_BOOLEAN, &val);
634
635                 str = connman_device_get_string(device, "Address");
636                 connman_dbus_dict_append_basic(iter, "MAC.Address",
637                                 DBUS_TYPE_STRING, &str);
638         }
639 }
640
641 void __connman_technology_append_interfaces(DBusMessageIter *array,
642                                 enum connman_service_type type, const char *ifname)
643 {
644         GSList *list;
645         struct connman_technology *technology = NULL;
646
647         for (list = technology_list; list; list = list->next) {
648                 struct connman_technology *local_tech = list->data;
649
650                 if (local_tech->type != type)
651                         continue;
652
653                 technology = local_tech;
654                 break;
655         }
656
657         if (!technology)
658                 return;
659
660         for (list = technology->device_list; list; list = list->next) {
661                 struct connman_device *device = list->data;
662                 const char *str = connman_device_get_string(device, "Interface");
663
664                 if (g_strcmp0(ifname, str) == 0)
665                         continue;
666
667                 dbus_message_iter_append_basic(array,
668                                 DBUS_TYPE_STRING, &str);
669         }
670 }
671 #endif
672
673 static void append_properties(DBusMessageIter *iter,
674                 struct connman_technology *technology)
675 {
676         DBusMessageIter dict;
677         dbus_bool_t val;
678         const char *str;
679
680         connman_dbus_dict_open(iter, &dict);
681
682         str = get_name(technology->type);
683         if (str)
684                 connman_dbus_dict_append_basic(&dict, "Name",
685                                                 DBUS_TYPE_STRING, &str);
686
687         str = __connman_service_type2string(technology->type);
688         if (str)
689                 connman_dbus_dict_append_basic(&dict, "Type",
690                                                 DBUS_TYPE_STRING, &str);
691
692         __sync_synchronize();
693         val = technology->enabled;
694         connman_dbus_dict_append_basic(&dict, "Powered",
695                                         DBUS_TYPE_BOOLEAN,
696                                         &val);
697
698         val = technology->connected;
699         connman_dbus_dict_append_basic(&dict, "Connected",
700                                         DBUS_TYPE_BOOLEAN,
701                                         &val);
702
703         val = technology->tethering;
704         connman_dbus_dict_append_basic(&dict, "Tethering",
705                                         DBUS_TYPE_BOOLEAN,
706                                         &val);
707
708         if (technology->tethering_ident)
709                 connman_dbus_dict_append_basic(&dict, "TetheringIdentifier",
710                                         DBUS_TYPE_STRING,
711                                         &technology->tethering_ident);
712
713         if (technology->tethering_passphrase)
714                 connman_dbus_dict_append_basic(&dict, "TetheringPassphrase",
715                                         DBUS_TYPE_STRING,
716                                         &technology->tethering_passphrase);
717
718 #if defined TIZEN_EXT
719         connman_dbus_dict_append_basic(&dict, "MacPolicy",
720                                         DBUS_TYPE_UINT32,
721                                         &(technology->mac_policy));
722
723         connman_dbus_dict_append_basic(&dict, "PreassocMacPolicy",
724                                         DBUS_TYPE_UINT32,
725                                         &(technology->preassoc_mac_policy));
726
727         connman_dbus_dict_append_basic(&dict, "RandomMacLifetime",
728                                         DBUS_TYPE_UINT32,
729                                         &(technology->random_mac_lifetime));
730
731         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI)
732                 connman_dbus_dict_append_dict(&dict, "Device.List",
733                                         append_devices, technology);
734         if (technology->regdom)
735                 connman_dbus_dict_append_basic(&dict, "CountryCode",
736                                         DBUS_TYPE_STRING,
737                                         &technology->regdom);
738 #endif
739         connman_dbus_dict_close(iter, &dict);
740 }
741
742 static void technology_added_signal(struct connman_technology *technology)
743 {
744         DBusMessage *signal;
745         DBusMessageIter iter;
746
747         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
748                         CONNMAN_MANAGER_INTERFACE, "TechnologyAdded");
749         if (!signal)
750                 return;
751
752         dbus_message_iter_init_append(signal, &iter);
753         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
754                                                         &technology->path);
755         append_properties(&iter, technology);
756
757         dbus_connection_send(connection, signal, NULL);
758         dbus_message_unref(signal);
759 }
760
761 static void technology_removed_signal(struct connman_technology *technology)
762 {
763         g_dbus_emit_signal(connection, CONNMAN_MANAGER_PATH,
764                         CONNMAN_MANAGER_INTERFACE, "TechnologyRemoved",
765                         DBUS_TYPE_OBJECT_PATH, &technology->path,
766                         DBUS_TYPE_INVALID);
767 }
768
769 static DBusMessage *get_properties(DBusConnection *conn,
770                                         DBusMessage *message, void *user_data)
771 {
772         struct connman_technology *technology = user_data;
773         DBusMessage *reply;
774         DBusMessageIter iter;
775
776         reply = dbus_message_new_method_return(message);
777         if (!reply)
778                 return NULL;
779
780         dbus_message_iter_init_append(reply, &iter);
781         append_properties(&iter, technology);
782
783         return reply;
784 }
785
786 void __connman_technology_list_struct(DBusMessageIter *array)
787 {
788         GSList *list;
789         DBusMessageIter entry;
790
791         for (list = technology_list; list; list = list->next) {
792                 struct connman_technology *technology = list->data;
793
794                 if (!technology->path ||
795                                 (technology->rfkill_driven &&
796                                  technology->hardblocked))
797                         continue;
798
799                 dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT,
800                                 NULL, &entry);
801                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
802                                 &technology->path);
803                 append_properties(&entry, technology);
804                 dbus_message_iter_close_container(array, &entry);
805         }
806 }
807
808 static gboolean technology_pending_reply(gpointer user_data)
809 {
810         struct connman_technology *technology = user_data;
811         DBusMessage *reply;
812
813         /* Power request timed out, send ETIMEDOUT. */
814         if (technology->pending_reply) {
815                 reply = __connman_error_failed(technology->pending_reply, ETIMEDOUT);
816                 if (reply)
817                         g_dbus_send_message(connection, reply);
818
819                 dbus_message_unref(technology->pending_reply);
820                 technology->pending_reply = NULL;
821                 technology->pending_timeout = 0;
822         }
823
824         return FALSE;
825 }
826
827 static int technology_affect_devices(struct connman_technology *technology,
828                                                 bool enable_device)
829 {
830         int err = 0, err_dev;
831         GSList *list;
832
833         if (technology->type == CONNMAN_SERVICE_TYPE_P2P) {
834                 if (enable_device)
835                         __connman_technology_enabled(technology->type);
836                 else
837                         __connman_technology_disabled(technology->type);
838                 return 0;
839         }
840
841 #if defined TIZEN_EXT_WIFI_MESH
842         if (technology->type == CONNMAN_SERVICE_TYPE_MESH)
843                 return 0;
844 #endif
845
846         for (list = technology->device_list; list; list = list->next) {
847                 struct connman_device *device = list->data;
848
849                 if (enable_device)
850                         err_dev = __connman_device_enable(device);
851                 else
852                         err_dev = __connman_device_disable(device);
853
854                 if (err_dev < 0 && err_dev != -EALREADY)
855                         err = err_dev;
856         }
857
858         return err;
859 }
860
861 static void powered_changed(struct connman_technology *technology)
862 {
863         dbus_bool_t enabled;
864
865         if (!technology->dbus_registered)
866                 return;
867
868         if (technology->pending_reply) {
869                 g_dbus_send_reply(connection,
870                                 technology->pending_reply, DBUS_TYPE_INVALID);
871                 dbus_message_unref(technology->pending_reply);
872                 technology->pending_reply = NULL;
873
874                 g_source_remove(technology->pending_timeout);
875                 technology->pending_timeout = 0;
876         }
877
878         __sync_synchronize();
879         enabled = technology->enabled;
880 #if defined TIZEN_EXT
881         DBG("ConnMan, Powered : %s, %s",
882                         enabled ? "TRUE" : "FALSE",technology->path);
883 #endif
884         connman_dbus_property_changed_basic(technology->path,
885                         CONNMAN_TECHNOLOGY_INTERFACE, "Powered",
886                         DBUS_TYPE_BOOLEAN, &enabled);
887 }
888
889 static void enable_tethering(struct connman_technology *technology)
890 {
891         int ret;
892
893         if (!connman_setting_get_bool("PersistentTetheringMode"))
894                 return;
895
896         ret = set_tethering(technology, true);
897         if (ret < 0 && ret != -EALREADY)
898                 DBG("Cannot enable tethering yet for %s (%d/%s)",
899                         get_name(technology->type),
900                         -ret, strerror(-ret));
901 }
902
903 static int technology_enabled(struct connman_technology *technology)
904 {
905         __sync_synchronize();
906         if (technology->enabled)
907                 return -EALREADY;
908
909         technology->enabled = true;
910
911         if (technology->type == CONNMAN_SERVICE_TYPE_WIFI) {
912                 struct connman_technology *p2p;
913
914                 p2p = technology_find(CONNMAN_SERVICE_TYPE_P2P);
915                 if (p2p && !p2p->enabled && p2p->enable_persistent)
916                         technology_enabled(p2p);
917         }
918
919         if (technology->tethering_persistent)
920                 enable_tethering(technology);
921
922         powered_changed(technology);
923
924         return 0;
925 }
926
927 static int technology_enable(struct connman_technology *technology)
928 {
929         int err = 0;
930         int err_dev;
931
932         DBG("technology %p enable", technology);
933
934         __sync_synchronize();
935
936         if (technology->type == CONNMAN_SERVICE_TYPE_P2P) {
937                 struct connman_technology *wifi;
938
939                 wifi = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
940                 if (wifi && wifi->enabled)
941                         return technology_enabled(technology);
942                 return 0;
943         }
944
945         if (technology->enabled)
946                 return -EALREADY;
947
948         if (technology->pending_reply)
949                 return -EBUSY;
950
951         if (connman_setting_get_bool("PersistentTetheringMode") &&
952                                         technology->tethering)
953                 set_tethering(technology, true);
954
955         if (technology->rfkill_driven)
956                 err = __connman_rfkill_block(technology->type, false);
957
958         err_dev = technology_affect_devices(technology, true);
959
960         if (!technology->rfkill_driven)
961                 err = err_dev;
962
963         return err;
964 }
965
966 static int technology_disabled(struct connman_technology *technology)
967 {
968         __sync_synchronize();
969         if (!technology->enabled)
970                 return -EALREADY;
971
972         technology->enabled = false;
973
974         powered_changed(technology);
975
976         return 0;
977 }
978
979 static int technology_disable(struct connman_technology *technology)
980 {
981         int err;
982
983         DBG("technology %p disable", technology);
984
985         __sync_synchronize();
986
987         if (technology->type == CONNMAN_SERVICE_TYPE_P2P) {
988                 technology->enable_persistent = false;
989                 __connman_device_stop_scan(CONNMAN_SERVICE_TYPE_P2P);
990                 __connman_peer_disconnect_all();
991                 return technology_disabled(technology);
992         } else if (technology->type == CONNMAN_SERVICE_TYPE_WIFI) {
993                 struct connman_technology *p2p;
994
995                 p2p = technology_find(CONNMAN_SERVICE_TYPE_P2P);
996                 if (p2p && p2p->enabled) {
997                         p2p->enable_persistent = true;
998                         technology_disabled(p2p);
999                 }
1000         }
1001
1002         if (!technology->enabled)
1003                 return -EALREADY;
1004
1005         if (technology->pending_reply)
1006                 return -EBUSY;
1007
1008         if (technology->tethering)
1009                 set_tethering(technology, false);
1010
1011         err = technology_affect_devices(technology, false);
1012
1013         if (technology->rfkill_driven)
1014                 err = __connman_rfkill_block(technology->type, true);
1015
1016         return err;
1017 }
1018
1019 static DBusMessage *set_powered(struct connman_technology *technology,
1020                                 DBusMessage *msg, bool powered)
1021 {
1022         DBusMessage *reply = NULL;
1023         int err = 0;
1024
1025         if (technology->rfkill_driven && technology->hardblocked) {
1026                 err = -EACCES;
1027                 goto make_reply;
1028         }
1029
1030         if (powered)
1031                 err = technology_enable(technology);
1032         else
1033                 err = technology_disable(technology);
1034
1035         if (err != -EBUSY) {
1036                 technology->enable_persistent = powered;
1037                 technology_save(technology);
1038         }
1039
1040 make_reply:
1041         if (err == -EINPROGRESS) {
1042                 technology->pending_reply = dbus_message_ref(msg);
1043                 technology->pending_timeout = g_timeout_add_seconds(10,
1044                                         technology_pending_reply, technology);
1045         } else if (err == -EALREADY) {
1046                 if (powered)
1047                         reply = __connman_error_already_enabled(msg);
1048                 else
1049                         reply = __connman_error_already_disabled(msg);
1050         } else if (err < 0)
1051                 reply = __connman_error_failed(msg, -err);
1052         else
1053                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1054
1055         return reply;
1056 }
1057
1058 #if defined TIZEN_EXT
1059 int set_connman_bssid(enum bssid_type mode, char *bssid, const char *ifname)
1060 {
1061         static int bssid_len;
1062         static const char *def_ifname = "default";
1063         static GSList *bssid_list = NULL;
1064         GSList *list;
1065         const char *local_ifname = ifname;
1066         bool found = false;
1067         struct connman_bssid_pending *bssid_info;
1068
1069         DBG("mode: %d, ifname: %s", mode, ifname);
1070
1071         if (!ifname)
1072                 local_ifname = def_ifname;
1073
1074         for (list = bssid_list; list; list = list->next) {
1075                 bssid_info = list->data;
1076
1077                 if (g_strcmp0(bssid_info->ifname, local_ifname) == 0) {
1078                         found = true;
1079                         break;
1080                 }
1081         }
1082
1083         if (mode == CHECK_BSSID) {
1084                 if (found)
1085                         return 6;
1086
1087                 return 0;
1088         }
1089
1090         if (mode == GET_BSSID && bssid) {
1091                 if (found) {
1092                         memcpy(bssid, bssid_info->bssid, 6);
1093                         return 6;
1094                 }
1095                 return 0;
1096         }
1097
1098         if (mode == RESET_BSSID) {
1099                 if (found) {
1100                         bssid_list = g_slist_remove(bssid_list, bssid_info);
1101                         g_free(bssid_info->ifname);
1102                         g_free(bssid_info);
1103                 }
1104                 return 0;
1105         }
1106
1107         if (mode != SET_BSSID || !bssid) {
1108                 DBG("Invalid parameter");
1109                 return 0;
1110         }
1111
1112         if (found) {
1113                 bssid_list = g_slist_remove(bssid_list, bssid_info);
1114                 g_free(bssid_info->ifname);
1115                 g_free(bssid_info);
1116         }
1117
1118         bssid_info = g_try_malloc0(sizeof(struct connman_bssid_pending));
1119         if (!bssid_info) {
1120                 DBG("Failed to allocate memory");
1121                 return 0;
1122         }
1123
1124         unsigned char *bssid_data = bssid_info->bssid;
1125
1126         bssid_len = sscanf(bssid, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
1127                 &bssid_data[0], &bssid_data[1], &bssid_data[2],
1128                 &bssid_data[3], &bssid_data[4], &bssid_data[5]);
1129         if (bssid_len != 6) {
1130                 DBG("Incorrect BSSID format. bssid_len = %d", bssid_len);
1131                 g_free(bssid_info);
1132                 return 0;
1133         }
1134
1135         DBG("SET BSSID len: %d, BSSID: %02x:%02x:%02x:%02x:%02x:%02x ifname: %s",
1136                 bssid_len,
1137                 bssid_data[0], bssid_data[1], bssid_data[2],
1138                 bssid_data[3], bssid_data[4], bssid_data[5],
1139                 ifname);
1140
1141         bssid_info->ifname = g_strdup(ifname);
1142         bssid_list = g_slist_prepend(bssid_list, bssid_info);
1143
1144         return bssid_len;
1145 }
1146
1147 void connman_technology_mac_policy_notify(struct connman_technology *technology,
1148                                                         unsigned int policy)
1149 {
1150         DBG("Mac polict set to %u", policy);
1151
1152         technology->mac_policy = policy;
1153         technology_save(technology);
1154 }
1155
1156 void __connman_technology_notify_mac_policy_by_device(struct connman_device *device,
1157                                                 int result, unsigned int policy)
1158 {
1159         struct connman_technology *technology;
1160         enum connman_service_type type;
1161
1162         type = __connman_device_get_service_type(device);
1163         technology = technology_find(type);
1164
1165         if (!technology)
1166                 return;
1167
1168         connman_technology_mac_policy_notify(technology, policy);
1169 }
1170
1171 static DBusMessage *set_mac_policy(struct connman_technology *technology,
1172                                 DBusMessage *msg, unsigned int policy)
1173 {
1174         DBusMessage *reply = NULL;
1175         int err = 0;
1176         unsigned int last_policy = technology->mac_policy;
1177
1178         if (technology->rfkill_driven && technology->hardblocked) {
1179                 err = -EACCES;
1180                 goto make_reply;
1181         }
1182
1183         for (GSList *list = technology->device_list; list; list = list->next) {
1184                 struct connman_device *device = list->data;
1185
1186                 err = connman_device_set_mac_policy(device, policy);
1187                 if (err < 0)
1188                         break;
1189         }
1190
1191 make_reply:
1192         if (err < 0) {
1193                 if (err != -EACCES && err != -EOPNOTSUPP) {
1194                         for (GSList *list = technology->device_list; list; list = list->next) {
1195                                 struct connman_device *device = list->data;
1196
1197                                 connman_device_set_mac_policy(device, last_policy);
1198                         }
1199                 }
1200
1201                 reply = __connman_error_failed(msg, -err);
1202         } else {
1203                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1204         }
1205
1206         return reply;
1207 }
1208
1209 void connman_technology_preassoc_mac_policy_notify(struct connman_technology *technology,
1210                                                         unsigned int policy)
1211 {
1212         DBG("Preassoc mac polict set to %u", policy);
1213
1214         technology->preassoc_mac_policy = policy;
1215         technology_save(technology);
1216 }
1217
1218 void __connman_technology_notify_preassoc_mac_policy_by_device(struct connman_device *device,
1219                                                 int result, unsigned int policy)
1220 {
1221         struct connman_technology *technology;
1222         enum connman_service_type type;
1223
1224         type = __connman_device_get_service_type(device);
1225         technology = technology_find(type);
1226
1227         if (!technology)
1228                 return;
1229
1230         connman_technology_preassoc_mac_policy_notify(technology, policy);
1231 }
1232
1233 static DBusMessage *set_preassoc_mac_policy(struct connman_technology *technology,
1234                                 DBusMessage *msg, unsigned int policy)
1235 {
1236         DBusMessage *reply = NULL;
1237         int err = 0;
1238         unsigned int last_policy = technology->preassoc_mac_policy;
1239
1240         if (technology->rfkill_driven && technology->hardblocked) {
1241                 err = -EACCES;
1242                 goto make_reply;
1243         }
1244
1245         for (GSList *list = technology->device_list; list; list = list->next) {
1246                 struct connman_device *device = list->data;
1247
1248                 err = connman_device_set_preassoc_mac_policy(device, policy);
1249                 if (err < 0)
1250                         break;
1251         }
1252
1253 make_reply:
1254         if (err < 0) {
1255                 if (err != -EACCES && err != -EOPNOTSUPP) {
1256                         for (GSList *list = technology->device_list; list; list = list->next) {
1257                                 struct connman_device *device = list->data;
1258
1259                                 connman_device_set_preassoc_mac_policy(device, last_policy);
1260                         }
1261                 }
1262
1263                 reply = __connman_error_failed(msg, -err);
1264         } else {
1265                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1266         }
1267
1268         return reply;
1269 }
1270
1271 void connman_technology_random_mac_lifetime_notify(struct connman_technology *technology,
1272                                                         unsigned int lifetime)
1273 {
1274         DBG("Random mac lifetime set to %u", lifetime);
1275
1276         technology->random_mac_lifetime = lifetime;
1277         technology_save(technology);
1278 }
1279
1280 void __connman_technology_notify_random_mac_lifetime_by_device(struct connman_device *device,
1281                                                 int result, unsigned int lifetime)
1282 {
1283         struct connman_technology *technology;
1284         enum connman_service_type type;
1285
1286         type = __connman_device_get_service_type(device);
1287         technology = technology_find(type);
1288
1289         if (!technology)
1290                 return;
1291
1292         connman_technology_random_mac_lifetime_notify(technology, lifetime);
1293 }
1294
1295 static DBusMessage *set_random_mac_lifetime(struct connman_technology *technology,
1296                                 DBusMessage *msg, unsigned int lifetime)
1297 {
1298         DBusMessage *reply = NULL;
1299         int err = 0;
1300         unsigned int last_lifetime = technology->random_mac_lifetime;
1301
1302         if (technology->rfkill_driven && technology->hardblocked) {
1303                 err = -EACCES;
1304                 goto make_reply;
1305         }
1306
1307         for (GSList *list = technology->device_list; list; list = list->next) {
1308                 struct connman_device *device = list->data;
1309
1310                 err = connman_device_set_random_mac_lifetime(device, lifetime);
1311         }
1312
1313 make_reply:
1314         if (err < 0) {
1315                 if (err != -EACCES && err != -EOPNOTSUPP) {
1316                         for (GSList *list = technology->device_list; list; list = list->next) {
1317                                 struct connman_device *device = list->data;
1318
1319                                 connman_device_set_random_mac_lifetime(device, last_lifetime);
1320                         }
1321                 }
1322
1323                 reply = __connman_error_failed(msg, -err);
1324         } else {
1325                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1326         }
1327
1328         return reply;
1329 }
1330 #endif
1331
1332 static DBusMessage *set_property(DBusConnection *conn,
1333                                         DBusMessage *msg, void *data)
1334 {
1335         struct connman_technology *technology = data;
1336         DBusMessageIter iter, value;
1337         const char *name;
1338         int type, err;
1339
1340         DBG("conn %p", conn);
1341
1342         if (!dbus_message_iter_init(msg, &iter))
1343                 return __connman_error_invalid_arguments(msg);
1344
1345         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1346                 return __connman_error_invalid_arguments(msg);
1347
1348         dbus_message_iter_get_basic(&iter, &name);
1349         dbus_message_iter_next(&iter);
1350
1351         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1352                 return __connman_error_invalid_arguments(msg);
1353
1354         dbus_message_iter_recurse(&iter, &value);
1355
1356         type = dbus_message_iter_get_arg_type(&value);
1357
1358         DBG("property %s", name);
1359
1360         if (g_str_equal(name, "Tethering")) {
1361                 dbus_bool_t tethering;
1362                 int err;
1363
1364                 if (type != DBUS_TYPE_BOOLEAN)
1365                         return __connman_error_invalid_arguments(msg);
1366
1367                 if (!connman_technology_is_tethering_allowed(technology->type)) {
1368                         DBG("%s tethering not allowed by config file",
1369                                 __connman_service_type2string(technology->type));
1370                         return __connman_error_not_supported(msg);
1371                 }
1372
1373                 dbus_message_iter_get_basic(&value, &tethering);
1374
1375                 if (technology->tethering == tethering) {
1376                         if (!tethering)
1377                                 return __connman_error_already_disabled(msg);
1378                         else
1379                                 return __connman_error_already_enabled(msg);
1380                 }
1381
1382                 err = set_tethering(technology, tethering);
1383                 if (err < 0)
1384                         return __connman_error_failed(msg, -err);
1385
1386                 technology->tethering_persistent = tethering;
1387
1388                 technology_save(technology);
1389
1390         } else if (g_str_equal(name, "TetheringIdentifier")) {
1391                 const char *str;
1392
1393                 dbus_message_iter_get_basic(&value, &str);
1394
1395                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
1396                         return __connman_error_not_supported(msg);
1397
1398                 if (strlen(str) < 1 || strlen(str) > 32)
1399                         return __connman_error_invalid_arguments(msg);
1400
1401                 if (g_strcmp0(technology->tethering_ident, str) != 0) {
1402                         g_free(technology->tethering_ident);
1403                         technology->tethering_ident = g_strdup(str);
1404                         technology_save(technology);
1405
1406                         connman_dbus_property_changed_basic(technology->path,
1407                                                 CONNMAN_TECHNOLOGY_INTERFACE,
1408                                                 "TetheringIdentifier",
1409                                                 DBUS_TYPE_STRING,
1410                                                 &technology->tethering_ident);
1411                 }
1412         } else if (g_str_equal(name, "TetheringPassphrase")) {
1413                 const char *str;
1414
1415                 dbus_message_iter_get_basic(&value, &str);
1416
1417                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
1418                         return __connman_error_not_supported(msg);
1419
1420                 err = __connman_service_check_passphrase(CONNMAN_SERVICE_SECURITY_PSK,
1421                                                         str);
1422                 if (err < 0)
1423                         return __connman_error_passphrase_required(msg);
1424
1425                 if (g_strcmp0(technology->tethering_passphrase, str) != 0) {
1426                         g_free(technology->tethering_passphrase);
1427                         technology->tethering_passphrase = g_strdup(str);
1428                         technology_save(technology);
1429
1430                         connman_dbus_property_changed_basic(technology->path,
1431                                         CONNMAN_TECHNOLOGY_INTERFACE,
1432                                         "TetheringPassphrase",
1433                                         DBUS_TYPE_STRING,
1434                                         &technology->tethering_passphrase);
1435                 }
1436         } else if (g_str_equal(name, "Powered")) {
1437                 dbus_bool_t enable;
1438
1439                 if (type != DBUS_TYPE_BOOLEAN)
1440                         return __connman_error_invalid_arguments(msg);
1441
1442                 dbus_message_iter_get_basic(&value, &enable);
1443
1444                 return set_powered(technology, msg, enable);
1445 #if defined TIZEN_EXT
1446         } else if (g_str_equal(name, "SetBSSID")) {
1447                 char *key;
1448
1449                 if (type != DBUS_TYPE_STRING)
1450                         return __connman_error_invalid_arguments(msg);
1451
1452                 dbus_message_iter_get_basic(&value, &key);
1453                 DBG("BSSID %s", key);
1454                 set_connman_bssid(SET_BSSID, key, NULL);
1455         } else if (g_str_equal(name, "MacPolicy")) {
1456                 dbus_uint32_t mac_policy;
1457
1458                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
1459                         return __connman_error_not_supported(msg);
1460
1461                 if (type != DBUS_TYPE_UINT32)
1462                         return __connman_error_invalid_arguments(msg);
1463
1464                 dbus_message_iter_get_basic(&value, &mac_policy);
1465
1466                 if (mac_policy <= 2)
1467                         return set_mac_policy(technology, msg, mac_policy);
1468                 else
1469                         return __connman_error_invalid_arguments(msg);
1470
1471         } else if (g_str_equal(name, "PreassocMacPolicy")) {
1472                 dbus_uint32_t preassoc_mac_policy;
1473
1474                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
1475                         return __connman_error_not_supported(msg);
1476
1477                 if (type != DBUS_TYPE_UINT32)
1478                         return __connman_error_invalid_arguments(msg);
1479
1480                 dbus_message_iter_get_basic(&value, &preassoc_mac_policy);
1481
1482                 if (preassoc_mac_policy <= 2)
1483                         return set_preassoc_mac_policy(technology, msg, preassoc_mac_policy);
1484                 else
1485                         return __connman_error_invalid_arguments(msg);
1486
1487         } else if (g_str_equal(name, "RandomMacLifetime")) {
1488                 dbus_uint32_t random_mac_lifetime;
1489
1490                 if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
1491                         return __connman_error_not_supported(msg);
1492
1493                 if (type != DBUS_TYPE_UINT32)
1494                         return __connman_error_invalid_arguments(msg);
1495
1496                 dbus_message_iter_get_basic(&value, &random_mac_lifetime);
1497
1498                 if (random_mac_lifetime > 0)
1499                         return set_random_mac_lifetime(technology, msg, random_mac_lifetime);
1500                 else
1501                         return __connman_error_invalid_arguments(msg);
1502
1503         } else if (g_str_equal(name, "CountryCode")) {
1504                 const char *str;
1505
1506                 dbus_message_iter_get_basic(&value, &str);
1507                 DBG("country code %s", str);
1508                 connman_technology_set_regdom(str);
1509 #endif
1510         } else
1511                 return __connman_error_invalid_property(msg);
1512
1513         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1514 }
1515
1516 static void reply_scan_pending(struct connman_technology *technology, int err)
1517 {
1518         DBusMessage *reply;
1519
1520         DBG("technology %p err %d", technology, err);
1521
1522         while (technology->scan_pending) {
1523 #if defined TIZEN_EXT
1524                 struct connman_scan_pending *pending_data = technology->scan_pending->data;
1525                 DBusMessage *msg = pending_data->msg;
1526 #else
1527                 DBusMessage *msg = technology->scan_pending->data;
1528 #endif
1529                 DBG("reply to %s", dbus_message_get_sender(msg));
1530
1531                 if (err == 0)
1532                         reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1533                 else
1534                         reply = __connman_error_failed(msg, -err);
1535                 g_dbus_send_message(connection, reply);
1536                 dbus_message_unref(msg);
1537
1538                 technology->scan_pending =
1539                         g_slist_delete_link(technology->scan_pending,
1540                                         technology->scan_pending);
1541 #if defined TIZEN_EXT
1542                 g_free(pending_data->ifname);
1543                 g_free(pending_data);
1544 #endif
1545         }
1546 }
1547
1548 #if defined TIZEN_EXT
1549 dbus_bool_t __connman_technology_notify_scan_changed(const char *key, void *val)
1550 {
1551         DBG("key %s", key);
1552         DBusMessage *signal;
1553         DBusMessageIter iter;
1554         dbus_bool_t result = FALSE;
1555
1556         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1557                         CONNMAN_MANAGER_INTERFACE, "ScanChanged");
1558         if (!signal)
1559                 return result;
1560
1561         dbus_message_iter_init_append(signal, &iter);
1562         if (key)
1563                 connman_dbus_property_append_basic(&iter, key, DBUS_TYPE_BOOLEAN, val);
1564         else
1565                 connman_dbus_property_append_basic(&iter, "", DBUS_TYPE_BOOLEAN, val);
1566
1567         result = dbus_connection_send(connection, signal, NULL);
1568         dbus_message_unref(signal);
1569
1570         DBG("Successfuly sent signal");
1571
1572         return result;
1573 }
1574
1575 void __connman_technology_notify_scan_done(const char *ifname, int val)
1576 {
1577         DBG("");
1578         DBusMessage *signal;
1579         DBusMessageIter iter;
1580
1581         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1582                         CONNMAN_MANAGER_INTERFACE, "ScanDone");
1583         if (!signal)
1584                 return;
1585
1586         dbus_message_iter_init_append(signal, &iter);
1587         if (ifname)
1588                 connman_dbus_property_append_basic(&iter, ifname,
1589                                 DBUS_TYPE_INT32, &val);
1590         else
1591                 connman_dbus_property_append_basic(&iter, "",
1592                                 DBUS_TYPE_INT32, &val);
1593
1594         dbus_connection_send(connection, signal, NULL);
1595         dbus_message_unref(signal);
1596
1597         DBG("Successfuly sent ScanDone signal");
1598 }
1599
1600 static void reply_scan_pending_device(
1601                 struct connman_technology *technology, const char *ifname, int count)
1602 {
1603         DBusMessage *reply;
1604         GSList *list;
1605         dbus_bool_t status = 0;
1606         connman_scan_type_e scan_type = CONNMAN_SCAN_TYPE_UNKNOWN;
1607
1608         DBG("technology %p ifname %s count %d", technology, ifname, count);
1609
1610         list = technology->scan_pending;
1611
1612         while (list) {
1613                 struct connman_scan_pending *pending_data = list->data;
1614                 DBusMessage *msg = pending_data->msg;
1615                 list = list->next;
1616
1617                 if (scan_type == CONNMAN_SCAN_TYPE_UNKNOWN)
1618                         scan_type = pending_data->scan_type;
1619
1620                 if (count != 0 && g_strcmp0(pending_data->ifname, ifname) != 0)
1621                         continue;
1622
1623                 scan_type = pending_data->scan_type;
1624
1625                 DBG("reply to %s", dbus_message_get_sender(msg));
1626                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1627
1628                 g_dbus_send_message(connection, reply);
1629                 dbus_message_unref(msg);
1630
1631                 technology->scan_pending =
1632                                 g_slist_remove(technology->scan_pending, pending_data);
1633
1634                 g_free(pending_data->ifname);
1635                 g_free(pending_data);
1636         }
1637
1638         if (scan_type == CONNMAN_SCAN_TYPE_UNKNOWN)
1639                 scan_type = CONNMAN_SCAN_TYPE_FULL_CHANNEL;
1640
1641         __connman_technology_notify_scan_changed(ifname, &status);
1642         __connman_technology_notify_scan_done(ifname, scan_type);
1643 }
1644
1645 static void __connman_technology_notify_device_detected(
1646                 struct connman_technology *technology, const char *ifname, bool val)
1647 {
1648         DBG("");
1649         DBusMessage *signal;
1650         DBusMessageIter iter;
1651         dbus_bool_t detected = val;
1652
1653         if (!ifname)
1654                 return;
1655
1656         signal = dbus_message_new_signal(technology->path,
1657                         CONNMAN_TECHNOLOGY_INTERFACE, "DeviceDetected");
1658         if (!signal)
1659                 return;
1660
1661         dbus_message_iter_init_append(signal, &iter);
1662         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &ifname);
1663         dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &detected);
1664
1665         dbus_connection_send(connection, signal, NULL);
1666         dbus_message_unref(signal);
1667
1668         DBG("Successfuly sent DeviceDetected signal");
1669 }
1670
1671 void __connman_technology_notify_roaming_state(const char *ifname,
1672                 const char *state, const char *cur_bssid, const char *dst_bssid)
1673 {
1674         DBG("");
1675         DBusMessage *signal;
1676         DBusMessageIter array, dict;
1677
1678         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1679                         CONNMAN_MANAGER_INTERFACE, "RoamingStateChanged");
1680         if (!signal)
1681                 return;
1682
1683         dbus_message_iter_init_append(signal, &array);
1684
1685         connman_dbus_dict_open(&array, &dict);
1686
1687         if (ifname)
1688                 connman_dbus_dict_append_basic(&dict, "Interface",
1689                                         DBUS_TYPE_STRING, &ifname);
1690         if (state)
1691                 connman_dbus_dict_append_basic(&dict, "State",
1692                                         DBUS_TYPE_STRING, &state);
1693         if (cur_bssid)
1694                 connman_dbus_dict_append_basic(&dict, "ConnectedBSSID",
1695                                         DBUS_TYPE_STRING, &cur_bssid);
1696         if (dst_bssid)
1697                 connman_dbus_dict_append_basic(&dict, "TargetBSSID",
1698                                         DBUS_TYPE_STRING, &dst_bssid);
1699
1700         connman_dbus_dict_close(&array, &dict);
1701
1702         dbus_connection_send(connection, signal, NULL);
1703         dbus_message_unref(signal);
1704
1705         DBG("Successfully sent Roaming State Changed signal");
1706 }
1707 #endif
1708
1709 void __connman_technology_scan_started(struct connman_device *device)
1710 {
1711         DBG("device %p", device);
1712 #if defined TIZEN_EXT
1713         dbus_bool_t status = 1;
1714         const char *ifname = connman_device_get_string(device, "Interface");
1715
1716         __connman_technology_notify_scan_changed(ifname, &status);
1717 #endif
1718 }
1719
1720 void __connman_technology_scan_stopped(struct connman_device *device,
1721                                         enum connman_service_type type)
1722 {
1723         int count = 0;
1724         struct connman_technology *technology;
1725         GSList *list;
1726
1727         technology = technology_find(type);
1728
1729         DBG("technology %p device %p", technology, device);
1730
1731         if (!technology)
1732                 return;
1733
1734         for (list = technology->device_list; list; list = list->next) {
1735                 struct connman_device *other_device = list->data;
1736
1737                 if (device == other_device)
1738                         continue;
1739
1740                 if (connman_device_get_scanning(other_device, type))
1741                         count += 1;
1742         }
1743
1744 #if defined TIZEN_EXT
1745         const char *ifname = connman_device_get_string(device, "Interface");
1746         reply_scan_pending_device(technology, ifname, count);
1747
1748         return;
1749 #else
1750         if (count == 0)
1751                 reply_scan_pending(technology, 0);
1752 #endif
1753 }
1754
1755 void __connman_technology_notify_regdom_by_device(struct connman_device *device,
1756                                                 int result, const char *alpha2)
1757 {
1758         bool regdom_set = false;
1759         struct connman_technology *technology;
1760         enum connman_service_type type;
1761         GSList *tech_drivers;
1762
1763         type = __connman_device_get_service_type(device);
1764         technology = technology_find(type);
1765
1766         if (!technology)
1767                 return;
1768
1769         if (result < 0) {
1770
1771                 for (tech_drivers = technology->driver_list;
1772                      tech_drivers;
1773                      tech_drivers = g_slist_next(tech_drivers)) {
1774                         struct connman_technology_driver *driver =
1775                                 tech_drivers->data;
1776
1777                         if (driver->set_regdom) {
1778                                 driver->set_regdom(technology, alpha2);
1779                                 regdom_set = true;
1780                         }
1781
1782                 }
1783
1784                 if (!regdom_set)
1785                         alpha2 = NULL;
1786         }
1787
1788         connman_technology_regdom_notify(technology, alpha2);
1789 }
1790
1791 static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data)
1792 {
1793         struct connman_technology *technology = data;
1794         int err;
1795
1796         DBG("technology %p request from %s", technology,
1797                         dbus_message_get_sender(msg));
1798
1799         if (technology->type == CONNMAN_SERVICE_TYPE_P2P &&
1800                                 !technology->enabled)
1801                 return __connman_error_permission_denied(msg);
1802
1803 #if !defined TIZEN_EXT
1804         dbus_message_ref(msg);
1805         technology->scan_pending =
1806                 g_slist_prepend(technology->scan_pending, msg);
1807 #endif
1808
1809         err = __connman_device_request_scan_full(technology->type);
1810         if (err < 0)
1811 #if defined TIZEN_EXT
1812                 return __connman_error_failed(msg, -err);
1813 #else
1814                 reply_scan_pending(technology, err);
1815 #endif
1816
1817 #if defined TIZEN_EXT
1818         struct connman_scan_pending *pending_data =
1819                         g_try_malloc0(sizeof(struct connman_scan_pending));
1820         if (!pending_data)
1821                 return __connman_error_failed(msg, ENOMEM);
1822
1823         pending_data->scan_type = CONNMAN_SCAN_TYPE_FULL_CHANNEL;
1824         DBG("scan_type %d", pending_data->scan_type);
1825
1826         pending_data->msg = dbus_message_ref(msg);
1827
1828         technology->scan_pending =
1829                 g_slist_prepend(technology->scan_pending, pending_data);
1830 #endif
1831         return NULL;
1832 }
1833
1834 #if defined TIZEN_EXT
1835 static DBusMessage *scan_device(DBusConnection *conn, DBusMessage *msg, void *data)
1836 {
1837         struct connman_technology *technology = data;
1838         DBusMessageIter iter;
1839         const char *ifname;
1840         int err;
1841
1842         DBG("technology %p request from %s", technology,
1843                         dbus_message_get_sender(msg));
1844
1845         if (!dbus_message_iter_init(msg, &iter))
1846                 return __connman_error_invalid_arguments(msg);
1847
1848         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1849                 return __connman_error_invalid_arguments(msg);
1850
1851         dbus_message_iter_get_basic(&iter, &ifname);
1852         DBG("Interface name %s", ifname);
1853
1854         if (!ifname || strlen(ifname) == 0)
1855                 return __connman_error_invalid_arguments(msg);
1856
1857         err = connman_device_request_device_scan(technology->type, ifname, true);
1858         if (err < 0)
1859                 return __connman_error_failed(msg, -err);
1860
1861         struct connman_scan_pending *pending_data =
1862                         g_try_malloc0(sizeof(struct connman_scan_pending));
1863         if (!pending_data)
1864                 return __connman_error_failed(msg, ENOMEM);
1865
1866         pending_data->ifname =  g_strdup(ifname);
1867         if (pending_data->ifname == NULL) {
1868                 g_free(pending_data);
1869                 return __connman_error_failed(msg, ENOMEM);
1870         }
1871
1872         pending_data->scan_type = CONNMAN_SCAN_TYPE_FULL_CHANNEL;
1873         DBG("scan_type %d", pending_data->scan_type);
1874
1875         pending_data->msg = dbus_message_ref(msg);
1876
1877         technology->scan_pending =
1878                 g_slist_prepend(technology->scan_pending, pending_data);
1879
1880         return NULL;
1881 }
1882
1883 static DBusMessage *specific_scan(DBusConnection *conn, DBusMessage *msg, void *data)
1884 {
1885         struct connman_technology *technology = data;
1886         GSList *specific_scan_list = NULL;
1887         int scan_type = 0;
1888         const char *name = NULL;
1889         const char *freq = NULL;
1890         const char *ifname = NULL;
1891         DBusMessageIter iter, dict;
1892         int err;
1893
1894         DBG("technology %p request from %s", technology,
1895                         dbus_message_get_sender(msg));
1896
1897         if (!dbus_message_iter_init(msg, &iter))
1898                 return __connman_error_invalid_arguments(msg);
1899
1900         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1901                 return __connman_error_invalid_arguments(msg);
1902
1903         dbus_message_iter_recurse(&iter, &dict);
1904         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1905                 DBusMessageIter entry, value2;
1906                 const char *key;
1907                 int type;
1908
1909                 dbus_message_iter_recurse(&dict, &entry);
1910                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) {
1911                         g_slist_free_full(specific_scan_list, g_free);
1912                         return __connman_error_invalid_arguments(msg);
1913                 }
1914
1915                 dbus_message_iter_get_basic(&entry, &key);
1916                 dbus_message_iter_next(&entry);
1917
1918                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) {
1919                         g_slist_free_full(specific_scan_list, g_free);
1920                         return __connman_error_invalid_arguments(msg);
1921                 }
1922
1923                 dbus_message_iter_recurse(&entry, &value2);
1924                 type = dbus_message_iter_get_arg_type(&value2);
1925                 if (g_str_equal(key, "Ifname") && type == DBUS_TYPE_STRING) {
1926
1927                         dbus_message_iter_get_basic(&value2, &ifname);
1928                         DBG("ifname %s", ifname);
1929                 } else if (g_str_equal(key, "SSID")) {
1930                         if (type != DBUS_TYPE_STRING) {
1931                                 g_slist_free_full(specific_scan_list, g_free);
1932                                 return __connman_error_invalid_arguments(msg);
1933                         }
1934
1935                         scan_type = CONNMAN_MULTI_SCAN_SSID; /* SSID based scan */
1936                         dbus_message_iter_get_basic(&value2, &name);
1937                         DBG("name %s", name);
1938                         specific_scan_list = g_slist_append(specific_scan_list, g_strdup(name));
1939                 } else if (g_str_equal(key, "Frequency")) {
1940                         if (type != DBUS_TYPE_STRING) {
1941                                 g_slist_free_full(specific_scan_list, g_free);
1942                                 return __connman_error_invalid_arguments(msg);
1943                         }
1944
1945                         scan_type = CONNMAN_MULTI_SCAN_FREQ; /* Frequency based scan */
1946                         dbus_message_iter_get_basic(&value2, &freq);
1947                         DBG("freq %s", freq);
1948                         specific_scan_list = g_slist_append(specific_scan_list, GINT_TO_POINTER(atoi(freq)));
1949                 } else if (g_str_equal(key, "SSID_Mixed")) {
1950                         if (type != DBUS_TYPE_STRING) {
1951                                 g_slist_free_full(specific_scan_list, g_free);
1952                                 return __connman_error_invalid_arguments(msg);
1953                         }
1954
1955                         scan_type = CONNMAN_MULTI_SCAN_SSID_FREQ; /* SSID & Frequency mixed scan */
1956                         dbus_message_iter_get_basic(&value2, &name);
1957
1958                         connman_multi_scan_ap_s *ap =
1959                                         (connman_multi_scan_ap_s*)g_try_malloc0(sizeof(connman_multi_scan_ap_s));
1960                         if (ap) {
1961                                 g_strlcpy(ap->str, name, strlen(name) + 1);
1962                                 ap->flag = true;
1963                                 specific_scan_list = g_slist_append(specific_scan_list, ap);
1964                         } else
1965                                 DBG("Failed to allocate memory");
1966
1967                 } else if (g_str_equal(key, "Frequency_Mixed")) {
1968                         if (type != DBUS_TYPE_STRING) {
1969                                 g_slist_free_full(specific_scan_list, g_free);
1970                                 return __connman_error_invalid_arguments(msg);
1971                         }
1972
1973                         scan_type = CONNMAN_MULTI_SCAN_SSID_FREQ; /* SSID & Frequency mixed scan */
1974                         dbus_message_iter_get_basic(&value2, &freq);
1975
1976                         connman_multi_scan_ap_s *ap =
1977                                         (connman_multi_scan_ap_s*)g_try_malloc0(sizeof(connman_multi_scan_ap_s));
1978                         if (ap) {
1979                                 g_strlcpy(ap->str, freq, strlen(freq) + 1);
1980                                 ap->flag = false;
1981                                 specific_scan_list = g_slist_append(specific_scan_list, ap);
1982                         } else
1983                                 DBG("Failed to allocate memory");
1984                 }
1985                 dbus_message_iter_next(&dict);
1986         }
1987
1988         err = __connman_device_request_specific_scan(technology->type, ifname, scan_type, specific_scan_list);
1989         if (err < 0)
1990                 return __connman_error_failed(msg, -err);
1991
1992         guint list_size = g_slist_length(specific_scan_list);
1993
1994         if (scan_type == CONNMAN_MULTI_SCAN_SSID ||
1995                         scan_type == CONNMAN_MULTI_SCAN_SSID_FREQ)
1996                 g_slist_free_full(specific_scan_list, g_free);
1997
1998         struct connman_scan_pending *pending_data =
1999                         g_try_malloc0(sizeof(struct connman_scan_pending));
2000         if (!pending_data)
2001                 return __connman_error_failed(msg, ENOMEM);
2002
2003         if (ifname) {
2004                 pending_data->ifname =  g_strdup(ifname);
2005                 if (pending_data->ifname == NULL) {
2006                         g_free(pending_data);
2007                         return __connman_error_failed(msg, ENOMEM);
2008                 }
2009         }
2010
2011         if (list_size == 1)
2012                 pending_data->scan_type = CONNMAN_SCAN_TYPE_SPECIFIC_AP;
2013         else
2014                 pending_data->scan_type = CONNMAN_SCAN_TYPE_MULTI_AP;
2015         DBG("list_size %u scan_type %d", list_size, pending_data->scan_type);
2016
2017         pending_data->msg = dbus_message_ref(msg);
2018
2019         technology->scan_pending =
2020                 g_slist_prepend(technology->scan_pending, pending_data);
2021
2022         return NULL;
2023 }
2024
2025 static DBusMessage *get_5ghz_supported(DBusConnection *conn, DBusMessage *msg, void *data)
2026 {
2027         DBusMessage *reply;
2028         DBusMessageIter iter, dict;
2029         GSList *list;
2030         struct connman_technology *technology = data;
2031         dbus_bool_t supported = false;
2032         const char *ifname = NULL;
2033
2034         DBG("technology %p", technology);
2035
2036         reply = dbus_message_new_method_return(msg);
2037         if (!reply)
2038                 return NULL;
2039
2040         dbus_message_iter_init_append(reply, &iter);
2041         connman_dbus_dict_open(&iter, &dict);
2042
2043         for (list = technology->device_list; list; list = list->next) {
2044                 struct connman_device *device = list->data;
2045
2046                 supported = connman_device_get_wifi_5ghz_supported(device);
2047                 ifname = connman_device_get_string(device, "Interface");
2048
2049                 DBG("ifname %s supported : %d", ifname, supported);
2050                 connman_dbus_dict_append_basic(&dict, ifname,
2051                                                 DBUS_TYPE_BOOLEAN,
2052                                                 &supported);
2053         }
2054
2055         connman_dbus_dict_close(&iter, &dict);
2056
2057         return reply;
2058 }
2059
2060 static DBusMessage *get_scan_state(DBusConnection *conn, DBusMessage *msg, void *data)
2061 {
2062         DBusMessage *reply;
2063         DBusMessageIter iter, dict;
2064         GSList *list;
2065         struct connman_technology *technology = data;
2066         dbus_bool_t scanning = false;
2067         const char *ifname = NULL;
2068
2069         DBG("technology %p", technology);
2070
2071         reply = dbus_message_new_method_return(msg);
2072         if (!reply)
2073                 return NULL;
2074
2075         dbus_message_iter_init_append(reply, &iter);
2076         connman_dbus_dict_open(&iter, &dict);
2077
2078         for (list = technology->device_list; list; list = list->next) {
2079                 struct connman_device *device = list->data;
2080
2081                 scanning = connman_device_get_scanning(device, technology->type);
2082                 ifname = connman_device_get_string(device, "Interface");
2083
2084                 DBG("ifname %s scanning : %d", ifname, scanning);
2085                 connman_dbus_dict_append_basic(&dict, ifname,
2086                                                 DBUS_TYPE_BOOLEAN,
2087                                                 &scanning);
2088         }
2089
2090         connman_dbus_dict_close(&iter, &dict);
2091
2092         return reply;
2093 }
2094
2095 static DBusMessage *get_max_scan_ssid(DBusConnection *conn, DBusMessage *msg, void *data)
2096 {
2097         DBusMessage *reply;
2098         DBusMessageIter iter, dict;
2099         GSList *list;
2100         struct connman_technology *technology = data;
2101         dbus_int32_t max_scan_ssids = 0;
2102         const char *ifname = NULL;
2103
2104         DBG("technology %p", technology);
2105
2106         reply = dbus_message_new_method_return(msg);
2107         if (!reply)
2108                 return NULL;
2109
2110         dbus_message_iter_init_append(reply, &iter);
2111         connman_dbus_dict_open(&iter, &dict);
2112
2113         for (list = technology->device_list; list; list = list->next) {
2114                 struct connman_device *device = list->data;
2115
2116                 max_scan_ssids = connman_device_get_max_scan_ssids(device);
2117                 ifname = connman_device_get_string(device, "Interface");
2118
2119                 DBG("ifname %s max_scan_ssids : %d", ifname, max_scan_ssids);
2120                 connman_dbus_dict_append_basic(&dict, ifname,
2121                                 DBUS_TYPE_INT32,
2122                                 &max_scan_ssids);
2123         }
2124
2125         connman_dbus_dict_close(&iter, &dict);
2126
2127         return reply;
2128 }
2129
2130 static int technology_enable_device(struct connman_technology *technology,
2131                                 bool enable_device, const char *ifname, struct connman_device **device_out)
2132 {
2133         int err = 0;
2134         GSList *list;
2135
2136         for (list = technology->device_list; list; list = list->next) {
2137                 struct connman_device *device = list->data;
2138                 const char *str = connman_device_get_string(device, "Interface");
2139
2140                 if (g_strcmp0(str, ifname) != 0)
2141                         continue;
2142
2143                 if (enable_device)
2144                         err = __connman_device_enable(device);
2145                 else
2146                         err = __connman_device_disable(device);
2147
2148                 *device_out = device;
2149                 return err;
2150         }
2151
2152         return -ENXIO;
2153 }
2154
2155 static DBusMessage *technology_set_device_powered(struct connman_technology *technology,
2156                                 DBusMessage *msg, bool powered, const char *ifname)
2157 {
2158         DBusMessage *reply = NULL;
2159         struct connman_device *device = NULL;
2160         int err = 0;
2161
2162         err = technology_enable_device(technology, powered, ifname, &device);
2163
2164         if (err == -EINPROGRESS) {
2165                 if (device)
2166                         connman_device_set_pending_reply(device, msg);
2167                 return reply;
2168         } else if (err == -EALREADY) {
2169                 if (powered)
2170                         reply = __connman_error_already_enabled(msg);
2171                 else
2172                         reply = __connman_error_already_disabled(msg);
2173         } else if (err < 0)
2174                 reply = __connman_error_failed(msg, -err);
2175         else
2176                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2177
2178         return reply;
2179 }
2180
2181 static DBusMessage *set_device_power(DBusConnection *conn,
2182                                         DBusMessage *msg, void *data)
2183 {
2184         struct connman_technology *technology = data;
2185         DBusMessageIter iter;
2186         const char *name;
2187         int len;
2188         dbus_bool_t enable;
2189
2190         DBG("conn %p", conn);
2191
2192         if (!dbus_message_iter_init(msg, &iter))
2193                 return __connman_error_invalid_arguments(msg);
2194
2195         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
2196                 return __connman_error_invalid_arguments(msg);
2197
2198         dbus_message_iter_get_basic(&iter, &name);
2199         dbus_message_iter_next(&iter);
2200
2201         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
2202                 return __connman_error_invalid_arguments(msg);
2203
2204         DBG("interface name %s", name);
2205
2206         len = strlen(name);
2207
2208         if (len + 1 > IFNAMSIZ)
2209                 return __connman_error_invalid_arguments(msg);
2210
2211         dbus_message_iter_get_basic(&iter, &enable);
2212         DBG("powered %s", enable ? "TRUE" : "FALSE");
2213
2214         return technology_set_device_powered(technology, msg, enable, name);
2215 }
2216
2217 static DBusMessage *set_bssid(DBusConnection *conn,
2218                                         DBusMessage *msg, void *data)
2219 {
2220         DBusMessageIter iter;
2221         char *name, *bssid;
2222         int len;
2223
2224         DBG("conn %p", conn);
2225
2226         if (!dbus_message_iter_init(msg, &iter))
2227                 return __connman_error_invalid_arguments(msg);
2228
2229         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
2230                 return __connman_error_invalid_arguments(msg);
2231
2232         dbus_message_iter_get_basic(&iter, &name);
2233         dbus_message_iter_next(&iter);
2234
2235         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
2236                 return __connman_error_invalid_arguments(msg);
2237
2238         dbus_message_iter_get_basic(&iter, &bssid);
2239
2240         DBG("interface name %s bssid %s", name, bssid);
2241
2242         len = strlen(name);
2243
2244         if (len + 1 > IFNAMSIZ)
2245                 return __connman_error_invalid_arguments(msg);
2246
2247         set_connman_bssid(SET_BSSID, bssid, name);
2248
2249         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2250 }
2251 static struct connman_technology *technology_get(enum connman_service_type type);
2252
2253 void technology_save_device(struct connman_device *device)
2254 {
2255         struct connman_technology *technology;
2256         enum connman_service_type type;
2257
2258         type = __connman_device_get_service_type(device);
2259
2260         if (type != CONNMAN_SERVICE_TYPE_WIFI)
2261                 return;
2262
2263         technology = technology_get(type);
2264         if (!technology)
2265                 return;
2266
2267         if (!g_slist_find(technology->device_list, device))
2268                 return;
2269
2270         GKeyFile *keyfile;
2271         gchar *identifier;
2272         const char *name = get_name(technology->type);
2273
2274         DBG("technology %p type %d name %s", technology, technology->type,
2275                                                                         name);
2276         if (!name)
2277                 return;
2278
2279         keyfile = __connman_storage_load_global();
2280         if (!keyfile)
2281                 keyfile = g_key_file_new();
2282
2283         identifier = g_strdup_printf("%s", name);
2284         if (!identifier)
2285                 goto done;
2286
2287         GSList *list = NULL;
2288         gchar **ifname_list = NULL;
2289         guint dev_count = g_slist_length(technology->device_list);
2290
2291         if (dev_count >= 1) {
2292                 GString *ifname_str = g_string_new(NULL);
2293
2294                 if (ifname_str) {
2295                         for (list = technology->device_list; list; list = list->next) {
2296                                 struct connman_device *device = list->data;
2297
2298                                 if (connman_device_get_powered(device)) {
2299                                         const char *ifname = connman_device_get_string(device, "Interface");
2300
2301                                         if (ifname_str->len > 0)
2302                                                 g_string_append_printf(ifname_str, " %s", ifname);
2303                                         else
2304                                                 g_string_append(ifname_str, ifname);
2305                                 }
2306                         }
2307
2308                         if (ifname_str->len > 0) {
2309                                 ifname_list = g_strsplit_set(ifname_str->str, " ", 0);
2310                                 dev_count = g_strv_length(ifname_list);
2311                                 g_key_file_set_string_list(keyfile, identifier, "Enable.Devices",
2312                                                                 (const gchar **) ifname_list, dev_count);
2313
2314                                 technology->enable_persistent = true;
2315                         } else {
2316                                 g_key_file_remove_key(keyfile, identifier, "Enable.Devices", NULL);
2317                                 technology->enable_persistent = false;
2318                         }
2319
2320                         g_strfreev(ifname_list);
2321                         g_string_free(ifname_str, TRUE);
2322                 }
2323         }
2324
2325         g_key_file_set_boolean(keyfile, identifier, "Enable",
2326                                 technology->enable_persistent);
2327
2328         g_key_file_set_boolean(keyfile, identifier, "Tethering",
2329                                 technology->tethering_persistent);
2330
2331         if (technology->tethering_ident)
2332                 g_key_file_set_string(keyfile, identifier,
2333                                         "Tethering.Identifier",
2334                                         technology->tethering_ident);
2335
2336         if (technology->tethering_passphrase)
2337                 g_key_file_set_string(keyfile, identifier,
2338                                         "Tethering.Passphrase",
2339                                         technology->tethering_passphrase);
2340
2341 done:
2342         g_free(identifier);
2343
2344         __connman_storage_save_global(keyfile);
2345
2346         g_key_file_free(keyfile);
2347 }
2348 #endif
2349
2350 #if defined TIZEN_EXT_WIFI_MESH
2351 bool __connman_technology_get_connected(enum connman_service_type type)
2352 {
2353         struct connman_technology *technology;
2354
2355         technology = technology_find(type);
2356
2357         if (!technology)
2358                 return false;
2359
2360         return technology->connected;
2361 }
2362
2363 void __connman_technology_mesh_interface_create_finished(
2364                                                         enum connman_service_type type, bool success,
2365                                                         const char *error)
2366 {
2367         DBusMessage *reply;
2368         struct connman_technology *technology;
2369         DBusMessage *msg;
2370         technology = technology_find(type);
2371
2372         DBG("technology %p success %d", technology, success);
2373
2374         if (!technology)
2375                 return;
2376
2377         msg = technology->mesh_dbus_msg;
2378         if (!msg) {
2379                 DBG("No pending dbus message");
2380                 return;
2381         }
2382
2383         if (success) {
2384                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2385                 __connman_device_request_scan(technology->type);
2386         } else
2387                 reply = g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
2388                                 ".MeshInterfaceAddFailed", "%s", error);
2389         g_dbus_send_message(connection, reply);
2390         dbus_message_unref(msg);
2391         technology->mesh_dbus_msg = NULL;
2392 }
2393
2394 void __connman_technology_mesh_interface_remove_finished(
2395                                                         enum connman_service_type type, bool success)
2396 {
2397         DBusMessage *reply;
2398         struct connman_technology *technology;
2399         DBusMessage *msg;
2400         technology = technology_find(type);
2401
2402         DBG("technology %p success %d", technology, success);
2403
2404         if (!technology || !technology->mesh_dbus_msg)
2405                 return;
2406
2407         msg = technology->mesh_dbus_msg;
2408         if (!msg) {
2409                 DBG("No pending dbus message");
2410                 return;
2411         }
2412
2413         if (success)
2414                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2415         else
2416                 reply = __connman_error_failed(msg, EINVAL);
2417         g_dbus_send_message(connection, reply);
2418         dbus_message_unref(msg);
2419         technology->mesh_dbus_msg = NULL;
2420 }
2421
2422 void __connman_technology_notify_abort_scan(enum connman_service_type type,
2423                                                         int result)
2424 {
2425         DBusMessage *reply;
2426         struct connman_technology *technology;
2427         DBusMessage *msg;
2428         technology = technology_find(type);
2429
2430         DBG("technology %p result %d", technology, result);
2431
2432         if (!technology || !technology->mesh_dbus_msg)
2433                 return;
2434
2435         msg = technology->mesh_dbus_msg;
2436         if (!msg) {
2437                 DBG("No pending dbus message");
2438                 return;
2439         }
2440
2441         if (result < 0)
2442                 reply = __connman_error_scan_abort_failed(msg);
2443         else
2444                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2445
2446         g_dbus_send_message(connection, reply);
2447         dbus_message_unref(msg);
2448         technology->mesh_dbus_msg = NULL;
2449 }
2450
2451 static DBusMessage *mesh_commands(DBusConnection *conn,
2452                                   DBusMessage *msg, void *data)
2453 {
2454         struct connman_technology *technology = data;
2455         DBusMessageIter iter, value, dict;
2456         const char *cmd = NULL, *ifname = NULL, *parent_ifname = NULL;
2457         int err;
2458
2459         DBG("conn %p", conn);
2460
2461         if (technology->type != CONNMAN_SERVICE_TYPE_MESH)
2462                 return __connman_error_invalid_arguments(msg);
2463
2464         if (!dbus_message_iter_init(msg, &iter))
2465                 return __connman_error_invalid_arguments(msg);
2466
2467         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
2468                 return __connman_error_invalid_arguments(msg);
2469
2470         dbus_message_iter_get_basic(&iter, &cmd);
2471         dbus_message_iter_next(&iter);
2472
2473         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
2474                 return __connman_error_invalid_arguments(msg);
2475
2476         dbus_message_iter_recurse(&iter, &value);
2477
2478         if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_ARRAY)
2479                 return __connman_error_invalid_arguments(msg);
2480
2481         DBG("Mesh Command %s", cmd);
2482         if (g_str_equal(cmd, "MeshInterfaceAdd")) {
2483                 dbus_message_iter_recurse(&value, &dict);
2484                 const char *bridge_ifname = NULL;
2485                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2486                         DBusMessageIter entry, value2;
2487                         const char *key;
2488                         int type;
2489
2490                         dbus_message_iter_recurse(&dict, &entry);
2491
2492                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2493                                 return __connman_error_invalid_arguments(msg);
2494
2495                         dbus_message_iter_get_basic(&entry, &key);
2496                         dbus_message_iter_next(&entry);
2497
2498                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
2499                                 return __connman_error_invalid_arguments(msg);
2500
2501                         dbus_message_iter_recurse(&entry, &value2);
2502
2503                         type = dbus_message_iter_get_arg_type(&value2);
2504
2505                         if (g_str_equal(key, "Ifname")) {
2506                                 if (type != DBUS_TYPE_STRING)
2507                                         return __connman_error_invalid_arguments(msg);
2508
2509                                 dbus_message_iter_get_basic(&value2, &ifname);
2510                         } else if (g_str_equal(key, "ParentIfname")) {
2511                                 if (type != DBUS_TYPE_STRING)
2512                                         return __connman_error_invalid_arguments(msg);
2513
2514                                 dbus_message_iter_get_basic(&value2, &parent_ifname);
2515                         } else if (g_str_equal(key, "BridgeIfname")) {
2516                                 if (type != DBUS_TYPE_STRING)
2517                                         return __connman_error_invalid_arguments(msg);
2518
2519                                 dbus_message_iter_get_basic(&value2, &bridge_ifname);
2520                         }
2521                         dbus_message_iter_next(&dict);
2522                 }
2523                 DBG("Mesh Ifname %s parent %s bridge %s", ifname, parent_ifname,
2524                                         bridge_ifname ? bridge_ifname : "NULL");
2525                 err = __connman_mesh_add_virtual_interface(ifname, parent_ifname,
2526                                                            bridge_ifname);
2527
2528                 if (err != 0) {
2529                         DBG("Failed to add virtual mesh interface");
2530                         return __connman_error_failed(msg, -err);
2531                 }
2532
2533                 DBG("Successfully added virtual mesh interface");
2534
2535                 dbus_message_ref(msg);
2536                 technology->mesh_dbus_msg = msg;
2537
2538         } else if (g_str_equal(cmd, "MeshInterfaceRemove")) {
2539                 dbus_message_iter_recurse(&value, &dict);
2540                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2541                         DBusMessageIter entry, value2;
2542                         const char *key;
2543                         int type;
2544
2545                         dbus_message_iter_recurse(&dict, &entry);
2546
2547                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2548                                 return __connman_error_invalid_arguments(msg);
2549
2550                         dbus_message_iter_get_basic(&entry, &key);
2551                         dbus_message_iter_next(&entry);
2552
2553                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
2554                                 return __connman_error_invalid_arguments(msg);
2555
2556                         dbus_message_iter_recurse(&entry, &value2);
2557
2558                         type = dbus_message_iter_get_arg_type(&value2);
2559
2560                         if (g_str_equal(key, "Ifname")) {
2561                                 if (type != DBUS_TYPE_STRING)
2562                                         return __connman_error_invalid_arguments(msg);
2563
2564                                 dbus_message_iter_get_basic(&value2, &ifname);
2565                         }
2566                         dbus_message_iter_next(&dict);
2567                 }
2568                 DBG("Mesh Ifname %s", ifname);
2569                 err = __connman_mesh_remove_virtual_interface(ifname);
2570
2571                 if (err != 0) {
2572                         DBG("Failed to remove virtual mesh interface");
2573                         return __connman_error_failed(msg, -err);
2574                 }
2575
2576                 DBG("Successfully removed virtual mesh interface");
2577
2578                 dbus_message_ref(msg);
2579                 technology->mesh_dbus_msg = msg;
2580
2581         } else if (g_str_equal(cmd, "MeshCreateNetwork")) {
2582                 struct connman_mesh *connman_mesh;
2583                 const char *name = NULL;
2584                 const char *sec_type = NULL;
2585                 const char *mesh_ifname = NULL;
2586                 char *identifier, *group, *address;
2587                 unsigned int freq = 0;
2588                 unsigned int ieee80211w = 0;
2589                 GString *str;
2590                 int i;
2591                 dbus_message_iter_recurse(&value, &dict);
2592                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2593                         DBusMessageIter entry, value2;
2594                         const char *key;
2595                         int type;
2596
2597                         dbus_message_iter_recurse(&dict, &entry);
2598
2599                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2600                                 return __connman_error_invalid_arguments(msg);
2601
2602                         dbus_message_iter_get_basic(&entry, &key);
2603                         dbus_message_iter_next(&entry);
2604
2605                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
2606                                 return __connman_error_invalid_arguments(msg);
2607
2608                         dbus_message_iter_recurse(&entry, &value2);
2609
2610                         type = dbus_message_iter_get_arg_type(&value2);
2611
2612                         if (g_str_equal(key, "Name")) {
2613                                 if (type != DBUS_TYPE_STRING)
2614                                         return __connman_error_invalid_arguments(msg);
2615
2616                                 dbus_message_iter_get_basic(&value2, &name);
2617                         } else if (g_str_equal(key, "Frequency")) {
2618                                 if (type != DBUS_TYPE_UINT16)
2619                                         return __connman_error_invalid_arguments(msg);
2620
2621                                 dbus_message_iter_get_basic(&value2, &freq);
2622                         } else if (g_str_equal(key, "Security")) {
2623                                 if (type != DBUS_TYPE_STRING)
2624                                         return __connman_error_invalid_arguments(msg);
2625
2626                                 dbus_message_iter_get_basic(&value2, &sec_type);
2627                         } else if (g_str_equal(key, "Pmf")) {
2628                                 if (type != DBUS_TYPE_UINT16)
2629                                         return __connman_error_invalid_arguments(msg);
2630
2631                                 dbus_message_iter_get_basic(&value2, &ieee80211w);
2632                         }
2633                         dbus_message_iter_next(&dict);
2634                 }
2635
2636                 if (name == NULL || sec_type == NULL || freq == 0)
2637                         return __connman_error_invalid_arguments(msg);
2638
2639                 DBG("Name %s Frequency %d Security type %s Pmf %u",
2640                     name, freq, sec_type, ieee80211w);
2641
2642                 if (g_strcmp0(sec_type, "none") != 0 &&
2643                     g_strcmp0(sec_type, "sae") != 0) {
2644                         DBG("Unsupported security");
2645                         return __connman_error_invalid_arguments(msg);
2646                 }
2647
2648                 mesh_ifname = connman_mesh_get_interface_name();
2649
2650                 if (!connman_mesh_is_interface_created()) {
2651                         DBG("Mesh interface doesn't exists");
2652                         return __connman_error_invalid_command(msg);
2653                 }
2654
2655                 str = g_string_sized_new((strlen(name) * 2) + 24);
2656
2657                 for (i = 0; name[i]; i++)
2658                         g_string_append_printf(str, "%02x", name[i]);
2659
2660                 g_string_append_printf(str, "_mesh");
2661
2662                 if (g_strcmp0(sec_type, "none") == 0)
2663                         g_string_append_printf(str, "_none");
2664                 else if (g_strcmp0(sec_type, "sae") == 0)
2665                         g_string_append_printf(str, "_sae");
2666
2667                 group = g_string_free(str, FALSE);
2668
2669                 identifier = connman_inet_ifaddr(mesh_ifname);
2670                 address = connman_inet_ifname2addr(mesh_ifname);
2671
2672                 connman_mesh = connman_mesh_create(identifier, group);
2673                 connman_mesh_set_name(connman_mesh, name);
2674                 connman_mesh_set_address(connman_mesh, address);
2675                 connman_mesh_set_security(connman_mesh, sec_type);
2676                 connman_mesh_set_frequency(connman_mesh, freq);
2677                 connman_mesh_set_index(connman_mesh, connman_inet_ifindex(mesh_ifname));
2678                 connman_mesh_set_peer_type(connman_mesh,
2679                                            CONNMAN_MESH_PEER_TYPE_CREATED);
2680                 connman_mesh_set_ieee80211w(connman_mesh, ieee80211w);
2681
2682                 connman_mesh_register(connman_mesh);
2683                 g_free(group);
2684                 g_free(identifier);
2685                 g_free(address);
2686                 DBG("Successfully Created Mesh Network");
2687                 return  g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2688
2689         } else if (g_str_equal(cmd, "AbortScan")) {
2690                 DBG("Abort Scan method");
2691                 err = __connman_device_abort_scan(technology->type);
2692                 if (err != 0) {
2693                         DBG("Failed to abort scan");
2694                         return __connman_error_failed(msg, -err);
2695                 }
2696
2697                 DBG("Successfully requested to abort scan");
2698                 dbus_message_ref(msg);
2699                 technology->mesh_dbus_msg = msg;
2700
2701         } else if (g_str_equal(cmd, "MeshSpecificScan")) {
2702                 const char *name = NULL;
2703                 unsigned int freq = 0;
2704                 dbus_message_iter_recurse(&value, &dict);
2705                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2706                         DBusMessageIter entry, value2;
2707                         const char *key;
2708                         int type;
2709
2710                         dbus_message_iter_recurse(&dict, &entry);
2711
2712                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2713                                 return __connman_error_invalid_arguments(msg);
2714
2715                         dbus_message_iter_get_basic(&entry, &key);
2716                         dbus_message_iter_next(&entry);
2717
2718                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
2719                                 return __connman_error_invalid_arguments(msg);
2720
2721                         dbus_message_iter_recurse(&entry, &value2);
2722
2723                         type = dbus_message_iter_get_arg_type(&value2);
2724
2725                         if (g_str_equal(key, "Name")) {
2726                                 if (type != DBUS_TYPE_STRING)
2727                                         return __connman_error_invalid_arguments(msg);
2728
2729                                 dbus_message_iter_get_basic(&value2, &name);
2730                         } else if (g_str_equal(key, "Frequency")) {
2731                                 if (type != DBUS_TYPE_UINT16)
2732                                         return __connman_error_invalid_arguments(msg);
2733
2734                                 dbus_message_iter_get_basic(&value2, &freq);
2735                         }
2736                         dbus_message_iter_next(&dict);
2737                 }
2738
2739                 DBG("MeshID %s Frequency %d sender %s", name, freq,
2740                                                 dbus_message_get_sender(msg));
2741
2742                 struct connman_scan_pending *pending_data =
2743                                 g_try_malloc0(sizeof(struct connman_scan_pending));
2744                 if (!pending_data)
2745                         return __connman_error_failed(msg, ENOMEM);
2746
2747                 pending_data->msg = dbus_message_ref(msg);
2748
2749                 technology->scan_pending =
2750                         g_slist_prepend(technology->scan_pending, pending_data);
2751
2752                 err = __connman_device_request_mesh_specific_scan(technology->type,
2753                                                                   name, freq);
2754                 if (err < 0)
2755                         reply_scan_pending(technology, err);
2756                 else
2757                         DBG("Successfully requested to scan specific Mesh Network");
2758
2759         } else if (g_str_equal(cmd, "SetMeshGate")) {
2760                 unsigned int hwmp_rootmode = 0;
2761                 bool gate_announce = false;
2762                 unsigned int stp = 0;
2763                 int err;
2764                 dbus_message_iter_recurse(&value, &dict);
2765                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2766                         DBusMessageIter entry, value2;
2767                         const char *key;
2768                         int type;
2769
2770                         dbus_message_iter_recurse(&dict, &entry);
2771
2772                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2773                                 return __connman_error_invalid_arguments(msg);
2774
2775                         dbus_message_iter_get_basic(&entry, &key);
2776                         dbus_message_iter_next(&entry);
2777
2778                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
2779                                 return __connman_error_invalid_arguments(msg);
2780
2781                         dbus_message_iter_recurse(&entry, &value2);
2782
2783                         type = dbus_message_iter_get_arg_type(&value2);
2784
2785                         if (g_str_equal(key, "GateAnnounce")) {
2786                                 if (type != DBUS_TYPE_BOOLEAN)
2787                                         return __connman_error_invalid_arguments(msg);
2788
2789                                 dbus_message_iter_get_basic(&value2, &gate_announce);
2790                         } else if (g_str_equal(key, "HWMPRootMode")) {
2791                                 if (type != DBUS_TYPE_UINT16)
2792                                         return __connman_error_invalid_arguments(msg);
2793
2794                                 dbus_message_iter_get_basic(&value2, &hwmp_rootmode);
2795                         } else if (g_str_equal(key, "STP")) {
2796                                 if (type != DBUS_TYPE_UINT16)
2797                                         return __connman_error_invalid_arguments(msg);
2798
2799                                 dbus_message_iter_get_basic(&value2, &stp);
2800                         }
2801                         dbus_message_iter_next(&dict);
2802                 }
2803
2804                 DBG("GateAnnounce %d HWMPRootMode %d STP %d sender %s",
2805                     gate_announce, hwmp_rootmode, stp, dbus_message_get_sender(msg));
2806
2807                 err = __connman_mesh_set_stp_gate_announce(gate_announce,
2808                                                            hwmp_rootmode,
2809                                                            stp);
2810
2811                 if (err < 0)
2812                         return __connman_error_failed(msg, -err);
2813
2814                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2815         } else
2816                 return __connman_error_invalid_command(msg);
2817         return NULL;
2818 }
2819 #endif
2820
2821 static const GDBusMethodTable technology_methods[] = {
2822         { GDBUS_DEPRECATED_METHOD("GetProperties",
2823                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
2824                         get_properties) },
2825         { GDBUS_ASYNC_METHOD("SetProperty",
2826                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
2827                         NULL, set_property) },
2828         { GDBUS_ASYNC_METHOD("Scan", NULL, NULL, scan) },
2829 #if defined TIZEN_EXT
2830         { GDBUS_ASYNC_METHOD("ScanDevice", GDBUS_ARGS({ "interface_name", "s" }),
2831                         NULL, scan_device) },
2832         { GDBUS_ASYNC_METHOD("SpecificScan", GDBUS_ARGS({ "specificscan", "a{sv}" }),
2833                         NULL, specific_scan) },
2834         { GDBUS_METHOD("GetScanState", NULL, GDBUS_ARGS({ "scan_state", "a{sv}" }),
2835                         get_scan_state) },
2836         { GDBUS_METHOD("Get5GhzSupported", NULL, GDBUS_ARGS({ "supported", "a{sv}" }),
2837                         get_5ghz_supported) },
2838         { GDBUS_METHOD("GetMaxScanSsid", NULL, GDBUS_ARGS({ "maxscanssid", "a{sv}" }),
2839                         get_max_scan_ssid) },
2840         { GDBUS_ASYNC_METHOD("SetDevicePower",
2841                         GDBUS_ARGS({ "ifname", "s" }, { "value", "b" }),
2842                         NULL, set_device_power) },
2843         { GDBUS_ASYNC_METHOD("SetBSSID",
2844                         GDBUS_ARGS({ "ifname", "s" }, { "bssid", "s" }),
2845                         NULL, set_bssid) },
2846 #endif
2847 #if defined TIZEN_EXT_WIFI_MESH
2848         { GDBUS_ASYNC_METHOD("MeshCommands",
2849                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
2850                         NULL, mesh_commands) },
2851 #endif
2852         { },
2853 };
2854
2855 static const GDBusSignalTable technology_signals[] = {
2856         { GDBUS_SIGNAL("PropertyChanged",
2857                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
2858 #if defined TIZEN_EXT
2859         { GDBUS_SIGNAL("DeviceChanged",
2860                         GDBUS_ARGS({ "device_property", "a{sv}" })) },
2861         { GDBUS_SIGNAL("DeviceDetected",
2862                         GDBUS_ARGS({ "ifname", "s" }, { "detected", "b" })) },
2863 #endif
2864         { },
2865 };
2866
2867 static bool technology_dbus_register(struct connman_technology *technology)
2868 {
2869         if (technology->dbus_registered ||
2870                                 (technology->rfkill_driven &&
2871                                  technology->hardblocked))
2872                 return true;
2873
2874         if (!g_dbus_register_interface(connection, technology->path,
2875                                         CONNMAN_TECHNOLOGY_INTERFACE,
2876                                         technology_methods, technology_signals,
2877                                         NULL, technology, NULL)) {
2878                 connman_error("Failed to register %s", technology->path);
2879                 return false;
2880         }
2881
2882         technology_added_signal(technology);
2883         technology->dbus_registered = true;
2884
2885         return true;
2886 }
2887
2888 static void technology_dbus_unregister(struct connman_technology *technology)
2889 {
2890         if (!technology->dbus_registered)
2891                 return;
2892
2893         technology_removed_signal(technology);
2894         g_dbus_unregister_interface(connection, technology->path,
2895                 CONNMAN_TECHNOLOGY_INTERFACE);
2896
2897         technology->dbus_registered = false;
2898 }
2899
2900 static void technology_put(struct connman_technology *technology)
2901 {
2902         DBG("technology %p", technology);
2903
2904         if (__sync_sub_and_fetch(&technology->refcount, 1) > 0)
2905                 return;
2906
2907         reply_scan_pending(technology, -EINTR);
2908
2909         while (technology->driver_list) {
2910                 struct connman_technology_driver *driver;
2911
2912                 driver = technology->driver_list->data;
2913
2914                 if (driver->remove)
2915                         driver->remove(technology);
2916
2917                 technology->driver_list =
2918                         g_slist_delete_link(technology->driver_list,
2919                                         technology->driver_list);
2920         }
2921
2922         technology_list = g_slist_remove(technology_list, technology);
2923
2924         technology_dbus_unregister(technology);
2925
2926         g_slist_free(technology->device_list);
2927
2928     if (technology->pending_reply) {
2929         dbus_message_unref(technology->pending_reply);
2930         technology->pending_reply = NULL;
2931         g_source_remove(technology->pending_timeout);
2932         technology->pending_timeout = 0;
2933     }
2934 #ifdef TIZEN_EXT
2935     g_strfreev(technology->enabled_devices);
2936 #endif
2937         g_free(technology->path);
2938         g_free(technology->regdom);
2939         g_free(technology->tethering_ident);
2940         g_free(technology->tethering_passphrase);
2941         g_free(technology);
2942 }
2943
2944 static struct connman_technology *technology_get(enum connman_service_type type)
2945 {
2946         GSList *tech_drivers = NULL;
2947         struct connman_technology_driver *driver;
2948         struct connman_technology *technology;
2949         const char *str;
2950         GSList *list;
2951
2952         DBG("type %d", type);
2953
2954         str = __connman_service_type2string(type);
2955         if (!str)
2956                 return NULL;
2957
2958         technology = technology_find(type);
2959         if (technology) {
2960 #if defined TIZEN_EXT_WIFI_MESH
2961                 if (type != CONNMAN_SERVICE_TYPE_P2P &&
2962                         type != CONNMAN_SERVICE_TYPE_MESH)
2963 #else
2964                 if (type != CONNMAN_SERVICE_TYPE_P2P)
2965 #endif
2966                         __sync_fetch_and_add(&technology->refcount, 1);
2967                 return technology;
2968         }
2969
2970         /* First check if we have a driver for this technology type */
2971         for (list = driver_list; list; list = list->next) {
2972                 driver = list->data;
2973
2974                 if (driver->type == type) {
2975                         DBG("technology %p driver %p", technology, driver);
2976                         tech_drivers = g_slist_append(tech_drivers, driver);
2977                 }
2978         }
2979
2980         if (!tech_drivers) {
2981                 DBG("No matching drivers found for %s.",
2982                                 __connman_service_type2string(type));
2983                 return NULL;
2984         }
2985
2986         technology = g_try_new0(struct connman_technology, 1);
2987         if (!technology)
2988                 return NULL;
2989
2990         technology->refcount = 1;
2991         technology->type = type;
2992         technology->path = g_strdup_printf("%s/technology/%s",
2993                                                         CONNMAN_PATH, str);
2994
2995 #if defined TIZEN_EXT_WIFI_MESH
2996         if (type == CONNMAN_SERVICE_TYPE_MESH) {
2997                 struct connman_technology *wifi;
2998
2999                 wifi = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
3000                 if (wifi)
3001                         technology->enabled = wifi->enabled;
3002         }
3003 #endif
3004
3005         technology_load(technology);
3006         technology_list = g_slist_prepend(technology_list, technology);
3007         technology->driver_list = tech_drivers;
3008
3009         for (list = tech_drivers; list; list = list->next) {
3010                 driver = list->data;
3011
3012                 if (driver->probe && driver->probe(technology) < 0)
3013                         DBG("Driver probe failed for technology %p",
3014                                         technology);
3015         }
3016
3017         if (!technology_dbus_register(technology)) {
3018                 technology_put(technology);
3019                 return NULL;
3020         }
3021
3022         if (type == CONNMAN_SERVICE_TYPE_P2P) {
3023                 struct connman_technology *wifi;
3024                 bool enable;
3025
3026                 enable = technology->enable_persistent;
3027
3028                 wifi = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
3029                 if (enable && wifi)
3030                         enable = wifi->enabled;
3031
3032                 technology_affect_devices(technology, enable);
3033         }
3034
3035         DBG("technology %p %s", technology, get_name(technology->type));
3036
3037         return technology;
3038 }
3039
3040 int connman_technology_driver_register(struct connman_technology_driver *driver)
3041 {
3042         GSList *list;
3043         struct connman_device *device;
3044         enum connman_service_type type;
3045
3046         for (list = driver_list; list; list = list->next) {
3047                 if (list->data == driver)
3048                         goto exist;
3049         }
3050
3051         DBG("Registering %s driver", driver->name);
3052
3053         driver_list = g_slist_insert_sorted(driver_list, driver,
3054                                                         compare_priority);
3055
3056         /*
3057          * Check for technology less devices if this driver
3058          * can service any of them.
3059         */
3060         for (list = techless_device_list; list; list = list->next) {
3061                 device = list->data;
3062
3063                 type = __connman_device_get_service_type(device);
3064                 if (type != driver->type)
3065                         continue;
3066
3067                 techless_device_list = g_slist_remove(techless_device_list,
3068                                                                 device);
3069
3070                 __connman_technology_add_device(device);
3071         }
3072
3073         /* Check for orphaned rfkill switches. */
3074         g_hash_table_foreach(rfkill_list, rfkill_check,
3075                                         GINT_TO_POINTER(driver->type));
3076
3077 exist:
3078         if (driver->type == CONNMAN_SERVICE_TYPE_P2P) {
3079                 if (!technology_get(CONNMAN_SERVICE_TYPE_P2P))
3080                         return -ENOMEM;
3081         }
3082
3083 #if defined TIZEN_EXT_WIFI_MESH
3084         if (driver->type == CONNMAN_SERVICE_TYPE_MESH) {
3085                 if (!technology_get(CONNMAN_SERVICE_TYPE_MESH))
3086                         return -ENOMEM;
3087         }
3088 #endif
3089
3090         return 0;
3091 }
3092
3093 void connman_technology_driver_unregister(struct connman_technology_driver *driver)
3094 {
3095         GSList *list, *tech_drivers;
3096         struct connman_technology *technology;
3097         struct connman_technology_driver *current;
3098
3099         DBG("Unregistering driver %p name %s", driver, driver->name);
3100
3101         for (list = technology_list; list; list = list->next) {
3102                 technology = list->data;
3103
3104                 for (tech_drivers = technology->driver_list; tech_drivers;
3105                                 tech_drivers = g_slist_next(tech_drivers)) {
3106                         current = tech_drivers->data;
3107                         if (driver != current)
3108                                 continue;
3109
3110                         if (driver->remove)
3111                                 driver->remove(technology);
3112
3113                         technology->driver_list =
3114                                 g_slist_remove(technology->driver_list,
3115                                                                 driver);
3116                         break;
3117                 }
3118         }
3119
3120         driver_list = g_slist_remove(driver_list, driver);
3121
3122         if (driver->type == CONNMAN_SERVICE_TYPE_P2P) {
3123                 technology = technology_find(CONNMAN_SERVICE_TYPE_P2P);
3124                 if (technology)
3125                         technology_put(technology);
3126         }
3127 #if defined TIZEN_EXT_WIFI_MESH
3128         if (driver->type == CONNMAN_SERVICE_TYPE_MESH) {
3129                 technology = technology_find(CONNMAN_SERVICE_TYPE_MESH);
3130                 if (technology)
3131                         technology_put(technology);
3132         }
3133 #endif
3134 }
3135
3136 void __connman_technology_add_interface(enum connman_service_type type,
3137                                 int index, const char *ident)
3138 {
3139         struct connman_technology *technology;
3140         GSList *tech_drivers;
3141         struct connman_technology_driver *driver;
3142         char *name;
3143
3144         switch (type) {
3145         case CONNMAN_SERVICE_TYPE_UNKNOWN:
3146         case CONNMAN_SERVICE_TYPE_SYSTEM:
3147                 return;
3148         case CONNMAN_SERVICE_TYPE_ETHERNET:
3149         case CONNMAN_SERVICE_TYPE_WIFI:
3150         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
3151         case CONNMAN_SERVICE_TYPE_CELLULAR:
3152         case CONNMAN_SERVICE_TYPE_GPS:
3153         case CONNMAN_SERVICE_TYPE_VPN:
3154         case CONNMAN_SERVICE_TYPE_GADGET:
3155         case CONNMAN_SERVICE_TYPE_P2P:
3156 #if defined TIZEN_EXT_WIFI_MESH
3157         case CONNMAN_SERVICE_TYPE_MESH:
3158 #endif
3159                 break;
3160         }
3161
3162         name = connman_inet_ifname(index);
3163         connman_info("Adding interface %s [ %s ]", name,
3164                                 __connman_service_type2string(type));
3165
3166         technology = technology_find(type);
3167
3168         if (!technology)
3169                 goto out;
3170
3171         for (tech_drivers = technology->driver_list; tech_drivers;
3172              tech_drivers = g_slist_next(tech_drivers)) {
3173                 driver = tech_drivers->data;
3174
3175                 if (driver->add_interface)
3176                         driver->add_interface(technology, index, name, ident);
3177         }
3178
3179         /*
3180          * At this point we can try to enable tethering automatically as
3181          * now the interfaces are set properly.
3182          */
3183         if (technology->tethering_persistent)
3184                 enable_tethering(technology);
3185
3186 out:
3187         g_free(name);
3188 }
3189
3190 void __connman_technology_remove_interface(enum connman_service_type type,
3191                                 int index, const char *ident)
3192 {
3193         struct connman_technology *technology;
3194         GSList *tech_drivers;
3195         struct connman_technology_driver *driver;
3196         char *name;
3197
3198         switch (type) {
3199         case CONNMAN_SERVICE_TYPE_UNKNOWN:
3200         case CONNMAN_SERVICE_TYPE_SYSTEM:
3201                 return;
3202         case CONNMAN_SERVICE_TYPE_ETHERNET:
3203         case CONNMAN_SERVICE_TYPE_WIFI:
3204         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
3205         case CONNMAN_SERVICE_TYPE_CELLULAR:
3206         case CONNMAN_SERVICE_TYPE_GPS:
3207         case CONNMAN_SERVICE_TYPE_VPN:
3208         case CONNMAN_SERVICE_TYPE_GADGET:
3209         case CONNMAN_SERVICE_TYPE_P2P:
3210 #if defined TIZEN_EXT_WIFI_MESH
3211         case CONNMAN_SERVICE_TYPE_MESH:
3212 #endif
3213                 break;
3214         }
3215
3216         name = connman_inet_ifname(index);
3217         connman_info("Remove interface %s [ %s ]", name,
3218                                 __connman_service_type2string(type));
3219         g_free(name);
3220
3221         technology = technology_find(type);
3222
3223         if (!technology)
3224                 return;
3225
3226         for (tech_drivers = technology->driver_list; tech_drivers;
3227              tech_drivers = g_slist_next(tech_drivers)) {
3228                 driver = tech_drivers->data;
3229
3230                 if (driver->remove_interface)
3231                         driver->remove_interface(technology, index);
3232         }
3233 }
3234
3235 int __connman_technology_add_device(struct connman_device *device)
3236 {
3237         struct connman_technology *technology;
3238         enum connman_service_type type;
3239
3240         type = __connman_device_get_service_type(device);
3241
3242         DBG("device %p type %s", device, get_name(type));
3243
3244         technology = technology_get(type);
3245         if (!technology) {
3246                 /*
3247                  * Since no driver can be found for this device at the moment we
3248                  * add it to the techless device list.
3249                 */
3250                 techless_device_list = g_slist_prepend(techless_device_list,
3251                                                                 device);
3252
3253                 return -ENXIO;
3254         }
3255
3256         __sync_synchronize();
3257         if (technology->rfkill_driven) {
3258                 if (technology->enabled)
3259                         __connman_device_enable(device);
3260                 else
3261                         __connman_device_disable(device);
3262
3263                 goto done;
3264         }
3265
3266         if (technology->enable_persistent &&
3267                                         !global_offlinemode) {
3268 #if defined TIZEN_EXT
3269                 bool found = true;
3270                 int err = 0;
3271                 if (technology->enabled_devices && type == CONNMAN_SERVICE_TYPE_WIFI) {
3272                         int i = 0;
3273                         found = false;
3274                         const char *ifname = connman_device_get_string(device, "Interface");
3275
3276                         while (technology->enabled_devices[i]) {
3277                                 if (g_strcmp0(technology->enabled_devices[i], ifname) == 0) {
3278                                         found = true;
3279                                         break;
3280                                 }
3281                                 i++;
3282                         }
3283                 }
3284
3285                 if (found)
3286                         err = __connman_device_enable(device);
3287 #else
3288                 int err = __connman_device_enable(device);
3289 #endif
3290                 /*
3291                  * connman_technology_add_device() calls __connman_device_enable()
3292                  * but since the device is already enabled, the call does not
3293                  * propagate through to connman_technology_enabled via
3294                  * connman_device_set_powered.
3295                  */
3296                 if (err == -EALREADY)
3297                         __connman_technology_enabled(type);
3298         }
3299         /* if technology persistent state is offline */
3300         if (!technology->enable_persistent)
3301                 __connman_device_disable(device);
3302
3303 done:
3304         technology->device_list = g_slist_prepend(technology->device_list,
3305                                                                 device);
3306
3307 #if defined TIZEN_EXT
3308         technology_save_device(device);
3309
3310         const char *ifname = connman_device_get_string(device, "Interface");
3311         __connman_technology_notify_device_detected(technology, ifname, true);
3312
3313         connman_device_set_mac_policy(device, technology->mac_policy);
3314         connman_device_set_preassoc_mac_policy(device, technology->preassoc_mac_policy);
3315         connman_device_set_random_mac_lifetime(device, technology->random_mac_lifetime);
3316 #endif
3317         return 0;
3318 }
3319
3320 int __connman_technology_remove_device(struct connman_device *device)
3321 {
3322         struct connman_technology *technology;
3323         enum connman_service_type type;
3324
3325         DBG("device %p", device);
3326
3327         type = __connman_device_get_service_type(device);
3328
3329         technology = technology_find(type);
3330         if (!technology) {
3331                 techless_device_list = g_slist_remove(techless_device_list,
3332                                                                 device);
3333                 return -ENXIO;
3334         }
3335
3336         technology->device_list = g_slist_remove(technology->device_list,
3337                                                                 device);
3338
3339 #if defined TIZEN_EXT
3340         technology_save_device(device);
3341
3342         const char *ifname = connman_device_get_string(device, "Interface");
3343         __connman_technology_notify_device_detected(technology, ifname, false);
3344 #endif
3345
3346         if (technology->tethering)
3347                 set_tethering(technology, false);
3348
3349         technology_put(technology);
3350
3351         return 0;
3352 }
3353
3354 int __connman_technology_enabled(enum connman_service_type type)
3355 {
3356         struct connman_technology *technology;
3357
3358         technology = technology_find(type);
3359         if (!technology)
3360                 return -ENXIO;
3361
3362         DBG("technology %p type %s rfkill %d enabled %d", technology,
3363                 get_name(type), technology->rfkill_driven,
3364                 technology->enabled);
3365
3366 #if !defined TIZEN_EXT
3367         if (technology->rfkill_driven) {
3368                 if (technology->tethering_persistent)
3369                         enable_tethering(technology);
3370                 return 0;
3371         }
3372 #endif
3373
3374         return technology_enabled(technology);
3375 }
3376
3377 int __connman_technology_disabled(enum connman_service_type type)
3378 {
3379         struct connman_technology *technology;
3380         GSList *list;
3381
3382         technology = technology_find(type);
3383         if (!technology)
3384                 return -ENXIO;
3385
3386 #if !defined TIZEN_EXT
3387         if (technology->rfkill_driven)
3388                 return 0;
3389
3390 #endif
3391         for (list = technology->device_list; list; list = list->next) {
3392                 struct connman_device *device = list->data;
3393
3394                 if (connman_device_get_powered(device))
3395                         return 0;
3396         }
3397
3398         return technology_disabled(technology);
3399 }
3400
3401 int __connman_technology_set_offlinemode(bool offlinemode)
3402 {
3403         GSList *list;
3404         int err = -EINVAL, enabled_tech_count = 0;
3405
3406         if (global_offlinemode == offlinemode)
3407                 return 0;
3408
3409         DBG("offlinemode %s", offlinemode ? "On" : "Off");
3410
3411         /*
3412          * This is a bit tricky. When you set offlinemode, there is no
3413          * way to differentiate between attempting offline mode and
3414          * resuming offlinemode from last saved profile. We need that
3415          * information in rfkill_update, otherwise it falls back on the
3416          * technology's persistent state. Hence we set the offline mode here
3417          * but save it & call the notifier only if it is successful.
3418          */
3419
3420         global_offlinemode = offlinemode;
3421
3422         /* Traverse technology list, enable/disable each technology. */
3423         for (list = technology_list; list; list = list->next) {
3424                 struct connman_technology *technology = list->data;
3425
3426                 if (offlinemode)
3427                         err = technology_disable(technology);
3428                 else {
3429                         if (technology->hardblocked)
3430                                 continue;
3431
3432                         if (technology->enable_persistent) {
3433                                 err = technology_enable(technology);
3434                                 enabled_tech_count++;
3435                         }
3436                 }
3437         }
3438
3439         if (err == 0 || err == -EINPROGRESS || err == -EALREADY ||
3440                         (err == -EINVAL && enabled_tech_count == 0)) {
3441                 connman_technology_save_offlinemode();
3442                 __connman_notifier_offlinemode(offlinemode);
3443         } else
3444                 global_offlinemode = connman_technology_load_offlinemode();
3445
3446         return err;
3447 }
3448
3449 #if defined TIZEN_EXT_WIFI_MESH
3450 static gboolean __add_ethernet_to_bridge(gpointer data)
3451 {
3452         DBG("");
3453         __connman_mesh_add_ethernet_to_bridge();
3454         return FALSE;
3455 }
3456 #endif
3457
3458 void __connman_technology_set_connected(enum connman_service_type type,
3459                 bool connected)
3460 {
3461         struct connman_technology *technology;
3462         dbus_bool_t val;
3463
3464         technology = technology_find(type);
3465         if (!technology)
3466                 return;
3467
3468         DBG("technology %p connected %d", technology, connected);
3469
3470         technology->connected = connected;
3471
3472 #if defined TIZEN_EXT_WIFI_MESH
3473         if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET && connected)
3474                 g_idle_add(__add_ethernet_to_bridge, NULL);
3475 #endif
3476
3477         val = connected;
3478         connman_dbus_property_changed_basic(technology->path,
3479                         CONNMAN_TECHNOLOGY_INTERFACE, "Connected",
3480                         DBUS_TYPE_BOOLEAN, &val);
3481 }
3482
3483 static bool technology_apply_rfkill_change(struct connman_technology *technology,
3484                                                 bool softblock,
3485                                                 bool hardblock,
3486                                                 bool new_rfkill)
3487 {
3488         bool hardblock_changed = false;
3489         bool apply = true;
3490         GList *start, *list;
3491
3492         DBG("technology %p --> %d/%d vs %d/%d",
3493                         technology, softblock, hardblock,
3494                         technology->softblocked, technology->hardblocked);
3495
3496         if (technology->hardblocked == hardblock)
3497                 goto softblock_change;
3498
3499         if (!(new_rfkill && !hardblock)) {
3500                 start = g_hash_table_get_values(rfkill_list);
3501
3502                 for (list = start; list; list = list->next) {
3503                         struct connman_rfkill *rfkill = list->data;
3504
3505                         if (rfkill->type != technology->type)
3506                                 continue;
3507
3508                         if (rfkill->hardblock != hardblock)
3509                                 apply = false;
3510                 }
3511
3512                 g_list_free(start);
3513         }
3514
3515         if (!apply)
3516                 goto softblock_change;
3517
3518         technology->hardblocked = hardblock;
3519         hardblock_changed = true;
3520
3521 softblock_change:
3522         if (!apply && technology->softblocked != softblock)
3523                 apply = true;
3524
3525         if (!apply)
3526                 return technology->hardblocked;
3527
3528         technology->softblocked = softblock;
3529
3530         if (technology->hardblocked ||
3531                                         technology->softblocked) {
3532                 if (technology_disabled(technology) != -EALREADY)
3533                         technology_affect_devices(technology, false);
3534         } else if (!technology->hardblocked &&
3535                                         !technology->softblocked) {
3536                 if (technology_enabled(technology) != -EALREADY)
3537                         technology_affect_devices(technology, true);
3538         }
3539
3540         if (hardblock_changed) {
3541                 if (technology->hardblocked) {
3542                         DBG("%s is switched off.", get_name(technology->type));
3543                         technology_dbus_unregister(technology);
3544                 } else {
3545                         DBG("%s is switched on.", get_name(technology->type));
3546                         technology_dbus_register(technology);
3547
3548                         if (global_offlinemode)
3549                                 __connman_rfkill_block(technology->type, true);
3550                 }
3551         }
3552
3553         return technology->hardblocked;
3554 }
3555
3556 int __connman_technology_add_rfkill(unsigned int index,
3557                                         enum connman_service_type type,
3558                                                 bool softblock,
3559                                                 bool hardblock)
3560 {
3561         struct connman_technology *technology;
3562         struct connman_rfkill *rfkill;
3563
3564         DBG("index %u type %d soft %u hard %u", index, type,
3565                                                         softblock, hardblock);
3566
3567         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
3568         if (rfkill)
3569                 goto done;
3570
3571         rfkill = g_try_new0(struct connman_rfkill, 1);
3572         if (!rfkill)
3573                 return -ENOMEM;
3574
3575         rfkill->index = index;
3576         rfkill->type = type;
3577         rfkill->softblock = softblock;
3578         rfkill->hardblock = hardblock;
3579
3580         g_hash_table_insert(rfkill_list, GINT_TO_POINTER(index), rfkill);
3581
3582 done:
3583 #if defined TIZEN_EXT
3584         /* Fix Svace Issue [WGID: 1348]. */
3585         g_free(rfkill);
3586 #endif
3587         technology = technology_get(type);
3588         /* If there is no driver for this type, ignore it. */
3589         if (!technology)
3590                 return -ENXIO;
3591
3592         technology->rfkill_driven = true;
3593
3594 #if !defined TIZEN_EXT
3595         /* If hardblocked, there is no need to handle softblocked state */
3596         if (technology_apply_rfkill_change(technology,
3597                                 softblock, hardblock, true))
3598                 return 0;
3599 #endif
3600
3601         if (global_offlinemode)
3602                 return 0;
3603
3604         /*
3605          * Depending on softblocked state we unblock/block according to
3606          * offlinemode and persistente state.
3607          */
3608         if (technology->softblocked &&
3609                                 technology->enable_persistent)
3610                 return __connman_rfkill_block(type, false);
3611         else if (!technology->softblocked &&
3612                                 !technology->enable_persistent)
3613                 return __connman_rfkill_block(type, true);
3614
3615         return 0;
3616 }
3617
3618 int __connman_technology_update_rfkill(unsigned int index,
3619                                         enum connman_service_type type,
3620                                                 bool softblock,
3621                                                 bool hardblock)
3622 {
3623         struct connman_technology *technology;
3624         struct connman_rfkill *rfkill;
3625
3626         DBG("index %u soft %u hard %u", index, softblock, hardblock);
3627
3628         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
3629         if (!rfkill)
3630                 return -ENXIO;
3631
3632         if (rfkill->softblock == softblock &&
3633                                 rfkill->hardblock == hardblock)
3634                 return 0;
3635
3636         rfkill->softblock = softblock;
3637         rfkill->hardblock = hardblock;
3638
3639         technology = technology_find(type);
3640         /* If there is no driver for this type, ignore it. */
3641         if (!technology)
3642                 return -ENXIO;
3643
3644         technology_apply_rfkill_change(technology, softblock, hardblock,
3645                                                                 false);
3646
3647         if (technology->hardblocked)
3648                 DBG("%s hardblocked", get_name(technology->type));
3649         else
3650                 DBG("%s is%s softblocked", get_name(technology->type),
3651                         technology->softblocked ? "" : " not");
3652
3653         return 0;
3654 }
3655
3656 int __connman_technology_remove_rfkill(unsigned int index,
3657                                         enum connman_service_type type)
3658 {
3659         struct connman_technology *technology;
3660         struct connman_rfkill *rfkill;
3661
3662         DBG("index %u", index);
3663
3664         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
3665         if (!rfkill)
3666                 return -ENXIO;
3667
3668         g_hash_table_remove(rfkill_list, GINT_TO_POINTER(index));
3669
3670         technology = technology_find(type);
3671         if (!technology)
3672                 return -ENXIO;
3673
3674         technology_apply_rfkill_change(technology,
3675                 technology->softblocked, !technology->hardblocked, false);
3676
3677         technology_put(technology);
3678
3679         return 0;
3680 }
3681
3682 int __connman_technology_init(void)
3683 {
3684         DBG("");
3685
3686         connection = connman_dbus_get_connection();
3687
3688         rfkill_list = g_hash_table_new_full(g_direct_hash, g_direct_equal,
3689                                                         NULL, free_rfkill);
3690
3691         global_offlinemode = connman_technology_load_offlinemode();
3692
3693         /* This will create settings file if it is missing */
3694         connman_technology_save_offlinemode();
3695
3696         return 0;
3697 }
3698
3699 void __connman_technology_cleanup(void)
3700 {
3701         DBG("");
3702
3703         while (technology_list) {
3704                 struct connman_technology *technology = technology_list->data;
3705                 technology_list = g_slist_remove(technology_list, technology);
3706                 technology_put(technology);
3707         }
3708
3709         g_hash_table_destroy(rfkill_list);
3710
3711         dbus_connection_unref(connection);
3712 }