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