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