6a539dc03255c4c99ed697320e947586f6540afd
[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 #endif
1667
1668 void __connman_technology_scan_started(struct connman_device *device)
1669 {
1670         DBG("device %p", device);
1671 #if defined TIZEN_EXT
1672         dbus_bool_t status = 1;
1673         const char *ifname = connman_device_get_string(device, "Interface");
1674
1675         __connman_technology_notify_scan_changed(ifname, &status);
1676 #endif
1677 }
1678
1679 void __connman_technology_scan_stopped(struct connman_device *device,
1680                                         enum connman_service_type type)
1681 {
1682         int count = 0;
1683         struct connman_technology *technology;
1684         GSList *list;
1685
1686         technology = technology_find(type);
1687
1688         DBG("technology %p device %p", technology, device);
1689
1690         if (!technology)
1691                 return;
1692
1693         for (list = technology->device_list; list; list = list->next) {
1694                 struct connman_device *other_device = list->data;
1695
1696                 if (device == other_device)
1697                         continue;
1698
1699                 if (connman_device_get_scanning(other_device, type))
1700                         count += 1;
1701         }
1702
1703 #if defined TIZEN_EXT
1704         const char *ifname = connman_device_get_string(device, "Interface");
1705         reply_scan_pending_device(technology, ifname, count);
1706
1707         return;
1708 #else
1709         if (count == 0)
1710                 reply_scan_pending(technology, 0);
1711 #endif
1712 }
1713
1714 void __connman_technology_notify_regdom_by_device(struct connman_device *device,
1715                                                 int result, const char *alpha2)
1716 {
1717         bool regdom_set = false;
1718         struct connman_technology *technology;
1719         enum connman_service_type type;
1720         GSList *tech_drivers;
1721
1722         type = __connman_device_get_service_type(device);
1723         technology = technology_find(type);
1724
1725         if (!technology)
1726                 return;
1727
1728         if (result < 0) {
1729
1730                 for (tech_drivers = technology->driver_list;
1731                      tech_drivers;
1732                      tech_drivers = g_slist_next(tech_drivers)) {
1733                         struct connman_technology_driver *driver =
1734                                 tech_drivers->data;
1735
1736                         if (driver->set_regdom) {
1737                                 driver->set_regdom(technology, alpha2);
1738                                 regdom_set = true;
1739                         }
1740
1741                 }
1742
1743                 if (!regdom_set)
1744                         alpha2 = NULL;
1745         }
1746
1747         connman_technology_regdom_notify(technology, alpha2);
1748 }
1749
1750 static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data)
1751 {
1752         struct connman_technology *technology = data;
1753         int err;
1754
1755         DBG("technology %p request from %s", technology,
1756                         dbus_message_get_sender(msg));
1757
1758         if (technology->type == CONNMAN_SERVICE_TYPE_P2P &&
1759                                 !technology->enabled)
1760                 return __connman_error_permission_denied(msg);
1761
1762 #if !defined TIZEN_EXT
1763         dbus_message_ref(msg);
1764         technology->scan_pending =
1765                 g_slist_prepend(technology->scan_pending, msg);
1766 #endif
1767
1768         err = __connman_device_request_scan_full(technology->type);
1769         if (err < 0)
1770 #if defined TIZEN_EXT
1771                 return __connman_error_failed(msg, -err);
1772 #else
1773                 reply_scan_pending(technology, err);
1774 #endif
1775
1776 #if defined TIZEN_EXT
1777         struct connman_scan_pending *pending_data =
1778                         g_try_malloc0(sizeof(struct connman_scan_pending));
1779         if (!pending_data)
1780                 return __connman_error_failed(msg, ENOMEM);
1781
1782         pending_data->scan_type = CONNMAN_SCAN_TYPE_FULL_CHANNEL;
1783         DBG("scan_type %d", pending_data->scan_type);
1784
1785         pending_data->msg = dbus_message_ref(msg);
1786
1787         technology->scan_pending =
1788                 g_slist_prepend(technology->scan_pending, pending_data);
1789 #endif
1790         return NULL;
1791 }
1792
1793 #if defined TIZEN_EXT
1794 static DBusMessage *scan_device(DBusConnection *conn, DBusMessage *msg, void *data)
1795 {
1796         struct connman_technology *technology = data;
1797         DBusMessageIter iter;
1798         const char *ifname;
1799         int err;
1800
1801         DBG("technology %p request from %s", technology,
1802                         dbus_message_get_sender(msg));
1803
1804         if (!dbus_message_iter_init(msg, &iter))
1805                 return __connman_error_invalid_arguments(msg);
1806
1807         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1808                 return __connman_error_invalid_arguments(msg);
1809
1810         dbus_message_iter_get_basic(&iter, &ifname);
1811         DBG("Interface name %s", ifname);
1812
1813         if (!ifname || strlen(ifname) == 0)
1814                 return __connman_error_invalid_arguments(msg);
1815
1816         err = connman_device_request_device_scan(technology->type, ifname, true);
1817         if (err < 0)
1818                 return __connman_error_failed(msg, -err);
1819
1820         struct connman_scan_pending *pending_data =
1821                         g_try_malloc0(sizeof(struct connman_scan_pending));
1822         if (!pending_data)
1823                 return __connman_error_failed(msg, ENOMEM);
1824
1825         pending_data->ifname =  g_strdup(ifname);
1826         if (pending_data->ifname == NULL) {
1827                 g_free(pending_data);
1828                 return __connman_error_failed(msg, ENOMEM);
1829         }
1830
1831         pending_data->scan_type = CONNMAN_SCAN_TYPE_FULL_CHANNEL;
1832         DBG("scan_type %d", pending_data->scan_type);
1833
1834         pending_data->msg = dbus_message_ref(msg);
1835
1836         technology->scan_pending =
1837                 g_slist_prepend(technology->scan_pending, pending_data);
1838
1839         return NULL;
1840 }
1841
1842 static DBusMessage *specific_scan(DBusConnection *conn, DBusMessage *msg, void *data)
1843 {
1844         struct connman_technology *technology = data;
1845         GSList *specific_scan_list = NULL;
1846         int scan_type = 0;
1847         const char *name = NULL;
1848         const char *freq = NULL;
1849         const char *ifname = NULL;
1850         DBusMessageIter iter, dict;
1851         int err;
1852
1853         DBG("technology %p request from %s", technology,
1854                         dbus_message_get_sender(msg));
1855
1856         if (!dbus_message_iter_init(msg, &iter))
1857                 return __connman_error_invalid_arguments(msg);
1858
1859         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1860                 return __connman_error_invalid_arguments(msg);
1861
1862         dbus_message_iter_recurse(&iter, &dict);
1863         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1864                 DBusMessageIter entry, value2;
1865                 const char *key;
1866                 int type;
1867
1868                 dbus_message_iter_recurse(&dict, &entry);
1869                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) {
1870                         g_slist_free_full(specific_scan_list, g_free);
1871                         return __connman_error_invalid_arguments(msg);
1872                 }
1873
1874                 dbus_message_iter_get_basic(&entry, &key);
1875                 dbus_message_iter_next(&entry);
1876
1877                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) {
1878                         g_slist_free_full(specific_scan_list, g_free);
1879                         return __connman_error_invalid_arguments(msg);
1880                 }
1881
1882                 dbus_message_iter_recurse(&entry, &value2);
1883                 type = dbus_message_iter_get_arg_type(&value2);
1884                 if (g_str_equal(key, "Ifname") && type == DBUS_TYPE_STRING) {
1885
1886                         dbus_message_iter_get_basic(&value2, &ifname);
1887                         DBG("ifname %s", ifname);
1888                 } else if (g_str_equal(key, "SSID")) {
1889                         if (type != DBUS_TYPE_STRING) {
1890                                 g_slist_free_full(specific_scan_list, g_free);
1891                                 return __connman_error_invalid_arguments(msg);
1892                         }
1893
1894                         scan_type = CONNMAN_MULTI_SCAN_SSID; /* SSID based scan */
1895                         dbus_message_iter_get_basic(&value2, &name);
1896                         DBG("name %s", name);
1897                         specific_scan_list = g_slist_append(specific_scan_list, g_strdup(name));
1898                 } else if (g_str_equal(key, "Frequency")) {
1899                         if (type != DBUS_TYPE_STRING) {
1900                                 g_slist_free_full(specific_scan_list, g_free);
1901                                 return __connman_error_invalid_arguments(msg);
1902                         }
1903
1904                         scan_type = CONNMAN_MULTI_SCAN_FREQ; /* Frequency based scan */
1905                         dbus_message_iter_get_basic(&value2, &freq);
1906                         DBG("freq %s", freq);
1907                         specific_scan_list = g_slist_append(specific_scan_list, GINT_TO_POINTER(atoi(freq)));
1908                 } else if (g_str_equal(key, "SSID_Mixed")) {
1909                         if (type != DBUS_TYPE_STRING) {
1910                                 g_slist_free_full(specific_scan_list, g_free);
1911                                 return __connman_error_invalid_arguments(msg);
1912                         }
1913
1914                         scan_type = CONNMAN_MULTI_SCAN_SSID_FREQ; /* SSID & Frequency mixed scan */
1915                         dbus_message_iter_get_basic(&value2, &name);
1916
1917                         connman_multi_scan_ap_s *ap =
1918                                         (connman_multi_scan_ap_s*)g_try_malloc0(sizeof(connman_multi_scan_ap_s));
1919                         if (ap) {
1920                                 g_strlcpy(ap->str, name, strlen(name) + 1);
1921                                 ap->flag = true;
1922                                 specific_scan_list = g_slist_append(specific_scan_list, ap);
1923                         } else
1924                                 DBG("Failed to allocate memory");
1925
1926                 } else if (g_str_equal(key, "Frequency_Mixed")) {
1927                         if (type != DBUS_TYPE_STRING) {
1928                                 g_slist_free_full(specific_scan_list, g_free);
1929                                 return __connman_error_invalid_arguments(msg);
1930                         }
1931
1932                         scan_type = CONNMAN_MULTI_SCAN_SSID_FREQ; /* SSID & Frequency mixed scan */
1933                         dbus_message_iter_get_basic(&value2, &freq);
1934
1935                         connman_multi_scan_ap_s *ap =
1936                                         (connman_multi_scan_ap_s*)g_try_malloc0(sizeof(connman_multi_scan_ap_s));
1937                         if (ap) {
1938                                 g_strlcpy(ap->str, freq, strlen(freq) + 1);
1939                                 ap->flag = false;
1940                                 specific_scan_list = g_slist_append(specific_scan_list, ap);
1941                         } else
1942                                 DBG("Failed to allocate memory");
1943                 }
1944                 dbus_message_iter_next(&dict);
1945         }
1946
1947         err = __connman_device_request_specific_scan(technology->type, ifname, scan_type, specific_scan_list);
1948         if (err < 0)
1949                 return __connman_error_failed(msg, -err);
1950
1951         guint list_size = g_slist_length(specific_scan_list);
1952
1953         if (scan_type == CONNMAN_MULTI_SCAN_SSID ||
1954                         scan_type == CONNMAN_MULTI_SCAN_SSID_FREQ)
1955                 g_slist_free_full(specific_scan_list, g_free);
1956
1957         struct connman_scan_pending *pending_data =
1958                         g_try_malloc0(sizeof(struct connman_scan_pending));
1959         if (!pending_data)
1960                 return __connman_error_failed(msg, ENOMEM);
1961
1962         if (ifname) {
1963                 pending_data->ifname =  g_strdup(ifname);
1964                 if (pending_data->ifname == NULL) {
1965                         g_free(pending_data);
1966                         return __connman_error_failed(msg, ENOMEM);
1967                 }
1968         }
1969
1970         if (list_size == 1)
1971                 pending_data->scan_type = CONNMAN_SCAN_TYPE_SPECIFIC_AP;
1972         else
1973                 pending_data->scan_type = CONNMAN_SCAN_TYPE_MULTI_AP;
1974         DBG("list_size %u scan_type %d", list_size, pending_data->scan_type);
1975
1976         pending_data->msg = dbus_message_ref(msg);
1977
1978         technology->scan_pending =
1979                 g_slist_prepend(technology->scan_pending, pending_data);
1980
1981         return NULL;
1982 }
1983
1984 static DBusMessage *get_5ghz_supported(DBusConnection *conn, DBusMessage *msg, void *data)
1985 {
1986         DBusMessage *reply;
1987         DBusMessageIter iter, dict;
1988         GSList *list;
1989         struct connman_technology *technology = data;
1990         dbus_bool_t supported = false;
1991         const char *ifname = NULL;
1992
1993         DBG("technology %p", technology);
1994
1995         reply = dbus_message_new_method_return(msg);
1996         if (!reply)
1997                 return NULL;
1998
1999         dbus_message_iter_init_append(reply, &iter);
2000         connman_dbus_dict_open(&iter, &dict);
2001
2002         for (list = technology->device_list; list; list = list->next) {
2003                 struct connman_device *device = list->data;
2004
2005                 supported = connman_device_get_wifi_5ghz_supported(device);
2006                 ifname = connman_device_get_string(device, "Interface");
2007
2008                 DBG("ifname %s supported : %d", ifname, supported);
2009                 connman_dbus_dict_append_basic(&dict, ifname,
2010                                                 DBUS_TYPE_BOOLEAN,
2011                                                 &supported);
2012         }
2013
2014         connman_dbus_dict_close(&iter, &dict);
2015
2016         return reply;
2017 }
2018
2019 static DBusMessage *get_scan_state(DBusConnection *conn, DBusMessage *msg, void *data)
2020 {
2021         DBusMessage *reply;
2022         DBusMessageIter iter, dict;
2023         GSList *list;
2024         struct connman_technology *technology = data;
2025         dbus_bool_t scanning = false;
2026         const char *ifname = NULL;
2027
2028         DBG("technology %p", technology);
2029
2030         reply = dbus_message_new_method_return(msg);
2031         if (!reply)
2032                 return NULL;
2033
2034         dbus_message_iter_init_append(reply, &iter);
2035         connman_dbus_dict_open(&iter, &dict);
2036
2037         for (list = technology->device_list; list; list = list->next) {
2038                 struct connman_device *device = list->data;
2039
2040                 scanning = connman_device_get_scanning(device, technology->type);
2041                 ifname = connman_device_get_string(device, "Interface");
2042
2043                 DBG("ifname %s scanning : %d", ifname, scanning);
2044                 connman_dbus_dict_append_basic(&dict, ifname,
2045                                                 DBUS_TYPE_BOOLEAN,
2046                                                 &scanning);
2047         }
2048
2049         connman_dbus_dict_close(&iter, &dict);
2050
2051         return reply;
2052 }
2053
2054 static DBusMessage *get_max_scan_ssid(DBusConnection *conn, DBusMessage *msg, void *data)
2055 {
2056         DBusMessage *reply;
2057         DBusMessageIter iter, dict;
2058         GSList *list;
2059         struct connman_technology *technology = data;
2060         dbus_int32_t max_scan_ssids = 0;
2061         const char *ifname = NULL;
2062
2063         DBG("technology %p", technology);
2064
2065         reply = dbus_message_new_method_return(msg);
2066         if (!reply)
2067                 return NULL;
2068
2069         dbus_message_iter_init_append(reply, &iter);
2070         connman_dbus_dict_open(&iter, &dict);
2071
2072         for (list = technology->device_list; list; list = list->next) {
2073                 struct connman_device *device = list->data;
2074
2075                 max_scan_ssids = connman_device_get_max_scan_ssids(device);
2076                 ifname = connman_device_get_string(device, "Interface");
2077
2078                 DBG("ifname %s max_scan_ssids : %d", ifname, max_scan_ssids);
2079                 connman_dbus_dict_append_basic(&dict, ifname,
2080                                 DBUS_TYPE_INT32,
2081                                 &max_scan_ssids);
2082         }
2083
2084         connman_dbus_dict_close(&iter, &dict);
2085
2086         return reply;
2087 }
2088
2089 static int technology_enable_device(struct connman_technology *technology,
2090                                 bool enable_device, const char *ifname, struct connman_device **device_out)
2091 {
2092         int err = 0;
2093         GSList *list;
2094
2095         for (list = technology->device_list; list; list = list->next) {
2096                 struct connman_device *device = list->data;
2097                 const char *str = connman_device_get_string(device, "Interface");
2098
2099                 if (g_strcmp0(str, ifname) != 0)
2100                         continue;
2101
2102                 if (enable_device)
2103                         err = __connman_device_enable(device);
2104                 else
2105                         err = __connman_device_disable(device);
2106
2107                 *device_out = device;
2108                 return err;
2109         }
2110
2111         return -ENXIO;
2112 }
2113
2114 static DBusMessage *technology_set_device_powered(struct connman_technology *technology,
2115                                 DBusMessage *msg, bool powered, const char *ifname)
2116 {
2117         DBusMessage *reply = NULL;
2118         struct connman_device *device = NULL;
2119         int err = 0;
2120
2121         err = technology_enable_device(technology, powered, ifname, &device);
2122
2123         if (err == -EINPROGRESS) {
2124                 if (device)
2125                         connman_device_set_pending_reply(device, msg);
2126                 return reply;
2127         } else if (err == -EALREADY) {
2128                 if (powered)
2129                         reply = __connman_error_already_enabled(msg);
2130                 else
2131                         reply = __connman_error_already_disabled(msg);
2132         } else if (err < 0)
2133                 reply = __connman_error_failed(msg, -err);
2134         else
2135                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2136
2137         return reply;
2138 }
2139
2140 static DBusMessage *set_device_power(DBusConnection *conn,
2141                                         DBusMessage *msg, void *data)
2142 {
2143         struct connman_technology *technology = data;
2144         DBusMessageIter iter;
2145         const char *name;
2146         int len;
2147         dbus_bool_t enable;
2148
2149         DBG("conn %p", conn);
2150
2151         if (!dbus_message_iter_init(msg, &iter))
2152                 return __connman_error_invalid_arguments(msg);
2153
2154         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
2155                 return __connman_error_invalid_arguments(msg);
2156
2157         dbus_message_iter_get_basic(&iter, &name);
2158         dbus_message_iter_next(&iter);
2159
2160         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
2161                 return __connman_error_invalid_arguments(msg);
2162
2163         DBG("interface name %s", name);
2164
2165         len = strlen(name);
2166
2167         if (len + 1 > IFNAMSIZ)
2168                 return __connman_error_invalid_arguments(msg);
2169
2170         dbus_message_iter_get_basic(&iter, &enable);
2171         DBG("powered %s", enable ? "TRUE" : "FALSE");
2172
2173         return technology_set_device_powered(technology, msg, enable, name);
2174 }
2175
2176 static DBusMessage *set_bssid(DBusConnection *conn,
2177                                         DBusMessage *msg, void *data)
2178 {
2179         DBusMessageIter iter;
2180         char *name, *bssid;
2181         int len;
2182
2183         DBG("conn %p", conn);
2184
2185         if (!dbus_message_iter_init(msg, &iter))
2186                 return __connman_error_invalid_arguments(msg);
2187
2188         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
2189                 return __connman_error_invalid_arguments(msg);
2190
2191         dbus_message_iter_get_basic(&iter, &name);
2192         dbus_message_iter_next(&iter);
2193
2194         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
2195                 return __connman_error_invalid_arguments(msg);
2196
2197         dbus_message_iter_get_basic(&iter, &bssid);
2198
2199         DBG("interface name %s bssid %s", name, bssid);
2200
2201         len = strlen(name);
2202
2203         if (len + 1 > IFNAMSIZ)
2204                 return __connman_error_invalid_arguments(msg);
2205
2206         set_connman_bssid(SET_BSSID, bssid, name);
2207
2208         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2209 }
2210 static struct connman_technology *technology_get(enum connman_service_type type);
2211
2212 void technology_save_device(struct connman_device *device)
2213 {
2214         struct connman_technology *technology;
2215         enum connman_service_type type;
2216
2217         type = __connman_device_get_service_type(device);
2218
2219         if (type != CONNMAN_SERVICE_TYPE_WIFI)
2220                 return;
2221
2222         technology = technology_get(type);
2223         if (!technology)
2224                 return;
2225
2226         GKeyFile *keyfile;
2227         gchar *identifier;
2228         const char *name = get_name(technology->type);
2229
2230         DBG("technology %p type %d name %s", technology, technology->type,
2231                                                                         name);
2232         if (!name)
2233                 return;
2234
2235         keyfile = __connman_storage_load_global();
2236         if (!keyfile)
2237                 keyfile = g_key_file_new();
2238
2239         identifier = g_strdup_printf("%s", name);
2240         if (!identifier)
2241                 goto done;
2242
2243         GSList *list = NULL;
2244         gchar **ifname_list = NULL;
2245         guint dev_count = g_slist_length(technology->device_list);
2246
2247         if (dev_count >= 1) {
2248                 GString *ifname_str = g_string_new(NULL);
2249
2250                 if (ifname_str) {
2251                         for (list = technology->device_list; list; list = list->next) {
2252                                 struct connman_device *device = list->data;
2253
2254                                 if (connman_device_get_powered(device)) {
2255                                         const char *ifname = connman_device_get_string(device, "Interface");
2256
2257                                         if (ifname_str->len > 0)
2258                                                 g_string_append_printf(ifname_str, " %s", ifname);
2259                                         else
2260                                                 g_string_append(ifname_str, ifname);
2261                                 }
2262                         }
2263
2264                         if (ifname_str->len > 0) {
2265                                 ifname_list = g_strsplit_set(ifname_str->str, " ", 0);
2266                                 dev_count = g_strv_length(ifname_list);
2267                                 g_key_file_set_string_list(keyfile, identifier, "Enable.Devices",
2268                                                                 (const gchar **) ifname_list, dev_count);
2269
2270                                 technology->enable_persistent = true;
2271                         } else {
2272                                 g_key_file_remove_key(keyfile, identifier, "Enable.Devices", NULL);
2273                                 technology->enable_persistent = false;
2274                         }
2275
2276                         g_strfreev(ifname_list);
2277                         g_string_free(ifname_str, TRUE);
2278                 }
2279         }
2280
2281         g_key_file_set_boolean(keyfile, identifier, "Enable",
2282                                 technology->enable_persistent);
2283
2284         g_key_file_set_boolean(keyfile, identifier, "Tethering",
2285                                 technology->tethering_persistent);
2286
2287         if (technology->tethering_ident)
2288                 g_key_file_set_string(keyfile, identifier,
2289                                         "Tethering.Identifier",
2290                                         technology->tethering_ident);
2291
2292         if (technology->tethering_passphrase)
2293                 g_key_file_set_string(keyfile, identifier,
2294                                         "Tethering.Passphrase",
2295                                         technology->tethering_passphrase);
2296
2297 done:
2298         g_free(identifier);
2299
2300         __connman_storage_save_global(keyfile);
2301
2302         g_key_file_free(keyfile);
2303 }
2304 #endif
2305
2306 #if defined TIZEN_EXT_WIFI_MESH
2307 bool __connman_technology_get_connected(enum connman_service_type type)
2308 {
2309         struct connman_technology *technology;
2310
2311         technology = technology_find(type);
2312
2313         if (!technology)
2314                 return false;
2315
2316         return technology->connected;
2317 }
2318
2319 void __connman_technology_mesh_interface_create_finished(
2320                                                         enum connman_service_type type, bool success,
2321                                                         const char *error)
2322 {
2323         DBusMessage *reply;
2324         struct connman_technology *technology;
2325         DBusMessage *msg;
2326         technology = technology_find(type);
2327
2328         DBG("technology %p success %d", technology, success);
2329
2330         if (!technology)
2331                 return;
2332
2333         msg = technology->mesh_dbus_msg;
2334         if (!msg) {
2335                 DBG("No pending dbus message");
2336                 return;
2337         }
2338
2339         if (success) {
2340                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2341                 __connman_device_request_scan(technology->type);
2342         } else
2343                 reply = g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE
2344                                 ".MeshInterfaceAddFailed", "%s", error);
2345         g_dbus_send_message(connection, reply);
2346         dbus_message_unref(msg);
2347         technology->mesh_dbus_msg = NULL;
2348 }
2349
2350 void __connman_technology_mesh_interface_remove_finished(
2351                                                         enum connman_service_type type, bool success)
2352 {
2353         DBusMessage *reply;
2354         struct connman_technology *technology;
2355         DBusMessage *msg;
2356         technology = technology_find(type);
2357
2358         DBG("technology %p success %d", technology, success);
2359
2360         if (!technology || !technology->mesh_dbus_msg)
2361                 return;
2362
2363         msg = technology->mesh_dbus_msg;
2364         if (!msg) {
2365                 DBG("No pending dbus message");
2366                 return;
2367         }
2368
2369         if (success)
2370                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2371         else
2372                 reply = __connman_error_failed(msg, EINVAL);
2373         g_dbus_send_message(connection, reply);
2374         dbus_message_unref(msg);
2375         technology->mesh_dbus_msg = NULL;
2376 }
2377
2378 void __connman_technology_notify_abort_scan(enum connman_service_type type,
2379                                                         int result)
2380 {
2381         DBusMessage *reply;
2382         struct connman_technology *technology;
2383         DBusMessage *msg;
2384         technology = technology_find(type);
2385
2386         DBG("technology %p result %d", technology, result);
2387
2388         if (!technology || !technology->mesh_dbus_msg)
2389                 return;
2390
2391         msg = technology->mesh_dbus_msg;
2392         if (!msg) {
2393                 DBG("No pending dbus message");
2394                 return;
2395         }
2396
2397         if (result < 0)
2398                 reply = __connman_error_scan_abort_failed(msg);
2399         else
2400                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2401
2402         g_dbus_send_message(connection, reply);
2403         dbus_message_unref(msg);
2404         technology->mesh_dbus_msg = NULL;
2405 }
2406
2407 static DBusMessage *mesh_commands(DBusConnection *conn,
2408                                   DBusMessage *msg, void *data)
2409 {
2410         struct connman_technology *technology = data;
2411         DBusMessageIter iter, value, dict;
2412         const char *cmd = NULL, *ifname = NULL, *parent_ifname = NULL;
2413         int err;
2414
2415         DBG("conn %p", conn);
2416
2417         if (technology->type != CONNMAN_SERVICE_TYPE_MESH)
2418                 return __connman_error_invalid_arguments(msg);
2419
2420         if (!dbus_message_iter_init(msg, &iter))
2421                 return __connman_error_invalid_arguments(msg);
2422
2423         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
2424                 return __connman_error_invalid_arguments(msg);
2425
2426         dbus_message_iter_get_basic(&iter, &cmd);
2427         dbus_message_iter_next(&iter);
2428
2429         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
2430                 return __connman_error_invalid_arguments(msg);
2431
2432         dbus_message_iter_recurse(&iter, &value);
2433
2434         if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_ARRAY)
2435                 return __connman_error_invalid_arguments(msg);
2436
2437         DBG("Mesh Command %s", cmd);
2438         if (g_str_equal(cmd, "MeshInterfaceAdd")) {
2439                 dbus_message_iter_recurse(&value, &dict);
2440                 const char *bridge_ifname = NULL;
2441                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2442                         DBusMessageIter entry, value2;
2443                         const char *key;
2444                         int type;
2445
2446                         dbus_message_iter_recurse(&dict, &entry);
2447
2448                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2449                                 return __connman_error_invalid_arguments(msg);
2450
2451                         dbus_message_iter_get_basic(&entry, &key);
2452                         dbus_message_iter_next(&entry);
2453
2454                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
2455                                 return __connman_error_invalid_arguments(msg);
2456
2457                         dbus_message_iter_recurse(&entry, &value2);
2458
2459                         type = dbus_message_iter_get_arg_type(&value2);
2460
2461                         if (g_str_equal(key, "Ifname")) {
2462                                 if (type != DBUS_TYPE_STRING)
2463                                         return __connman_error_invalid_arguments(msg);
2464
2465                                 dbus_message_iter_get_basic(&value2, &ifname);
2466                         } else if (g_str_equal(key, "ParentIfname")) {
2467                                 if (type != DBUS_TYPE_STRING)
2468                                         return __connman_error_invalid_arguments(msg);
2469
2470                                 dbus_message_iter_get_basic(&value2, &parent_ifname);
2471                         } else if (g_str_equal(key, "BridgeIfname")) {
2472                                 if (type != DBUS_TYPE_STRING)
2473                                         return __connman_error_invalid_arguments(msg);
2474
2475                                 dbus_message_iter_get_basic(&value2, &bridge_ifname);
2476                         }
2477                         dbus_message_iter_next(&dict);
2478                 }
2479                 DBG("Mesh Ifname %s parent %s bridge %s", ifname, parent_ifname,
2480                                         bridge_ifname ? bridge_ifname : "NULL");
2481                 err = __connman_mesh_add_virtual_interface(ifname, parent_ifname,
2482                                                            bridge_ifname);
2483
2484                 if (err != 0) {
2485                         DBG("Failed to add virtual mesh interface");
2486                         return __connman_error_failed(msg, -err);
2487                 }
2488
2489                 DBG("Successfully added virtual mesh interface");
2490
2491                 dbus_message_ref(msg);
2492                 technology->mesh_dbus_msg = msg;
2493
2494         } else if (g_str_equal(cmd, "MeshInterfaceRemove")) {
2495                 dbus_message_iter_recurse(&value, &dict);
2496                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2497                         DBusMessageIter entry, value2;
2498                         const char *key;
2499                         int type;
2500
2501                         dbus_message_iter_recurse(&dict, &entry);
2502
2503                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2504                                 return __connman_error_invalid_arguments(msg);
2505
2506                         dbus_message_iter_get_basic(&entry, &key);
2507                         dbus_message_iter_next(&entry);
2508
2509                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
2510                                 return __connman_error_invalid_arguments(msg);
2511
2512                         dbus_message_iter_recurse(&entry, &value2);
2513
2514                         type = dbus_message_iter_get_arg_type(&value2);
2515
2516                         if (g_str_equal(key, "Ifname")) {
2517                                 if (type != DBUS_TYPE_STRING)
2518                                         return __connman_error_invalid_arguments(msg);
2519
2520                                 dbus_message_iter_get_basic(&value2, &ifname);
2521                         }
2522                         dbus_message_iter_next(&dict);
2523                 }
2524                 DBG("Mesh Ifname %s", ifname);
2525                 err = __connman_mesh_remove_virtual_interface(ifname);
2526
2527                 if (err != 0) {
2528                         DBG("Failed to remove virtual mesh interface");
2529                         return __connman_error_failed(msg, -err);
2530                 }
2531
2532                 DBG("Successfully removed virtual mesh interface");
2533
2534                 dbus_message_ref(msg);
2535                 technology->mesh_dbus_msg = msg;
2536
2537         } else if (g_str_equal(cmd, "MeshCreateNetwork")) {
2538                 struct connman_mesh *connman_mesh;
2539                 const char *name = NULL;
2540                 const char *sec_type = NULL;
2541                 const char *mesh_ifname = NULL;
2542                 char *identifier, *group, *address;
2543                 unsigned int freq = 0;
2544                 unsigned int ieee80211w = 0;
2545                 GString *str;
2546                 int i;
2547                 dbus_message_iter_recurse(&value, &dict);
2548                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2549                         DBusMessageIter entry, value2;
2550                         const char *key;
2551                         int type;
2552
2553                         dbus_message_iter_recurse(&dict, &entry);
2554
2555                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2556                                 return __connman_error_invalid_arguments(msg);
2557
2558                         dbus_message_iter_get_basic(&entry, &key);
2559                         dbus_message_iter_next(&entry);
2560
2561                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
2562                                 return __connman_error_invalid_arguments(msg);
2563
2564                         dbus_message_iter_recurse(&entry, &value2);
2565
2566                         type = dbus_message_iter_get_arg_type(&value2);
2567
2568                         if (g_str_equal(key, "Name")) {
2569                                 if (type != DBUS_TYPE_STRING)
2570                                         return __connman_error_invalid_arguments(msg);
2571
2572                                 dbus_message_iter_get_basic(&value2, &name);
2573                         } else if (g_str_equal(key, "Frequency")) {
2574                                 if (type != DBUS_TYPE_UINT16)
2575                                         return __connman_error_invalid_arguments(msg);
2576
2577                                 dbus_message_iter_get_basic(&value2, &freq);
2578                         } else if (g_str_equal(key, "Security")) {
2579                                 if (type != DBUS_TYPE_STRING)
2580                                         return __connman_error_invalid_arguments(msg);
2581
2582                                 dbus_message_iter_get_basic(&value2, &sec_type);
2583                         } else if (g_str_equal(key, "Pmf")) {
2584                                 if (type != DBUS_TYPE_UINT16)
2585                                         return __connman_error_invalid_arguments(msg);
2586
2587                                 dbus_message_iter_get_basic(&value2, &ieee80211w);
2588                         }
2589                         dbus_message_iter_next(&dict);
2590                 }
2591
2592                 if (name == NULL || sec_type == NULL || freq == 0)
2593                         return __connman_error_invalid_arguments(msg);
2594
2595                 DBG("Name %s Frequency %d Security type %s Pmf %u",
2596                     name, freq, sec_type, ieee80211w);
2597
2598                 if (g_strcmp0(sec_type, "none") != 0 &&
2599                     g_strcmp0(sec_type, "sae") != 0) {
2600                         DBG("Unsupported security");
2601                         return __connman_error_invalid_arguments(msg);
2602                 }
2603
2604                 mesh_ifname = connman_mesh_get_interface_name();
2605
2606                 if (!connman_mesh_is_interface_created()) {
2607                         DBG("Mesh interface doesn't exists");
2608                         return __connman_error_invalid_command(msg);
2609                 }
2610
2611                 str = g_string_sized_new((strlen(name) * 2) + 24);
2612
2613                 for (i = 0; name[i]; i++)
2614                         g_string_append_printf(str, "%02x", name[i]);
2615
2616                 g_string_append_printf(str, "_mesh");
2617
2618                 if (g_strcmp0(sec_type, "none") == 0)
2619                         g_string_append_printf(str, "_none");
2620                 else if (g_strcmp0(sec_type, "sae") == 0)
2621                         g_string_append_printf(str, "_sae");
2622
2623                 group = g_string_free(str, FALSE);
2624
2625                 identifier = connman_inet_ifaddr(mesh_ifname);
2626                 address = connman_inet_ifname2addr(mesh_ifname);
2627
2628                 connman_mesh = connman_mesh_create(identifier, group);
2629                 connman_mesh_set_name(connman_mesh, name);
2630                 connman_mesh_set_address(connman_mesh, address);
2631                 connman_mesh_set_security(connman_mesh, sec_type);
2632                 connman_mesh_set_frequency(connman_mesh, freq);
2633                 connman_mesh_set_index(connman_mesh, connman_inet_ifindex(mesh_ifname));
2634                 connman_mesh_set_peer_type(connman_mesh,
2635                                            CONNMAN_MESH_PEER_TYPE_CREATED);
2636                 connman_mesh_set_ieee80211w(connman_mesh, ieee80211w);
2637
2638                 connman_mesh_register(connman_mesh);
2639                 g_free(group);
2640                 g_free(identifier);
2641                 g_free(address);
2642                 DBG("Successfully Created Mesh Network");
2643                 return  g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2644
2645         } else if (g_str_equal(cmd, "AbortScan")) {
2646                 DBG("Abort Scan method");
2647                 err = __connman_device_abort_scan(technology->type);
2648                 if (err != 0) {
2649                         DBG("Failed to abort scan");
2650                         return __connman_error_failed(msg, -err);
2651                 }
2652
2653                 DBG("Successfully requested to abort scan");
2654                 dbus_message_ref(msg);
2655                 technology->mesh_dbus_msg = msg;
2656
2657         } else if (g_str_equal(cmd, "MeshSpecificScan")) {
2658                 const char *name = NULL;
2659                 unsigned int freq = 0;
2660                 dbus_message_iter_recurse(&value, &dict);
2661                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2662                         DBusMessageIter entry, value2;
2663                         const char *key;
2664                         int type;
2665
2666                         dbus_message_iter_recurse(&dict, &entry);
2667
2668                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2669                                 return __connman_error_invalid_arguments(msg);
2670
2671                         dbus_message_iter_get_basic(&entry, &key);
2672                         dbus_message_iter_next(&entry);
2673
2674                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
2675                                 return __connman_error_invalid_arguments(msg);
2676
2677                         dbus_message_iter_recurse(&entry, &value2);
2678
2679                         type = dbus_message_iter_get_arg_type(&value2);
2680
2681                         if (g_str_equal(key, "Name")) {
2682                                 if (type != DBUS_TYPE_STRING)
2683                                         return __connman_error_invalid_arguments(msg);
2684
2685                                 dbus_message_iter_get_basic(&value2, &name);
2686                         } else if (g_str_equal(key, "Frequency")) {
2687                                 if (type != DBUS_TYPE_UINT16)
2688                                         return __connman_error_invalid_arguments(msg);
2689
2690                                 dbus_message_iter_get_basic(&value2, &freq);
2691                         }
2692                         dbus_message_iter_next(&dict);
2693                 }
2694
2695                 DBG("MeshID %s Frequency %d sender %s", name, freq,
2696                                                 dbus_message_get_sender(msg));
2697
2698                 struct connman_scan_pending *pending_data =
2699                                 g_try_malloc0(sizeof(struct connman_scan_pending));
2700                 if (!pending_data)
2701                         return __connman_error_failed(msg, ENOMEM);
2702
2703                 pending_data->msg = dbus_message_ref(msg);
2704
2705                 technology->scan_pending =
2706                         g_slist_prepend(technology->scan_pending, pending_data);
2707
2708                 err = __connman_device_request_mesh_specific_scan(technology->type,
2709                                                                   name, freq);
2710                 if (err < 0)
2711                         reply_scan_pending(technology, err);
2712                 else
2713                         DBG("Successfully requested to scan specific Mesh Network");
2714
2715         } else if (g_str_equal(cmd, "SetMeshGate")) {
2716                 unsigned int hwmp_rootmode = 0;
2717                 bool gate_announce = false;
2718                 unsigned int stp = 0;
2719                 int err;
2720                 dbus_message_iter_recurse(&value, &dict);
2721                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2722                         DBusMessageIter entry, value2;
2723                         const char *key;
2724                         int type;
2725
2726                         dbus_message_iter_recurse(&dict, &entry);
2727
2728                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2729                                 return __connman_error_invalid_arguments(msg);
2730
2731                         dbus_message_iter_get_basic(&entry, &key);
2732                         dbus_message_iter_next(&entry);
2733
2734                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
2735                                 return __connman_error_invalid_arguments(msg);
2736
2737                         dbus_message_iter_recurse(&entry, &value2);
2738
2739                         type = dbus_message_iter_get_arg_type(&value2);
2740
2741                         if (g_str_equal(key, "GateAnnounce")) {
2742                                 if (type != DBUS_TYPE_BOOLEAN)
2743                                         return __connman_error_invalid_arguments(msg);
2744
2745                                 dbus_message_iter_get_basic(&value2, &gate_announce);
2746                         } else if (g_str_equal(key, "HWMPRootMode")) {
2747                                 if (type != DBUS_TYPE_UINT16)
2748                                         return __connman_error_invalid_arguments(msg);
2749
2750                                 dbus_message_iter_get_basic(&value2, &hwmp_rootmode);
2751                         } else if (g_str_equal(key, "STP")) {
2752                                 if (type != DBUS_TYPE_UINT16)
2753                                         return __connman_error_invalid_arguments(msg);
2754
2755                                 dbus_message_iter_get_basic(&value2, &stp);
2756                         }
2757                         dbus_message_iter_next(&dict);
2758                 }
2759
2760                 DBG("GateAnnounce %d HWMPRootMode %d STP %d sender %s",
2761                     gate_announce, hwmp_rootmode, stp, dbus_message_get_sender(msg));
2762
2763                 err = __connman_mesh_set_stp_gate_announce(gate_announce,
2764                                                            hwmp_rootmode,
2765                                                            stp);
2766
2767                 if (err < 0)
2768                         return __connman_error_failed(msg, -err);
2769
2770                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2771         } else
2772                 return __connman_error_invalid_command(msg);
2773         return NULL;
2774 }
2775 #endif
2776
2777 static const GDBusMethodTable technology_methods[] = {
2778         { GDBUS_DEPRECATED_METHOD("GetProperties",
2779                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
2780                         get_properties) },
2781         { GDBUS_ASYNC_METHOD("SetProperty",
2782                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
2783                         NULL, set_property) },
2784         { GDBUS_ASYNC_METHOD("Scan", NULL, NULL, scan) },
2785 #if defined TIZEN_EXT
2786         { GDBUS_ASYNC_METHOD("ScanDevice", GDBUS_ARGS({ "interface_name", "s" }),
2787                         NULL, scan_device) },
2788         { GDBUS_ASYNC_METHOD("SpecificScan", GDBUS_ARGS({ "specificscan", "a{sv}" }),
2789                         NULL, specific_scan) },
2790         { GDBUS_METHOD("GetScanState", NULL, GDBUS_ARGS({ "scan_state", "a{sv}" }),
2791                         get_scan_state) },
2792         { GDBUS_METHOD("Get5GhzSupported", NULL, GDBUS_ARGS({ "supported", "a{sv}" }),
2793                         get_5ghz_supported) },
2794         { GDBUS_METHOD("GetMaxScanSsid", NULL, GDBUS_ARGS({ "maxscanssid", "a{sv}" }),
2795                         get_max_scan_ssid) },
2796         { GDBUS_ASYNC_METHOD("SetDevicePower",
2797                         GDBUS_ARGS({ "ifname", "s" }, { "value", "b" }),
2798                         NULL, set_device_power) },
2799         { GDBUS_ASYNC_METHOD("SetBSSID",
2800                         GDBUS_ARGS({ "ifname", "s" }, { "bssid", "s" }),
2801                         NULL, set_bssid) },
2802 #endif
2803 #if defined TIZEN_EXT_WIFI_MESH
2804         { GDBUS_ASYNC_METHOD("MeshCommands",
2805                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
2806                         NULL, mesh_commands) },
2807 #endif
2808         { },
2809 };
2810
2811 static const GDBusSignalTable technology_signals[] = {
2812         { GDBUS_SIGNAL("PropertyChanged",
2813                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
2814 #if defined TIZEN_EXT
2815         { GDBUS_SIGNAL("DeviceChanged",
2816                         GDBUS_ARGS({ "device_property", "a{sv}" })) },
2817         { GDBUS_SIGNAL("DeviceDetected",
2818                         GDBUS_ARGS({ "ifname", "s" }, { "detected", "b" })) },
2819 #endif
2820         { },
2821 };
2822
2823 static bool technology_dbus_register(struct connman_technology *technology)
2824 {
2825         if (technology->dbus_registered ||
2826                                 (technology->rfkill_driven &&
2827                                  technology->hardblocked))
2828                 return true;
2829
2830         if (!g_dbus_register_interface(connection, technology->path,
2831                                         CONNMAN_TECHNOLOGY_INTERFACE,
2832                                         technology_methods, technology_signals,
2833                                         NULL, technology, NULL)) {
2834                 connman_error("Failed to register %s", technology->path);
2835                 return false;
2836         }
2837
2838         technology_added_signal(technology);
2839         technology->dbus_registered = true;
2840
2841         return true;
2842 }
2843
2844 static void technology_dbus_unregister(struct connman_technology *technology)
2845 {
2846         if (!technology->dbus_registered)
2847                 return;
2848
2849         technology_removed_signal(technology);
2850         g_dbus_unregister_interface(connection, technology->path,
2851                 CONNMAN_TECHNOLOGY_INTERFACE);
2852
2853         technology->dbus_registered = false;
2854 }
2855
2856 static void technology_put(struct connman_technology *technology)
2857 {
2858         DBG("technology %p", technology);
2859
2860         if (__sync_sub_and_fetch(&technology->refcount, 1) > 0)
2861                 return;
2862
2863         reply_scan_pending(technology, -EINTR);
2864
2865         while (technology->driver_list) {
2866                 struct connman_technology_driver *driver;
2867
2868                 driver = technology->driver_list->data;
2869
2870                 if (driver->remove)
2871                         driver->remove(technology);
2872
2873                 technology->driver_list =
2874                         g_slist_delete_link(technology->driver_list,
2875                                         technology->driver_list);
2876         }
2877
2878         technology_list = g_slist_remove(technology_list, technology);
2879
2880         technology_dbus_unregister(technology);
2881
2882         g_slist_free(technology->device_list);
2883
2884     if (technology->pending_reply) {
2885         dbus_message_unref(technology->pending_reply);
2886         technology->pending_reply = NULL;
2887         g_source_remove(technology->pending_timeout);
2888         technology->pending_timeout = 0;
2889     }
2890 #ifdef TIZEN_EXT
2891     g_strfreev(technology->enabled_devices);
2892 #endif
2893         g_free(technology->path);
2894         g_free(technology->regdom);
2895         g_free(technology->tethering_ident);
2896         g_free(technology->tethering_passphrase);
2897         g_free(technology);
2898 }
2899
2900 static struct connman_technology *technology_get(enum connman_service_type type)
2901 {
2902         GSList *tech_drivers = NULL;
2903         struct connman_technology_driver *driver;
2904         struct connman_technology *technology;
2905         const char *str;
2906         GSList *list;
2907
2908         DBG("type %d", type);
2909
2910         str = __connman_service_type2string(type);
2911         if (!str)
2912                 return NULL;
2913
2914         technology = technology_find(type);
2915         if (technology) {
2916 #if defined TIZEN_EXT_WIFI_MESH
2917                 if (type != CONNMAN_SERVICE_TYPE_P2P &&
2918                         type != CONNMAN_SERVICE_TYPE_MESH)
2919 #else
2920                 if (type != CONNMAN_SERVICE_TYPE_P2P)
2921 #endif
2922                         __sync_fetch_and_add(&technology->refcount, 1);
2923                 return technology;
2924         }
2925
2926         /* First check if we have a driver for this technology type */
2927         for (list = driver_list; list; list = list->next) {
2928                 driver = list->data;
2929
2930                 if (driver->type == type) {
2931                         DBG("technology %p driver %p", technology, driver);
2932                         tech_drivers = g_slist_append(tech_drivers, driver);
2933                 }
2934         }
2935
2936         if (!tech_drivers) {
2937                 DBG("No matching drivers found for %s.",
2938                                 __connman_service_type2string(type));
2939                 return NULL;
2940         }
2941
2942         technology = g_try_new0(struct connman_technology, 1);
2943         if (!technology)
2944                 return NULL;
2945
2946         technology->refcount = 1;
2947         technology->type = type;
2948         technology->path = g_strdup_printf("%s/technology/%s",
2949                                                         CONNMAN_PATH, str);
2950
2951 #if defined TIZEN_EXT_WIFI_MESH
2952         if (type == CONNMAN_SERVICE_TYPE_MESH) {
2953                 struct connman_technology *wifi;
2954
2955                 wifi = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
2956                 if (wifi)
2957                         technology->enabled = wifi->enabled;
2958         }
2959 #endif
2960
2961         technology_load(technology);
2962         technology_list = g_slist_prepend(technology_list, technology);
2963         technology->driver_list = tech_drivers;
2964
2965         for (list = tech_drivers; list; list = list->next) {
2966                 driver = list->data;
2967
2968                 if (driver->probe && driver->probe(technology) < 0)
2969                         DBG("Driver probe failed for technology %p",
2970                                         technology);
2971         }
2972
2973         if (!technology_dbus_register(technology)) {
2974                 technology_put(technology);
2975                 return NULL;
2976         }
2977
2978         if (type == CONNMAN_SERVICE_TYPE_P2P) {
2979                 struct connman_technology *wifi;
2980                 bool enable;
2981
2982                 enable = technology->enable_persistent;
2983
2984                 wifi = technology_find(CONNMAN_SERVICE_TYPE_WIFI);
2985                 if (enable && wifi)
2986                         enable = wifi->enabled;
2987
2988                 technology_affect_devices(technology, enable);
2989         }
2990
2991         DBG("technology %p %s", technology, get_name(technology->type));
2992
2993         return technology;
2994 }
2995
2996 int connman_technology_driver_register(struct connman_technology_driver *driver)
2997 {
2998         GSList *list;
2999         struct connman_device *device;
3000         enum connman_service_type type;
3001
3002         for (list = driver_list; list; list = list->next) {
3003                 if (list->data == driver)
3004                         goto exist;
3005         }
3006
3007         DBG("Registering %s driver", driver->name);
3008
3009         driver_list = g_slist_insert_sorted(driver_list, driver,
3010                                                         compare_priority);
3011
3012         /*
3013          * Check for technology less devices if this driver
3014          * can service any of them.
3015         */
3016         for (list = techless_device_list; list; list = list->next) {
3017                 device = list->data;
3018
3019                 type = __connman_device_get_service_type(device);
3020                 if (type != driver->type)
3021                         continue;
3022
3023                 techless_device_list = g_slist_remove(techless_device_list,
3024                                                                 device);
3025
3026                 __connman_technology_add_device(device);
3027         }
3028
3029         /* Check for orphaned rfkill switches. */
3030         g_hash_table_foreach(rfkill_list, rfkill_check,
3031                                         GINT_TO_POINTER(driver->type));
3032
3033 exist:
3034         if (driver->type == CONNMAN_SERVICE_TYPE_P2P) {
3035                 if (!technology_get(CONNMAN_SERVICE_TYPE_P2P))
3036                         return -ENOMEM;
3037         }
3038
3039 #if defined TIZEN_EXT_WIFI_MESH
3040         if (driver->type == CONNMAN_SERVICE_TYPE_MESH) {
3041                 if (!technology_get(CONNMAN_SERVICE_TYPE_MESH))
3042                         return -ENOMEM;
3043         }
3044 #endif
3045
3046         return 0;
3047 }
3048
3049 void connman_technology_driver_unregister(struct connman_technology_driver *driver)
3050 {
3051         GSList *list, *tech_drivers;
3052         struct connman_technology *technology;
3053         struct connman_technology_driver *current;
3054
3055         DBG("Unregistering driver %p name %s", driver, driver->name);
3056
3057         for (list = technology_list; list; list = list->next) {
3058                 technology = list->data;
3059
3060                 for (tech_drivers = technology->driver_list; tech_drivers;
3061                                 tech_drivers = g_slist_next(tech_drivers)) {
3062                         current = tech_drivers->data;
3063                         if (driver != current)
3064                                 continue;
3065
3066                         if (driver->remove)
3067                                 driver->remove(technology);
3068
3069                         technology->driver_list =
3070                                 g_slist_remove(technology->driver_list,
3071                                                                 driver);
3072                         break;
3073                 }
3074         }
3075
3076         driver_list = g_slist_remove(driver_list, driver);
3077
3078         if (driver->type == CONNMAN_SERVICE_TYPE_P2P) {
3079                 technology = technology_find(CONNMAN_SERVICE_TYPE_P2P);
3080                 if (technology)
3081                         technology_put(technology);
3082         }
3083 #if defined TIZEN_EXT_WIFI_MESH
3084         if (driver->type == CONNMAN_SERVICE_TYPE_MESH) {
3085                 technology = technology_find(CONNMAN_SERVICE_TYPE_MESH);
3086                 if (technology)
3087                         technology_put(technology);
3088         }
3089 #endif
3090 }
3091
3092 void __connman_technology_add_interface(enum connman_service_type type,
3093                                 int index, const char *ident)
3094 {
3095         struct connman_technology *technology;
3096         GSList *tech_drivers;
3097         struct connman_technology_driver *driver;
3098         char *name;
3099
3100         switch (type) {
3101         case CONNMAN_SERVICE_TYPE_UNKNOWN:
3102         case CONNMAN_SERVICE_TYPE_SYSTEM:
3103                 return;
3104         case CONNMAN_SERVICE_TYPE_ETHERNET:
3105         case CONNMAN_SERVICE_TYPE_WIFI:
3106         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
3107         case CONNMAN_SERVICE_TYPE_CELLULAR:
3108         case CONNMAN_SERVICE_TYPE_GPS:
3109         case CONNMAN_SERVICE_TYPE_VPN:
3110         case CONNMAN_SERVICE_TYPE_GADGET:
3111         case CONNMAN_SERVICE_TYPE_P2P:
3112 #if defined TIZEN_EXT_WIFI_MESH
3113         case CONNMAN_SERVICE_TYPE_MESH:
3114 #endif
3115                 break;
3116         }
3117
3118         name = connman_inet_ifname(index);
3119         connman_info("Adding interface %s [ %s ]", name,
3120                                 __connman_service_type2string(type));
3121
3122         technology = technology_find(type);
3123
3124         if (!technology)
3125                 goto out;
3126
3127         for (tech_drivers = technology->driver_list; tech_drivers;
3128              tech_drivers = g_slist_next(tech_drivers)) {
3129                 driver = tech_drivers->data;
3130
3131                 if (driver->add_interface)
3132                         driver->add_interface(technology, index, name, ident);
3133         }
3134
3135         /*
3136          * At this point we can try to enable tethering automatically as
3137          * now the interfaces are set properly.
3138          */
3139         if (technology->tethering_persistent)
3140                 enable_tethering(technology);
3141
3142 out:
3143         g_free(name);
3144 }
3145
3146 void __connman_technology_remove_interface(enum connman_service_type type,
3147                                 int index, const char *ident)
3148 {
3149         struct connman_technology *technology;
3150         GSList *tech_drivers;
3151         struct connman_technology_driver *driver;
3152         char *name;
3153
3154         switch (type) {
3155         case CONNMAN_SERVICE_TYPE_UNKNOWN:
3156         case CONNMAN_SERVICE_TYPE_SYSTEM:
3157                 return;
3158         case CONNMAN_SERVICE_TYPE_ETHERNET:
3159         case CONNMAN_SERVICE_TYPE_WIFI:
3160         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
3161         case CONNMAN_SERVICE_TYPE_CELLULAR:
3162         case CONNMAN_SERVICE_TYPE_GPS:
3163         case CONNMAN_SERVICE_TYPE_VPN:
3164         case CONNMAN_SERVICE_TYPE_GADGET:
3165         case CONNMAN_SERVICE_TYPE_P2P:
3166 #if defined TIZEN_EXT_WIFI_MESH
3167         case CONNMAN_SERVICE_TYPE_MESH:
3168 #endif
3169                 break;
3170         }
3171
3172         name = connman_inet_ifname(index);
3173         connman_info("Remove interface %s [ %s ]", name,
3174                                 __connman_service_type2string(type));
3175         g_free(name);
3176
3177         technology = technology_find(type);
3178
3179         if (!technology)
3180                 return;
3181
3182         for (tech_drivers = technology->driver_list; tech_drivers;
3183              tech_drivers = g_slist_next(tech_drivers)) {
3184                 driver = tech_drivers->data;
3185
3186                 if (driver->remove_interface)
3187                         driver->remove_interface(technology, index);
3188         }
3189 }
3190
3191 int __connman_technology_add_device(struct connman_device *device)
3192 {
3193         struct connman_technology *technology;
3194         enum connman_service_type type;
3195
3196         type = __connman_device_get_service_type(device);
3197
3198         DBG("device %p type %s", device, get_name(type));
3199
3200         technology = technology_get(type);
3201         if (!technology) {
3202                 /*
3203                  * Since no driver can be found for this device at the moment we
3204                  * add it to the techless device list.
3205                 */
3206                 techless_device_list = g_slist_prepend(techless_device_list,
3207                                                                 device);
3208
3209                 return -ENXIO;
3210         }
3211
3212         __sync_synchronize();
3213         if (technology->rfkill_driven) {
3214                 if (technology->enabled)
3215                         __connman_device_enable(device);
3216                 else
3217                         __connman_device_disable(device);
3218
3219                 goto done;
3220         }
3221
3222         if (technology->enable_persistent &&
3223                                         !global_offlinemode) {
3224 #if defined TIZEN_EXT
3225                 bool found = true;
3226                 int err = 0;
3227                 if (technology->enabled_devices && type == CONNMAN_SERVICE_TYPE_WIFI) {
3228                         int i = 0;
3229                         found = false;
3230                         const char *ifname = connman_device_get_string(device, "Interface");
3231
3232                         while (technology->enabled_devices[i]) {
3233                                 if (g_strcmp0(technology->enabled_devices[i], ifname) == 0) {
3234                                         found = true;
3235                                         break;
3236                                 }
3237                                 i++;
3238                         }
3239                 }
3240
3241                 if (found)
3242                         err = __connman_device_enable(device);
3243 #else
3244                 int err = __connman_device_enable(device);
3245 #endif
3246                 /*
3247                  * connman_technology_add_device() calls __connman_device_enable()
3248                  * but since the device is already enabled, the call does not
3249                  * propagate through to connman_technology_enabled via
3250                  * connman_device_set_powered.
3251                  */
3252                 if (err == -EALREADY)
3253                         __connman_technology_enabled(type);
3254         }
3255         /* if technology persistent state is offline */
3256         if (!technology->enable_persistent)
3257                 __connman_device_disable(device);
3258
3259 done:
3260         technology->device_list = g_slist_prepend(technology->device_list,
3261                                                                 device);
3262
3263 #if defined TIZEN_EXT
3264         technology_save_device(device);
3265
3266         const char *ifname = connman_device_get_string(device, "Interface");
3267         __connman_technology_notify_device_detected(technology, ifname, true);
3268
3269         connman_device_set_mac_policy(device, technology->mac_policy);
3270         connman_device_set_preassoc_mac_policy(device, technology->preassoc_mac_policy);
3271         connman_device_set_random_mac_lifetime(device, technology->random_mac_lifetime);
3272 #endif
3273         return 0;
3274 }
3275
3276 int __connman_technology_remove_device(struct connman_device *device)
3277 {
3278         struct connman_technology *technology;
3279         enum connman_service_type type;
3280
3281         DBG("device %p", device);
3282
3283         type = __connman_device_get_service_type(device);
3284
3285         technology = technology_find(type);
3286         if (!technology) {
3287                 techless_device_list = g_slist_remove(techless_device_list,
3288                                                                 device);
3289                 return -ENXIO;
3290         }
3291
3292         technology->device_list = g_slist_remove(technology->device_list,
3293                                                                 device);
3294
3295 #if defined TIZEN_EXT
3296         technology_save_device(device);
3297
3298         const char *ifname = connman_device_get_string(device, "Interface");
3299         __connman_technology_notify_device_detected(technology, ifname, false);
3300 #endif
3301
3302         if (technology->tethering)
3303                 set_tethering(technology, false);
3304
3305         technology_put(technology);
3306
3307         return 0;
3308 }
3309
3310 int __connman_technology_enabled(enum connman_service_type type)
3311 {
3312         struct connman_technology *technology;
3313
3314         technology = technology_find(type);
3315         if (!technology)
3316                 return -ENXIO;
3317
3318         DBG("technology %p type %s rfkill %d enabled %d", technology,
3319                 get_name(type), technology->rfkill_driven,
3320                 technology->enabled);
3321
3322 #if !defined TIZEN_EXT
3323         if (technology->rfkill_driven) {
3324                 if (technology->tethering_persistent)
3325                         enable_tethering(technology);
3326                 return 0;
3327         }
3328 #endif
3329
3330         return technology_enabled(technology);
3331 }
3332
3333 int __connman_technology_disabled(enum connman_service_type type)
3334 {
3335         struct connman_technology *technology;
3336         GSList *list;
3337
3338         technology = technology_find(type);
3339         if (!technology)
3340                 return -ENXIO;
3341
3342 #if !defined TIZEN_EXT
3343         if (technology->rfkill_driven)
3344                 return 0;
3345
3346 #endif
3347         for (list = technology->device_list; list; list = list->next) {
3348                 struct connman_device *device = list->data;
3349
3350                 if (connman_device_get_powered(device))
3351                         return 0;
3352         }
3353
3354         return technology_disabled(technology);
3355 }
3356
3357 int __connman_technology_set_offlinemode(bool offlinemode)
3358 {
3359         GSList *list;
3360         int err = -EINVAL, enabled_tech_count = 0;
3361
3362         if (global_offlinemode == offlinemode)
3363                 return 0;
3364
3365         DBG("offlinemode %s", offlinemode ? "On" : "Off");
3366
3367         /*
3368          * This is a bit tricky. When you set offlinemode, there is no
3369          * way to differentiate between attempting offline mode and
3370          * resuming offlinemode from last saved profile. We need that
3371          * information in rfkill_update, otherwise it falls back on the
3372          * technology's persistent state. Hence we set the offline mode here
3373          * but save it & call the notifier only if it is successful.
3374          */
3375
3376         global_offlinemode = offlinemode;
3377
3378         /* Traverse technology list, enable/disable each technology. */
3379         for (list = technology_list; list; list = list->next) {
3380                 struct connman_technology *technology = list->data;
3381
3382                 if (offlinemode)
3383                         err = technology_disable(technology);
3384                 else {
3385                         if (technology->hardblocked)
3386                                 continue;
3387
3388                         if (technology->enable_persistent) {
3389                                 err = technology_enable(technology);
3390                                 enabled_tech_count++;
3391                         }
3392                 }
3393         }
3394
3395         if (err == 0 || err == -EINPROGRESS || err == -EALREADY ||
3396                         (err == -EINVAL && enabled_tech_count == 0)) {
3397                 connman_technology_save_offlinemode();
3398                 __connman_notifier_offlinemode(offlinemode);
3399         } else
3400                 global_offlinemode = connman_technology_load_offlinemode();
3401
3402         return err;
3403 }
3404
3405 #if defined TIZEN_EXT_WIFI_MESH
3406 static gboolean __add_ethernet_to_bridge(gpointer data)
3407 {
3408         DBG("");
3409         __connman_mesh_add_ethernet_to_bridge();
3410         return FALSE;
3411 }
3412 #endif
3413
3414 void __connman_technology_set_connected(enum connman_service_type type,
3415                 bool connected)
3416 {
3417         struct connman_technology *technology;
3418         dbus_bool_t val;
3419
3420         technology = technology_find(type);
3421         if (!technology)
3422                 return;
3423
3424         DBG("technology %p connected %d", technology, connected);
3425
3426         technology->connected = connected;
3427
3428 #if defined TIZEN_EXT_WIFI_MESH
3429         if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET && connected)
3430                 g_idle_add(__add_ethernet_to_bridge, NULL);
3431 #endif
3432
3433         val = connected;
3434         connman_dbus_property_changed_basic(technology->path,
3435                         CONNMAN_TECHNOLOGY_INTERFACE, "Connected",
3436                         DBUS_TYPE_BOOLEAN, &val);
3437 }
3438
3439 static bool technology_apply_rfkill_change(struct connman_technology *technology,
3440                                                 bool softblock,
3441                                                 bool hardblock,
3442                                                 bool new_rfkill)
3443 {
3444         bool hardblock_changed = false;
3445         bool apply = true;
3446         GList *start, *list;
3447
3448         DBG("technology %p --> %d/%d vs %d/%d",
3449                         technology, softblock, hardblock,
3450                         technology->softblocked, technology->hardblocked);
3451
3452         if (technology->hardblocked == hardblock)
3453                 goto softblock_change;
3454
3455         if (!(new_rfkill && !hardblock)) {
3456                 start = g_hash_table_get_values(rfkill_list);
3457
3458                 for (list = start; list; list = list->next) {
3459                         struct connman_rfkill *rfkill = list->data;
3460
3461                         if (rfkill->type != technology->type)
3462                                 continue;
3463
3464                         if (rfkill->hardblock != hardblock)
3465                                 apply = false;
3466                 }
3467
3468                 g_list_free(start);
3469         }
3470
3471         if (!apply)
3472                 goto softblock_change;
3473
3474         technology->hardblocked = hardblock;
3475         hardblock_changed = true;
3476
3477 softblock_change:
3478         if (!apply && technology->softblocked != softblock)
3479                 apply = true;
3480
3481         if (!apply)
3482                 return technology->hardblocked;
3483
3484         technology->softblocked = softblock;
3485
3486         if (technology->hardblocked ||
3487                                         technology->softblocked) {
3488                 if (technology_disabled(technology) != -EALREADY)
3489                         technology_affect_devices(technology, false);
3490         } else if (!technology->hardblocked &&
3491                                         !technology->softblocked) {
3492                 if (technology_enabled(technology) != -EALREADY)
3493                         technology_affect_devices(technology, true);
3494         }
3495
3496         if (hardblock_changed) {
3497                 if (technology->hardblocked) {
3498                         DBG("%s is switched off.", get_name(technology->type));
3499                         technology_dbus_unregister(technology);
3500                 } else {
3501                         DBG("%s is switched on.", get_name(technology->type));
3502                         technology_dbus_register(technology);
3503
3504                         if (global_offlinemode)
3505                                 __connman_rfkill_block(technology->type, true);
3506                 }
3507         }
3508
3509         return technology->hardblocked;
3510 }
3511
3512 int __connman_technology_add_rfkill(unsigned int index,
3513                                         enum connman_service_type type,
3514                                                 bool softblock,
3515                                                 bool hardblock)
3516 {
3517         struct connman_technology *technology;
3518         struct connman_rfkill *rfkill;
3519
3520         DBG("index %u type %d soft %u hard %u", index, type,
3521                                                         softblock, hardblock);
3522
3523         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
3524         if (rfkill)
3525                 goto done;
3526
3527         rfkill = g_try_new0(struct connman_rfkill, 1);
3528         if (!rfkill)
3529                 return -ENOMEM;
3530
3531         rfkill->index = index;
3532         rfkill->type = type;
3533         rfkill->softblock = softblock;
3534         rfkill->hardblock = hardblock;
3535
3536         g_hash_table_insert(rfkill_list, GINT_TO_POINTER(index), rfkill);
3537
3538 done:
3539 #if defined TIZEN_EXT
3540         /* Fix Svace Issue [WGID: 1348]. */
3541         g_free(rfkill);
3542 #endif
3543         technology = technology_get(type);
3544         /* If there is no driver for this type, ignore it. */
3545         if (!technology)
3546                 return -ENXIO;
3547
3548         technology->rfkill_driven = true;
3549
3550 #if !defined TIZEN_EXT
3551         /* If hardblocked, there is no need to handle softblocked state */
3552         if (technology_apply_rfkill_change(technology,
3553                                 softblock, hardblock, true))
3554                 return 0;
3555 #endif
3556
3557         if (global_offlinemode)
3558                 return 0;
3559
3560         /*
3561          * Depending on softblocked state we unblock/block according to
3562          * offlinemode and persistente state.
3563          */
3564         if (technology->softblocked &&
3565                                 technology->enable_persistent)
3566                 return __connman_rfkill_block(type, false);
3567         else if (!technology->softblocked &&
3568                                 !technology->enable_persistent)
3569                 return __connman_rfkill_block(type, true);
3570
3571         return 0;
3572 }
3573
3574 int __connman_technology_update_rfkill(unsigned int index,
3575                                         enum connman_service_type type,
3576                                                 bool softblock,
3577                                                 bool hardblock)
3578 {
3579         struct connman_technology *technology;
3580         struct connman_rfkill *rfkill;
3581
3582         DBG("index %u soft %u hard %u", index, softblock, hardblock);
3583
3584         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
3585         if (!rfkill)
3586                 return -ENXIO;
3587
3588         if (rfkill->softblock == softblock &&
3589                                 rfkill->hardblock == hardblock)
3590                 return 0;
3591
3592         rfkill->softblock = softblock;
3593         rfkill->hardblock = hardblock;
3594
3595         technology = technology_find(type);
3596         /* If there is no driver for this type, ignore it. */
3597         if (!technology)
3598                 return -ENXIO;
3599
3600         technology_apply_rfkill_change(technology, softblock, hardblock,
3601                                                                 false);
3602
3603         if (technology->hardblocked)
3604                 DBG("%s hardblocked", get_name(technology->type));
3605         else
3606                 DBG("%s is%s softblocked", get_name(technology->type),
3607                         technology->softblocked ? "" : " not");
3608
3609         return 0;
3610 }
3611
3612 int __connman_technology_remove_rfkill(unsigned int index,
3613                                         enum connman_service_type type)
3614 {
3615         struct connman_technology *technology;
3616         struct connman_rfkill *rfkill;
3617
3618         DBG("index %u", index);
3619
3620         rfkill = g_hash_table_lookup(rfkill_list, GINT_TO_POINTER(index));
3621         if (!rfkill)
3622                 return -ENXIO;
3623
3624         g_hash_table_remove(rfkill_list, GINT_TO_POINTER(index));
3625
3626         technology = technology_find(type);
3627         if (!technology)
3628                 return -ENXIO;
3629
3630         technology_apply_rfkill_change(technology,
3631                 technology->softblocked, !technology->hardblocked, false);
3632
3633         technology_put(technology);
3634
3635         return 0;
3636 }
3637
3638 int __connman_technology_init(void)
3639 {
3640         DBG("");
3641
3642         connection = connman_dbus_get_connection();
3643
3644         rfkill_list = g_hash_table_new_full(g_direct_hash, g_direct_equal,
3645                                                         NULL, free_rfkill);
3646
3647         global_offlinemode = connman_technology_load_offlinemode();
3648
3649         /* This will create settings file if it is missing */
3650         connman_technology_save_offlinemode();
3651
3652         return 0;
3653 }
3654
3655 void __connman_technology_cleanup(void)
3656 {
3657         DBG("");
3658
3659         while (technology_list) {
3660                 struct connman_technology *technology = technology_list->data;
3661                 technology_list = g_slist_remove(technology_list, technology);
3662                 technology_put(technology);
3663         }
3664
3665         g_hash_table_destroy(rfkill_list);
3666
3667         dbus_connection_unref(connection);
3668 }