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