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