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