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