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