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