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