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