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