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