Start wifi roaming when better BSS is found
[platform/upstream/connman.git] / plugins / wifi.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2014  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 <unistd.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <net/ethernet.h>
34 #include <linux/wireless.h>
35
36 #ifndef IFF_LOWER_UP
37 #define IFF_LOWER_UP    0x10000
38 #endif
39
40 #include <dbus/dbus.h>
41 #include <glib.h>
42
43 #define CONNMAN_API_SUBJECT_TO_CHANGE
44 #include <connman/plugin.h>
45 #include <connman/inet.h>
46 #include <connman/device.h>
47 #include <connman/rtnl.h>
48 #include <connman/technology.h>
49 #include <connman/service.h>
50 #include <connman/peer.h>
51 #include <connman/log.h>
52 #include <connman/option.h>
53 #include <connman/storage.h>
54 #include <include/setting.h>
55 #include <connman/provision.h>
56 #include <connman/utsname.h>
57 #include <connman/machine.h>
58 #include <connman/tethering.h>
59
60 #include <gsupplicant/gsupplicant.h>
61
62 #include "src/shared/util.h"
63
64 #define CLEANUP_TIMEOUT   8     /* in seconds */
65 #define INACTIVE_TIMEOUT  12    /* in seconds */
66 #define FAVORITE_MAXIMUM_RETRIES 2
67
68 #define BGSCAN_DEFAULT "simple:30:-65:300"
69 #define AUTOSCAN_EXPONENTIAL "exponential:3:300"
70 #define AUTOSCAN_SINGLE "single:3"
71
72 #define P2P_FIND_TIMEOUT 30
73 #define P2P_CONNECTION_TIMEOUT 100
74 #define P2P_LISTEN_PERIOD 500
75 #define P2P_LISTEN_INTERVAL 2000
76
77 #define ASSOC_STATUS_NO_CLIENT 17
78 #if defined TIZEN_EXT
79 #define LOAD_SHAPING_MAX_RETRIES 7
80 #else
81 #define LOAD_SHAPING_MAX_RETRIES 3
82 #endif
83
84 #if defined TIZEN_EXT
85 #define WIFI_EAP_FAST_PAC_FILE          "/var/lib/wifi/wifi.pac"        /* path of Pac file for EAP-FAST */
86
87         /* Wi-Fi Signal Strength (for 2.4G (dB))
88          * Excellent :     ~ -63
89          * Good      : -64 ~ -74
90          * Weak      : -75 ~ -82
91          * Very weak : -83 ~ -88
92          * No signal : -89 ~
93          *
94          * Wi-Fi Signal Strength (for 5G (dB))
95          * Excellent :     ~ -67
96          * Good      : -68 ~ -76
97          * Weak      : -77 ~ -82
98          * Very weak : -83 ~ -88
99          * No signal : -89 ~
100          */
101 #define RSSI_LEVEL_2_5G  -77
102 #define RSSI_LEVEL_2_24G -75
103 #define RSSI_LEVEL_3_5G  -68
104 #define RSSI_LEVEL_3_24G -64
105 #define WIFI_BSSID_STR_LEN 18
106 #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
107 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
108 #endif
109
110 static struct connman_technology *wifi_technology = NULL;
111 static struct connman_technology *p2p_technology = NULL;
112
113 enum wifi_ap_capability{
114         WIFI_AP_UNKNOWN         = 0,
115         WIFI_AP_SUPPORTED       = 1,
116         WIFI_AP_NOT_SUPPORTED   = 2,
117 };
118
119 enum wifi_scanning_type {
120         WIFI_SCANNING_UNKNOWN   = 0,
121         WIFI_SCANNING_PASSIVE   = 1,
122         WIFI_SCANNING_ACTIVE    = 2,
123 };
124
125 struct hidden_params {
126         char ssid[32];
127         unsigned int ssid_len;
128         char *identity;
129         char *anonymous_identity;
130         char *subject_match;
131         char *altsubject_match;
132         char *domain_suffix_match;
133         char *domain_match;
134         char *passphrase;
135         char *security;
136         GSupplicantScanParams *scan_params;
137         gpointer user_data;
138 };
139
140 /**
141  * Used for autoscan "emulation".
142  * Should be removed when wpa_s autoscan support will be by default.
143  */
144 struct autoscan_params {
145         int base;
146         int limit;
147         int interval;
148         unsigned int timeout;
149 };
150
151 struct wifi_tethering_info {
152         struct wifi_data *wifi;
153         struct connman_technology *technology;
154         char *ifname;
155         GSupplicantSSID *ssid;
156 };
157
158 struct wifi_data {
159         char *identifier;
160         struct connman_device *device;
161         struct connman_network *network;
162         struct connman_network *pending_network;
163         GSList *networks;
164         GSupplicantInterface *interface;
165         GSupplicantState state;
166         bool connected;
167         bool disconnecting;
168         bool tethering;
169         enum wifi_ap_capability ap_supported;
170         bool bridged;
171         bool interface_ready;
172         const char *bridge;
173         int index;
174         unsigned flags;
175         unsigned int watch;
176         int retries;
177         int load_shaping_retries;
178         struct hidden_params *hidden;
179         bool postpone_hidden;
180         struct wifi_tethering_info *tethering_param;
181         /**
182          * autoscan "emulation".
183          */
184         struct autoscan_params *autoscan;
185         enum wifi_scanning_type scanning_type;
186         GSupplicantScanParams *scan_params;
187         unsigned int p2p_find_timeout;
188         unsigned int p2p_connection_timeout;
189         struct connman_peer *pending_peer;
190         GSList *peers;
191         bool p2p_connecting;
192         bool p2p_device;
193         int servicing;
194 #if defined TIZEN_EXT
195         int assoc_retry_count;
196         struct connman_network *scan_pending_network;
197         bool allow_full_scan;
198         unsigned int automaxspeed_timeout;
199         GSupplicantScanParams *hidden_scan_params;
200         unsigned int mac_policy;
201         unsigned int preassoc_mac_policy;
202         unsigned int mac_lifetime;
203 #endif
204         int disconnect_code;
205         int assoc_code;
206 #if defined TIZEN_EXT_WIFI_MESH
207         bool mesh_interface;
208         struct wifi_mesh_info *mesh_info;
209 #endif
210 };
211
212 #if defined TIZEN_EXT
213 #include "connman.h"
214 #include "dbus.h"
215
216 #define TIZEN_ASSOC_RETRY_COUNT         4
217
218 static gboolean wifi_first_scan = false;
219 static gboolean found_with_first_scan = false;
220 static gboolean is_wifi_notifier_registered = false;
221 static GHashTable *failed_bssids = NULL;
222 static unsigned char buff_bssid[WIFI_BSSID_LEN_MAX] = { 0, };
223 #endif
224
225
226 static GList *iface_list = NULL;
227
228 static GList *pending_wifi_device = NULL;
229 static GList *p2p_iface_list = NULL;
230 static bool wfd_service_registered = false;
231
232 static void start_autoscan(struct connman_device *device);
233 static int tech_set_tethering(struct connman_technology *technology,
234                                 const char *identifier, const char *passphrase,
235                                 const char *bridge, bool enabled);
236
237 #if defined TIZEN_EXT
238 #define NETCONFIG_SERVICE "net.netconfig"
239 #define NETCONFIG_WIFI_PATH "/net/netconfig/wifi"
240 #define NETCONFIG_WIFI_INTERFACE NETCONFIG_SERVICE ".wifi"
241
242 struct enc_method_call_data {
243         DBusConnection *connection;
244         struct connman_network *network;
245 };
246
247 static struct enc_method_call_data encrypt_request_data;
248
249 static void encryption_request_reply(DBusPendingCall *call,
250                                                 void *user_data)
251 {
252         DBusMessage *reply;
253         DBusError error;
254         DBusMessageIter args;
255         char *out_data;
256         struct connman_service *service;
257         gchar* encrypted_value = NULL;
258         struct connman_network *network = encrypt_request_data.network;
259
260         DBG("");
261
262         reply = dbus_pending_call_steal_reply(call);
263
264         dbus_error_init(&error);
265         if (dbus_set_error_from_message(&error, reply)) {
266                 DBG("send_encryption_request() %s %s", error.name, error.message);
267                 dbus_error_free(&error);
268                 goto done;
269         }
270
271         if (dbus_message_iter_init(reply, &args) == FALSE)
272                 goto done;
273
274         dbus_message_iter_get_basic(&args, &out_data);
275
276         encrypted_value = g_strdup((const gchar *)out_data);
277         service = connman_service_lookup_from_network(network);
278
279         if (!service) {
280                 DBG("encryption result: no service");
281                 goto done;
282         }
283
284         if (connman_service_get_favorite(service)) {
285                 __connman_service_set_passphrase(service, encrypted_value);
286                 __connman_service_save(service);
287         } else
288                 connman_network_set_string(network, "WiFi.Passphrase",
289                                                         encrypted_value);
290
291         DBG("encryption result: succeeded");
292
293 done:
294         dbus_message_unref(reply);
295         dbus_pending_call_unref(call);
296         dbus_connection_unref(encrypt_request_data.connection);
297         g_free(encrypted_value);
298
299         encrypt_request_data.connection = NULL;
300         encrypt_request_data.network = NULL;
301 }
302
303 static int send_encryption_request(const char *passphrase,
304                                 struct connman_network *network)
305 {
306         DBusConnection *connection = NULL;
307         DBusMessage *msg = NULL;
308         DBusPendingCall *call;
309
310         if (!passphrase) {
311                 DBG("Invalid parameter");
312                 return -EINVAL;
313         }
314
315         connection = connman_dbus_get_connection();
316         if (!connection) {
317                 DBG("dbus connection does not exist");
318                 return -EINVAL;
319         }
320
321         msg = dbus_message_new_method_call(NETCONFIG_SERVICE, NETCONFIG_WIFI_PATH,
322                         NETCONFIG_WIFI_INTERFACE, "EncryptPassphrase");
323         if (!msg) {
324                 dbus_connection_unref(connection);
325                 return -EINVAL;
326         }
327
328         dbus_message_append_args(msg, DBUS_TYPE_STRING, &passphrase,
329                                                         DBUS_TYPE_INVALID);
330
331         if (!dbus_connection_send_with_reply(connection, msg,
332                                 &call, DBUS_TIMEOUT_USE_DEFAULT)) {
333                 dbus_message_unref(msg);
334                 dbus_connection_unref(connection);
335                 return -EIO;
336         }
337
338         if (!call) {
339                 dbus_message_unref(msg);
340                 dbus_connection_unref(connection);
341                 return -EIO;
342         }
343
344         encrypt_request_data.connection = connection;
345         encrypt_request_data.network = network;
346
347         dbus_pending_call_set_notify(call, encryption_request_reply, NULL, NULL);
348         dbus_message_unref(msg);
349
350         return 0;
351 }
352 #endif
353
354 static int p2p_tech_probe(struct connman_technology *technology)
355 {
356         p2p_technology = technology;
357
358         return 0;
359 }
360
361 static void p2p_tech_remove(struct connman_technology *technology)
362 {
363         p2p_technology = NULL;
364 }
365
366 static struct connman_technology_driver p2p_tech_driver = {
367         .name           = "p2p",
368         .type           = CONNMAN_SERVICE_TYPE_P2P,
369         .probe          = p2p_tech_probe,
370         .remove         = p2p_tech_remove,
371 };
372
373 static bool is_p2p_connecting(void)
374 {
375         GList *list;
376
377         for (list = iface_list; list; list = list->next) {
378                 struct wifi_data *wifi = list->data;
379
380                 if (wifi->p2p_connecting)
381                         return true;
382         }
383
384         return false;
385 }
386
387 static void add_pending_wifi_device(struct wifi_data *wifi)
388 {
389         if (g_list_find(pending_wifi_device, wifi))
390                 return;
391
392         pending_wifi_device = g_list_append(pending_wifi_device, wifi);
393 }
394
395 #if defined TIZEN_EXT_WIFI_MESH
396 struct wifi_mesh_info {
397         struct wifi_data *wifi;
398         GSupplicantInterface *interface;
399         struct connman_mesh *mesh;
400         char *parent_ifname;
401         char *ifname;
402         char *identifier;
403         int index;
404 };
405
406 struct mesh_change_peer_status_info {
407         char *peer_address;
408         enum connman_mesh_peer_status peer_status;
409         mesh_change_peer_status_cb_t callback;
410         void *user_data;
411 };
412
413 static struct connman_technology_driver mesh_tech_driver = {
414         .name = "mesh",
415         .type = CONNMAN_SERVICE_TYPE_MESH,
416 };
417
418 static void mesh_interface_create_callback(int result,
419                                            GSupplicantInterface *interface,
420                                            void *user_data)
421 {
422         struct wifi_mesh_info *mesh_info = user_data;
423         struct wifi_data *wifi;
424         bool success = false;
425
426         DBG("result %d ifname %s, mesh_info %p", result,
427                                 g_supplicant_interface_get_ifname(interface),
428                                 mesh_info);
429
430         if (result < 0 || !mesh_info)
431                 goto done;
432
433         wifi = mesh_info->wifi;
434
435         mesh_info->interface = interface;
436         mesh_info->identifier = connman_inet_ifaddr(mesh_info->ifname);
437         mesh_info->index = connman_inet_ifindex(mesh_info->ifname);
438         DBG("Mesh Interface identifier %s", mesh_info->identifier);
439         wifi->mesh_interface = true;
440         wifi->mesh_info = mesh_info;
441         g_supplicant_interface_set_data(interface, wifi);
442         success = true;
443
444 done:
445         connman_mesh_notify_interface_create(success);
446 }
447
448 static int add_mesh_interface(const char *ifname, const char *parent_ifname)
449 {
450         GList *list;
451         struct wifi_data *wifi;
452         struct wifi_mesh_info *mesh_info;
453         const char *wifi_ifname;
454         bool parent_found = false;
455         const char *driver = "nl80211";
456
457         for (list = iface_list; list; list = list->next) {
458                 wifi = list->data;
459
460                 if (!g_supplicant_interface_has_mesh(wifi->interface))
461                         continue;
462
463                 wifi_ifname = g_supplicant_interface_get_ifname(wifi->interface);
464                 if (!wifi_ifname)
465                         continue;
466
467                 if (!g_strcmp0(wifi_ifname, parent_ifname)) {
468                         parent_found = true;
469                         break;
470                 }
471         }
472
473         if (!parent_found) {
474                 DBG("Parent interface %s doesn't exist", parent_ifname);
475                 return -ENODEV;
476         }
477
478         mesh_info = g_try_malloc0(sizeof(struct wifi_mesh_info));
479         if (!mesh_info)
480                 return -ENOMEM;
481
482         mesh_info->wifi = wifi;
483         mesh_info->ifname = g_strdup(ifname);
484         mesh_info->parent_ifname = g_strdup(parent_ifname);
485
486         g_supplicant_mesh_interface_create(ifname, driver, NULL, parent_ifname,
487                                                 mesh_interface_create_callback, mesh_info);
488         return -EINPROGRESS;
489 }
490
491 static void mesh_interface_remove_callback(int result,
492                                         GSupplicantInterface *interface,
493                                                         void *user_data)
494 {
495         struct wifi_data *wifi = user_data;
496         struct wifi_mesh_info *mesh_info = wifi->mesh_info;
497         bool success = false;
498
499         DBG("result %d mesh_info %p", result, mesh_info);
500
501         if (result < 0 || !mesh_info)
502                 goto done;
503
504         mesh_info->interface = NULL;
505         g_free(mesh_info->parent_ifname);
506         g_free(mesh_info->ifname);
507         g_free(mesh_info->identifier);
508         g_free(mesh_info);
509         wifi->mesh_interface = false;
510         wifi->mesh_info = NULL;
511         success = true;
512
513 done:
514         connman_mesh_notify_interface_remove(success);
515 }
516
517 static int remove_mesh_interface(const char *ifname)
518 {
519         GList *list;
520         struct wifi_data *wifi;
521         struct wifi_mesh_info *mesh_info;
522         bool mesh_if_found = false;
523         int ret;
524
525         for (list = iface_list; list; list = list->next) {
526                 wifi = list->data;
527
528                 if (wifi->mesh_interface) {
529                         mesh_if_found = true;
530                         break;
531                 }
532         }
533
534         if (!mesh_if_found) {
535                 DBG("Mesh interface %s doesn't exist", ifname);
536                 return -ENODEV;
537         }
538
539         mesh_info = wifi->mesh_info;
540         ret = g_supplicant_interface_remove(mesh_info->interface,
541                                                 mesh_interface_remove_callback, wifi);
542         if (ret < 0)
543                 return ret;
544
545         return -EINPROGRESS;
546 }
547
548 static void mesh_disconnect_callback(int result,
549                                         GSupplicantInterface *interface, void *user_data)
550 {
551         struct connman_mesh *mesh = user_data;
552
553         DBG("result %d interface %p mesh %p", result, interface, mesh);
554 }
555
556 static int mesh_peer_disconnect(struct connman_mesh *mesh)
557 {
558         GList *list;
559         struct wifi_data *wifi;
560         struct wifi_mesh_info *mesh_info;
561         bool mesh_if_found = false;
562         GSupplicantInterface *interface;
563
564         for (list = iface_list; list; list = list->next) {
565                 wifi = list->data;
566
567                 if (wifi->mesh_interface) {
568                         mesh_if_found = true;
569                         break;
570                 }
571         }
572
573         if (!mesh_if_found) {
574                 DBG("Mesh interface is not created");
575                 return -ENODEV;
576         }
577
578         mesh_info = wifi->mesh_info;
579
580         interface = mesh_info->interface;
581         return g_supplicant_interface_disconnect(interface,
582                                                 mesh_disconnect_callback, mesh);
583 }
584
585 static void mesh_connect_callback(int result, GSupplicantInterface *interface,
586                                                                   void *user_data)
587 {
588         struct connman_mesh *mesh = user_data;
589         DBG("mesh %p result %d", mesh, result);
590
591         if (result < 0)
592                 connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_FAILURE);
593         else
594                 connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_ASSOCIATION);
595 }
596
597 static GSupplicantSecurity mesh_network_security(const char *security)
598 {
599         if (g_str_equal(security, "none"))
600                 return G_SUPPLICANT_SECURITY_NONE;
601         else if (g_str_equal(security, "sae"))
602                 return G_SUPPLICANT_SECURITY_SAE;
603
604         return G_SUPPLICANT_SECURITY_UNKNOWN;
605 }
606
607 static void mesh_ssid_init(GSupplicantSSID *ssid, struct connman_mesh *mesh)
608 {
609         const char *name;
610         const char *security;
611
612         if (ssid->ssid)
613                 g_free(ssid->ssid);
614
615         memset(ssid, 0, sizeof(*ssid));
616         ssid->mode = G_SUPPLICANT_MODE_MESH;
617
618         security = connman_mesh_get_security(mesh);
619         ssid->security = mesh_network_security(security);
620
621         if (ssid->security == G_SUPPLICANT_SECURITY_SAE)
622                 ssid->passphrase = connman_mesh_get_passphrase(mesh);
623
624         ssid->freq = connman_mesh_get_frequency(mesh);
625         name = connman_mesh_get_name(mesh);
626         if (name) {
627                 ssid->ssid_len = strlen(name);
628                 ssid->ssid = g_malloc0(ssid->ssid_len + 1);
629                 memcpy(ssid->ssid, name, ssid->ssid_len);
630                 ssid->scan_ssid = 1;
631         }
632 }
633
634 static int mesh_peer_connect(struct connman_mesh *mesh)
635 {
636         GList *list;
637         struct wifi_data *wifi;
638         struct wifi_mesh_info *mesh_info;
639         bool mesh_if_found = false;
640         GSupplicantInterface *interface;
641         GSupplicantSSID *ssid;
642
643         for (list = iface_list; list; list = list->next) {
644                 wifi = list->data;
645
646                 if (wifi->mesh_interface) {
647                         mesh_if_found = true;
648                         break;
649                 }
650         }
651
652         if (!mesh_if_found) {
653                 DBG("Mesh interface is not created");
654                 return -ENODEV;
655         }
656
657         mesh_info = wifi->mesh_info;
658
659         interface = mesh_info->interface;
660
661         ssid = g_try_malloc0(sizeof(GSupplicantSSID));
662         if (!ssid)
663                 return -ENOMEM;
664
665         mesh_info->mesh = mesh;
666
667         mesh_ssid_init(ssid, mesh);
668         return g_supplicant_interface_connect(interface, ssid,
669                                                 mesh_connect_callback, mesh);
670 }
671
672 static void mesh_peer_change_status_callback(int result,
673                                              GSupplicantInterface *interface,
674                                              void *user_data)
675 {
676         struct mesh_change_peer_status_info *data = user_data;
677
678         DBG("result %d Peer Status %d", result, data->peer_status);
679
680         if (result == 0 && data->peer_status == CONNMAN_MESH_PEER_REMOVE) {
681                 /* WLAN_REASON_MESH_PEERING_CANCELLED = 52 */
682                 connman_mesh_remove_connected_peer(data->peer_address, 52);
683         }
684
685         if (data->callback)
686                 data->callback(result, data->user_data);
687
688         g_free(data->peer_address);
689         g_free(data);
690         return;
691 }
692
693 static int mesh_change_peer_status(const char *peer_address,
694                                    enum connman_mesh_peer_status status,
695                                    mesh_change_peer_status_cb_t callback, void *user_data)
696 {
697         GList *list;
698         struct wifi_data *wifi;
699         struct wifi_mesh_info *mesh_info;
700         bool mesh_if_found = false;
701         GSupplicantInterface *interface;
702         struct mesh_change_peer_status_info *data;
703         const char *method;
704
705         for (list = iface_list; list; list = list->next) {
706                 wifi = list->data;
707
708                 if (wifi->mesh_interface) {
709                         mesh_if_found = true;
710                         break;
711                 }
712         }
713
714         if (!mesh_if_found) {
715                 DBG("Mesh interface is not created");
716                 return -ENODEV;
717         }
718
719         mesh_info = wifi->mesh_info;
720
721         interface = mesh_info->interface;
722
723         switch (status) {
724         case CONNMAN_MESH_PEER_ADD:
725                 method = "MeshPeerAdd";
726                 break;
727         case CONNMAN_MESH_PEER_REMOVE:
728                 method = "MeshPeerRemove";
729                 break;
730         default:
731                 DBG("Invalid method");
732                 return -EINVAL;
733         }
734
735         data = g_try_malloc0(sizeof(struct mesh_change_peer_status_info));
736         if (data == NULL) {
737                 DBG("Memory allocation failed");
738                 return -ENOMEM;
739         }
740
741         data->peer_address = g_strdup(peer_address);
742         data->peer_status = status;
743         data->callback = callback;
744         data->user_data = user_data;
745
746         return g_supplicant_interface_mesh_peer_change_status(interface,
747                                                 mesh_peer_change_status_callback, peer_address, method,
748                                                 data);
749 }
750
751 static struct connman_mesh_driver mesh_driver = {
752         .add_interface      = add_mesh_interface,
753         .remove_interface   = remove_mesh_interface,
754         .connect            = mesh_peer_connect,
755         .disconnect         = mesh_peer_disconnect,
756         .change_peer_status = mesh_change_peer_status,
757 };
758
759 static void mesh_support(GSupplicantInterface *interface)
760 {
761         DBG("");
762
763         if (!g_supplicant_interface_has_mesh(interface))
764                 return;
765
766         if (connman_technology_driver_register(&mesh_tech_driver) < 0) {
767                 DBG("Could not register Mesh technology driver");
768                 return;
769         }
770
771         connman_mesh_driver_register(&mesh_driver);
772 }
773
774 static void check_mesh_technology(void)
775 {
776         bool mesh_exists = false;
777         GList *list;
778
779         for (list = iface_list; list; list = list->next) {
780                 struct wifi_data *w = list->data;
781
782                 if (w->interface &&
783                                 g_supplicant_interface_has_mesh(w->interface))
784                         mesh_exists = true;
785         }
786
787         if (!mesh_exists) {
788                 connman_technology_driver_unregister(&mesh_tech_driver);
789                 connman_mesh_driver_unregister(&mesh_driver);
790         }
791 }
792
793 static void mesh_group_started(GSupplicantInterface *interface)
794 {
795         struct wifi_data *wifi;
796         struct wifi_mesh_info *mesh_info;
797         struct connman_mesh *mesh;
798         const unsigned char *ssid;
799         unsigned int ssid_len;
800         char name[33];
801
802         ssid = g_supplicant_interface_get_mesh_group_ssid(interface, &ssid_len);
803         memcpy(name, ssid, ssid_len);
804         name[ssid_len] = '\0';
805         DBG("name %s", name);
806         wifi = g_supplicant_interface_get_data(interface);
807         DBG("wifi %p", wifi);
808
809         if (!wifi)
810                 return;
811
812         mesh_info = wifi->mesh_info;
813         if (!mesh_info)
814                 return;
815
816         mesh = mesh_info->mesh;
817         if (!mesh)
818                 return;
819
820         connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_CONFIGURATION);
821 }
822
823 static void mesh_group_removed(GSupplicantInterface *interface)
824 {
825         struct wifi_data *wifi;
826         struct wifi_mesh_info *mesh_info;
827         struct connman_mesh *mesh;
828         const unsigned char *ssid;
829         unsigned int ssid_len;
830         int disconnect_reason;
831         char name[33];
832
833         ssid = g_supplicant_interface_get_mesh_group_ssid(interface, &ssid_len);
834         memcpy(name, ssid, ssid_len);
835         name[ssid_len] = '\0';
836         DBG("name %s", name);
837
838         disconnect_reason = g_supplicant_mesh_get_disconnect_reason(interface);
839         DBG("Disconnect Reason %d", disconnect_reason);
840
841         wifi = g_supplicant_interface_get_data(interface);
842         DBG("wifi %p", wifi);
843
844         if (!wifi)
845                 return;
846
847         mesh_info = wifi->mesh_info;
848         if (!mesh_info)
849                 return;
850
851         mesh = connman_get_connected_mesh_from_name(name);
852         if (!mesh) {
853                 DBG("%s is not connected", name);
854                 mesh = connman_get_connecting_mesh_from_name(name);
855                 if (!mesh) {
856                         DBG("%s is not connecting", name);
857                         return;
858                 }
859         }
860
861         connman_mesh_peer_set_disconnect_reason(mesh, disconnect_reason);
862         connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_DISCONNECT);
863 }
864
865 static void mesh_peer_connected(GSupplicantMeshPeer *mesh_peer)
866 {
867         const char *peer_address;
868
869         peer_address = g_supplicant_mesh_peer_get_address(mesh_peer);
870
871         if (!peer_address)
872                 return;
873
874         DBG("Peer %s connected", peer_address);
875         connman_mesh_add_connected_peer(peer_address);
876 }
877
878 static void mesh_peer_disconnected(GSupplicantMeshPeer *mesh_peer)
879 {
880         const char *peer_address;
881         int reason;
882
883         peer_address = g_supplicant_mesh_peer_get_address(mesh_peer);
884
885         if (!peer_address)
886                 return;
887
888         reason = g_supplicant_mesh_peer_get_disconnect_reason(mesh_peer);
889
890         DBG("Peer %s disconnected with reason %d", peer_address, reason);
891         connman_mesh_remove_connected_peer(peer_address, reason);
892 }
893 #endif
894
895 static struct wifi_data *get_pending_wifi_data(const char *ifname)
896 {
897         GList *list;
898
899         for (list = pending_wifi_device; list; list = list->next) {
900                 struct wifi_data *wifi;
901                 const char *dev_name;
902
903                 wifi = list->data;
904                 if (!wifi || !wifi->device)
905                         continue;
906
907                 dev_name = connman_device_get_string(wifi->device, "Interface");
908                 if (!g_strcmp0(ifname, dev_name)) {
909                         pending_wifi_device = g_list_delete_link(
910                                                 pending_wifi_device, list);
911                         return wifi;
912                 }
913         }
914
915         return NULL;
916 }
917
918 static void remove_pending_wifi_device(struct wifi_data *wifi)
919 {
920         GList *link;
921
922         link = g_list_find(pending_wifi_device, wifi);
923
924         if (!link)
925                 return;
926
927         pending_wifi_device = g_list_delete_link(pending_wifi_device, link);
928 }
929
930 static void peer_cancel_timeout(struct wifi_data *wifi)
931 {
932         if (wifi->p2p_connection_timeout > 0)
933                 g_source_remove(wifi->p2p_connection_timeout);
934
935         wifi->p2p_connection_timeout = 0;
936         wifi->p2p_connecting = false;
937
938         if (wifi->pending_peer) {
939                 connman_peer_unref(wifi->pending_peer);
940                 wifi->pending_peer = NULL;
941         }
942 }
943
944 static gboolean peer_connect_timeout(gpointer data)
945 {
946         struct wifi_data *wifi = data;
947
948         DBG("");
949
950         if (wifi->p2p_connecting) {
951                 enum connman_peer_state state = CONNMAN_PEER_STATE_FAILURE;
952                 GSupplicantPeer *gs_peer =
953                         g_supplicant_interface_peer_lookup(wifi->interface,
954                                 connman_peer_get_identifier(wifi->pending_peer));
955
956                 if (g_supplicant_peer_has_requested_connection(gs_peer))
957                         state = CONNMAN_PEER_STATE_IDLE;
958
959                 connman_peer_set_state(wifi->pending_peer, state);
960         }
961
962         peer_cancel_timeout(wifi);
963
964         return FALSE;
965 }
966
967 static void peer_connect_callback(int result, GSupplicantInterface *interface,
968                                                         void *user_data)
969 {
970         struct wifi_data *wifi = user_data;
971         struct connman_peer *peer = wifi->pending_peer;
972
973         DBG("peer %p - %d", peer, result);
974
975         if (!peer)
976                 return;
977
978         if (result < 0) {
979                 peer_connect_timeout(wifi);
980                 return;
981         }
982
983         connman_peer_set_state(peer, CONNMAN_PEER_STATE_ASSOCIATION);
984
985         wifi->p2p_connection_timeout = g_timeout_add_seconds(
986                                                 P2P_CONNECTION_TIMEOUT,
987                                                 peer_connect_timeout, wifi);
988 }
989
990 static int peer_connect(struct connman_peer *peer,
991                         enum connman_peer_wps_method wps_method,
992                         const char *wps_pin)
993 {
994         struct connman_device *device = connman_peer_get_device(peer);
995         GSupplicantPeerParams *peer_params;
996         GSupplicantPeer *gs_peer;
997         struct wifi_data *wifi;
998         bool pbc, pin;
999         int ret;
1000
1001         DBG("peer %p", peer);
1002
1003         if (!device)
1004                 return -ENODEV;
1005
1006         wifi = connman_device_get_data(device);
1007         if (!wifi || !wifi->interface)
1008                 return -ENODEV;
1009
1010         if (wifi->p2p_connecting)
1011                 return -EBUSY;
1012
1013         gs_peer = g_supplicant_interface_peer_lookup(wifi->interface,
1014                                         connman_peer_get_identifier(peer));
1015         if (!gs_peer)
1016                 return -EINVAL;
1017
1018         pbc = g_supplicant_peer_is_wps_pbc(gs_peer);
1019         pin = g_supplicant_peer_is_wps_pin(gs_peer);
1020
1021         switch (wps_method) {
1022         case CONNMAN_PEER_WPS_UNKNOWN:
1023                 if ((pbc && pin) || pin)
1024                         return -ENOKEY;
1025                 break;
1026         case CONNMAN_PEER_WPS_PBC:
1027                 if (!pbc)
1028                         return -EINVAL;
1029                 wps_pin = NULL;
1030                 break;
1031         case CONNMAN_PEER_WPS_PIN:
1032                 if (!pin || !wps_pin)
1033                         return -EINVAL;
1034                 break;
1035         }
1036
1037         peer_params = g_try_malloc0(sizeof(GSupplicantPeerParams));
1038         if (!peer_params)
1039                 return -ENOMEM;
1040
1041         peer_params->path = g_strdup(g_supplicant_peer_get_path(gs_peer));
1042         if (wps_pin)
1043                 peer_params->wps_pin = g_strdup(wps_pin);
1044
1045         peer_params->master = connman_peer_service_is_master();
1046
1047         ret = g_supplicant_interface_p2p_connect(wifi->interface, peer_params,
1048                                                 peer_connect_callback, wifi);
1049         if (ret == -EINPROGRESS) {
1050                 wifi->pending_peer = connman_peer_ref(peer);
1051                 wifi->p2p_connecting = true;
1052         } else if (ret < 0) {
1053                 g_free(peer_params->path);
1054                 g_free(peer_params->wps_pin);
1055                 g_free(peer_params);
1056         }
1057
1058         return ret;
1059 }
1060
1061 static int peer_disconnect(struct connman_peer *peer)
1062 {
1063         struct connman_device *device = connman_peer_get_device(peer);
1064         GSupplicantPeerParams peer_params = {};
1065         GSupplicantPeer *gs_peer;
1066         struct wifi_data *wifi;
1067         int ret;
1068
1069         DBG("peer %p", peer);
1070
1071         if (!device)
1072                 return -ENODEV;
1073
1074         wifi = connman_device_get_data(device);
1075         if (!wifi)
1076                 return -ENODEV;
1077
1078         gs_peer = g_supplicant_interface_peer_lookup(wifi->interface,
1079                                         connman_peer_get_identifier(peer));
1080         if (!gs_peer)
1081                 return -EINVAL;
1082
1083         peer_params.path = g_strdup(g_supplicant_peer_get_path(gs_peer));
1084
1085         ret = g_supplicant_interface_p2p_disconnect(wifi->interface,
1086                                                         &peer_params);
1087         g_free(peer_params.path);
1088
1089         if (ret == -EINPROGRESS) {
1090                 peer_cancel_timeout(wifi);
1091                 wifi->p2p_device = false;
1092         }
1093
1094         return ret;
1095 }
1096
1097 struct peer_service_registration {
1098         peer_service_registration_cb_t callback;
1099         void *user_data;
1100 };
1101
1102 static bool is_service_wfd(const unsigned char *specs, int length)
1103 {
1104         if (length < 9 || specs[0] != 0 || specs[1] != 0 || specs[2] != 6)
1105                 return false;
1106
1107         return true;
1108 }
1109
1110 static void apply_p2p_listen_on_iface(gpointer data, gpointer user_data)
1111 {
1112         struct wifi_data *wifi = data;
1113
1114         if (!wifi->interface ||
1115                         !g_supplicant_interface_has_p2p(wifi->interface))
1116                 return;
1117
1118         if (!wifi->servicing) {
1119                 g_supplicant_interface_p2p_listen(wifi->interface,
1120                                 P2P_LISTEN_PERIOD, P2P_LISTEN_INTERVAL);
1121         }
1122
1123         wifi->servicing++;
1124 }
1125
1126 static void register_wfd_service_cb(int result,
1127                                 GSupplicantInterface *iface, void *user_data)
1128 {
1129         struct peer_service_registration *reg_data = user_data;
1130
1131         DBG("");
1132
1133         if (result == 0)
1134                 g_list_foreach(iface_list, apply_p2p_listen_on_iface, NULL);
1135
1136         if (reg_data && reg_data->callback) {
1137                 reg_data->callback(result, reg_data->user_data);
1138                 g_free(reg_data);
1139         }
1140 }
1141
1142 static GSupplicantP2PServiceParams *fill_in_peer_service_params(
1143                                 const unsigned char *spec,
1144                                 int spec_length, const unsigned char *query,
1145                                 int query_length, int version)
1146 {
1147         GSupplicantP2PServiceParams *params;
1148
1149         params = g_try_malloc0(sizeof(GSupplicantP2PServiceParams));
1150         if (!params)
1151                 return NULL;
1152
1153         if (version > 0) {
1154                 params->version = version;
1155                 params->service = g_memdup(spec, spec_length);
1156         } else if (query_length > 0 && spec_length > 0) {
1157                 params->query = g_memdup(query, query_length);
1158                 params->query_length = query_length;
1159
1160                 params->response = g_memdup(spec, spec_length);
1161                 params->response_length = spec_length;
1162         } else {
1163                 params->wfd_ies = g_memdup(spec, spec_length);
1164                 params->wfd_ies_length = spec_length;
1165         }
1166
1167         return params;
1168 }
1169
1170 static void free_peer_service_params(GSupplicantP2PServiceParams *params)
1171 {
1172         if (!params)
1173                 return;
1174
1175         g_free(params->service);
1176         g_free(params->query);
1177         g_free(params->response);
1178         g_free(params->wfd_ies);
1179
1180         g_free(params);
1181 }
1182
1183 static int peer_register_wfd_service(const unsigned char *specification,
1184                                 int specification_length,
1185                                 peer_service_registration_cb_t callback,
1186                                 void *user_data)
1187 {
1188         struct peer_service_registration *reg_data = NULL;
1189         static GSupplicantP2PServiceParams *params;
1190         int ret;
1191
1192         DBG("");
1193
1194         if (wfd_service_registered)
1195                 return -EBUSY;
1196
1197         params = fill_in_peer_service_params(specification,
1198                                         specification_length, NULL, 0, 0);
1199         if (!params)
1200                 return -ENOMEM;
1201
1202         reg_data = g_try_malloc0(sizeof(*reg_data));
1203         if (!reg_data) {
1204                 ret = -ENOMEM;
1205                 goto error;
1206         }
1207
1208         reg_data->callback = callback;
1209         reg_data->user_data = user_data;
1210
1211         ret = g_supplicant_set_widi_ies(params,
1212                                         register_wfd_service_cb, reg_data);
1213         if (ret < 0 && ret != -EINPROGRESS)
1214                 goto error;
1215
1216         wfd_service_registered = true;
1217
1218         return ret;
1219 error:
1220         free_peer_service_params(params);
1221         g_free(reg_data);
1222
1223         return ret;
1224 }
1225
1226 static void register_peer_service_cb(int result,
1227                                 GSupplicantInterface *iface, void *user_data)
1228 {
1229         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
1230         struct peer_service_registration *reg_data = user_data;
1231
1232 #if defined TIZEN_EXT
1233         if (!wifi)
1234                 return;
1235 #endif
1236
1237         DBG("");
1238
1239         if (result == 0)
1240                 apply_p2p_listen_on_iface(wifi, NULL);
1241
1242         if (reg_data->callback)
1243                 reg_data->callback(result, reg_data->user_data);
1244
1245         g_free(reg_data);
1246 }
1247
1248 static int peer_register_service(const unsigned char *specification,
1249                                 int specification_length,
1250                                 const unsigned char *query,
1251                                 int query_length, int version,
1252                                 peer_service_registration_cb_t callback,
1253                                 void *user_data)
1254 {
1255         struct peer_service_registration *reg_data;
1256         GSupplicantP2PServiceParams *params;
1257         bool found = false;
1258         int ret, ret_f;
1259         GList *list;
1260
1261         DBG("");
1262
1263         if (specification && !version && !query &&
1264                         is_service_wfd(specification, specification_length)) {
1265                 return peer_register_wfd_service(specification,
1266                                 specification_length, callback, user_data);
1267         }
1268
1269         reg_data = g_try_malloc0(sizeof(*reg_data));
1270         if (!reg_data)
1271                 return -ENOMEM;
1272
1273         reg_data->callback = callback;
1274         reg_data->user_data = user_data;
1275
1276         ret_f = -EOPNOTSUPP;
1277
1278         for (list = iface_list; list; list = list->next) {
1279                 struct wifi_data *wifi = list->data;
1280                 GSupplicantInterface *iface = wifi->interface;
1281
1282                 if (!g_supplicant_interface_has_p2p(iface))
1283                         continue;
1284
1285                 params = fill_in_peer_service_params(specification,
1286                                                 specification_length, query,
1287                                                 query_length, version);
1288                 if (!params)
1289                         continue;
1290
1291                 if (!found) {
1292                         ret_f = g_supplicant_interface_p2p_add_service(iface,
1293                                 register_peer_service_cb, params, reg_data);
1294                         if (ret_f == 0 || ret_f == -EINPROGRESS)
1295                                 found = true;
1296                         ret = ret_f;
1297                 } else
1298                         ret = g_supplicant_interface_p2p_add_service(iface,
1299                                 register_peer_service_cb, params, NULL);
1300                 if (ret != 0 && ret != -EINPROGRESS)
1301                         free_peer_service_params(params);
1302         }
1303
1304         if (ret_f != 0 && ret_f != -EINPROGRESS)
1305                 g_free(reg_data);
1306
1307         return ret_f;
1308 }
1309
1310 static int peer_unregister_wfd_service(void)
1311 {
1312         GSupplicantP2PServiceParams *params;
1313         GList *list;
1314
1315         if (!wfd_service_registered)
1316                 return -EALREADY;
1317
1318         params = fill_in_peer_service_params(NULL, 0, NULL, 0, 0);
1319         if (!params)
1320                 return -ENOMEM;
1321
1322         wfd_service_registered = false;
1323
1324         g_supplicant_set_widi_ies(params, NULL, NULL);
1325
1326         for (list = iface_list; list; list = list->next) {
1327                 struct wifi_data *wifi = list->data;
1328
1329                 if (!g_supplicant_interface_has_p2p(wifi->interface))
1330                         continue;
1331
1332                 wifi->servicing--;
1333                 if (!wifi->servicing || wifi->servicing < 0) {
1334                         g_supplicant_interface_p2p_listen(wifi->interface,
1335                                                                         0, 0);
1336                         wifi->servicing = 0;
1337                 }
1338         }
1339
1340         return 0;
1341 }
1342
1343 static int peer_unregister_service(const unsigned char *specification,
1344                                                 int specification_length,
1345                                                 const unsigned char *query,
1346                                                 int query_length, int version)
1347 {
1348         GSupplicantP2PServiceParams *params;
1349         bool wfd = false;
1350         GList *list;
1351         int ret;
1352
1353         if (specification && !version && !query &&
1354                         is_service_wfd(specification, specification_length)) {
1355                 ret = peer_unregister_wfd_service();
1356                 if (ret != 0 && ret != -EINPROGRESS)
1357                         return ret;
1358                 wfd = true;
1359         }
1360
1361         for (list = iface_list; list; list = list->next) {
1362                 struct wifi_data *wifi = list->data;
1363                 GSupplicantInterface *iface = wifi->interface;
1364
1365                 if (wfd)
1366                         goto stop_listening;
1367
1368                 if (!g_supplicant_interface_has_p2p(iface))
1369                         continue;
1370
1371                 params = fill_in_peer_service_params(specification,
1372                                                 specification_length, query,
1373                                                 query_length, version);
1374                 if (!params)
1375                         continue;
1376
1377                 ret = g_supplicant_interface_p2p_del_service(iface, params);
1378                 if (ret != 0 && ret != -EINPROGRESS)
1379                         free_peer_service_params(params);
1380 stop_listening:
1381                 wifi->servicing--;
1382                 if (!wifi->servicing || wifi->servicing < 0) {
1383                         g_supplicant_interface_p2p_listen(iface, 0, 0);
1384                         wifi->servicing = 0;
1385                 }
1386         }
1387
1388         return 0;
1389 }
1390
1391 static struct connman_peer_driver peer_driver = {
1392         .connect    = peer_connect,
1393         .disconnect = peer_disconnect,
1394         .register_service = peer_register_service,
1395         .unregister_service = peer_unregister_service,
1396 };
1397
1398 static void handle_tethering(struct wifi_data *wifi)
1399 {
1400         if (!wifi->tethering)
1401                 return;
1402
1403         if (!wifi->bridge)
1404                 return;
1405
1406         if (wifi->bridged)
1407                 return;
1408
1409         DBG("index %d bridge %s", wifi->index, wifi->bridge);
1410
1411         if (connman_inet_add_to_bridge(wifi->index, wifi->bridge) < 0)
1412                 return;
1413
1414         wifi->bridged = true;
1415 }
1416
1417 static void wifi_newlink(unsigned flags, unsigned change, void *user_data)
1418 {
1419         struct connman_device *device = user_data;
1420         struct wifi_data *wifi = connman_device_get_data(device);
1421
1422         if (!wifi)
1423                 return;
1424
1425         DBG("index %d flags %d change %d", wifi->index, flags, change);
1426
1427         if ((wifi->flags & IFF_UP) != (flags & IFF_UP)) {
1428                 if (flags & IFF_UP)
1429                         DBG("interface up");
1430                 else
1431                         DBG("interface down");
1432         }
1433
1434         if ((wifi->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
1435                 if (flags & IFF_LOWER_UP) {
1436                         DBG("carrier on");
1437
1438                         handle_tethering(wifi);
1439                 } else
1440                         DBG("carrier off");
1441         }
1442
1443         wifi->flags = flags;
1444 }
1445
1446 static int wifi_probe(struct connman_device *device)
1447 {
1448         struct wifi_data *wifi;
1449
1450         DBG("device %p", device);
1451
1452         wifi = g_try_new0(struct wifi_data, 1);
1453         if (!wifi)
1454                 return -ENOMEM;
1455
1456         wifi->state = G_SUPPLICANT_STATE_INACTIVE;
1457         wifi->ap_supported = WIFI_AP_UNKNOWN;
1458         wifi->tethering_param = NULL;
1459
1460         connman_device_set_data(device, wifi);
1461         wifi->device = connman_device_ref(device);
1462
1463         wifi->index = connman_device_get_index(device);
1464         wifi->flags = 0;
1465
1466         wifi->watch = connman_rtnl_add_newlink_watch(wifi->index,
1467                                                         wifi_newlink, device);
1468         if (is_p2p_connecting())
1469                 add_pending_wifi_device(wifi);
1470         else
1471                 iface_list = g_list_append(iface_list, wifi);
1472
1473         return 0;
1474 }
1475
1476 static void remove_networks(struct connman_device *device,
1477                                 struct wifi_data *wifi)
1478 {
1479         GSList *list;
1480
1481         for (list = wifi->networks; list; list = list->next) {
1482                 struct connman_network *network = list->data;
1483
1484                 connman_device_remove_network(device, network);
1485                 connman_network_unref(network);
1486         }
1487
1488         g_slist_free(wifi->networks);
1489         wifi->networks = NULL;
1490 }
1491
1492 static void remove_peers(struct wifi_data *wifi)
1493 {
1494         GSList *list;
1495
1496         for (list = wifi->peers; list; list = list->next) {
1497                 struct connman_peer *peer = list->data;
1498
1499                 connman_peer_unregister(peer);
1500                 connman_peer_unref(peer);
1501         }
1502
1503         g_slist_free(wifi->peers);
1504         wifi->peers = NULL;
1505 }
1506
1507 static void reset_autoscan(struct connman_device *device)
1508 {
1509         struct wifi_data *wifi = connman_device_get_data(device);
1510         struct autoscan_params *autoscan;
1511
1512         DBG("");
1513
1514         if (!wifi || !wifi->autoscan)
1515                 return;
1516
1517         autoscan = wifi->autoscan;
1518
1519         autoscan->interval = 0;
1520
1521         if (autoscan->timeout == 0)
1522                 return;
1523
1524         g_source_remove(autoscan->timeout);
1525         autoscan->timeout = 0;
1526
1527         connman_device_unref(device);
1528 }
1529
1530 static void stop_autoscan(struct connman_device *device)
1531 {
1532         const struct wifi_data *wifi = connman_device_get_data(device);
1533
1534         if (!wifi || !wifi->autoscan)
1535                 return;
1536
1537         reset_autoscan(device);
1538
1539         connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_WIFI, false);
1540 }
1541
1542 static void check_p2p_technology(void)
1543 {
1544         bool p2p_exists = false;
1545         GList *list;
1546
1547         for (list = iface_list; list; list = list->next) {
1548                 struct wifi_data *w = list->data;
1549
1550                 if (w->interface &&
1551                                 g_supplicant_interface_has_p2p(w->interface))
1552                         p2p_exists = true;
1553         }
1554
1555         if (!p2p_exists) {
1556                 connman_technology_driver_unregister(&p2p_tech_driver);
1557                 connman_peer_driver_unregister(&peer_driver);
1558         }
1559 }
1560
1561 struct last_connected {
1562         GTimeVal modified;
1563         gchar *ssid;
1564         int freq;
1565 };
1566
1567 static gint sort_entry(gconstpointer a, gconstpointer b, gpointer user_data)
1568 {
1569         GTimeVal *aval = (GTimeVal *)a;
1570         GTimeVal *bval = (GTimeVal *)b;
1571
1572         /* Note that the sort order is descending */
1573         if (aval->tv_sec < bval->tv_sec)
1574                 return 1;
1575
1576         if (aval->tv_sec > bval->tv_sec)
1577                 return -1;
1578
1579         return 0;
1580 }
1581
1582 static void free_entry(gpointer data)
1583 {
1584         struct last_connected *entry = data;
1585
1586         g_free(entry->ssid);
1587         g_free(entry);
1588 }
1589
1590 static void wifi_remove(struct connman_device *device)
1591 {
1592         struct wifi_data *wifi = connman_device_get_data(device);
1593
1594         DBG("device %p wifi %p", device, wifi);
1595
1596         if (!wifi)
1597                 return;
1598
1599         stop_autoscan(device);
1600
1601         if (wifi->p2p_device)
1602                 p2p_iface_list = g_list_remove(p2p_iface_list, wifi);
1603         else
1604                 iface_list = g_list_remove(iface_list, wifi);
1605
1606         check_p2p_technology();
1607 #if defined TIZEN_EXT_WIFI_MESH
1608         check_mesh_technology();
1609 #endif
1610
1611         remove_pending_wifi_device(wifi);
1612
1613         if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_P2P)) {
1614                 g_source_remove(wifi->p2p_find_timeout);
1615                 connman_device_unref(wifi->device);
1616         }
1617
1618         if (wifi->p2p_connection_timeout)
1619                 g_source_remove(wifi->p2p_connection_timeout);
1620
1621 #if defined TIZEN_EXT
1622         if (wifi->automaxspeed_timeout != 0) {
1623                 g_source_remove(wifi->automaxspeed_timeout);
1624                 wifi->automaxspeed_timeout = 0;
1625         }
1626 #endif
1627
1628         remove_networks(device, wifi);
1629         remove_peers(wifi);
1630
1631         connman_device_set_powered(device, false);
1632         connman_device_set_data(device, NULL);
1633         connman_device_unref(wifi->device);
1634         connman_rtnl_remove_watch(wifi->watch);
1635
1636         g_supplicant_interface_set_data(wifi->interface, NULL);
1637
1638         g_supplicant_interface_cancel(wifi->interface);
1639
1640         if (wifi->scan_params)
1641                 g_supplicant_free_scan_params(wifi->scan_params);
1642 #if defined TIZEN_EXT
1643         if (wifi->hidden_scan_params) {
1644                 while (wifi->hidden_scan_params->ssids) {
1645                         struct scan_ssid *ssid;
1646                         ssid = wifi->hidden_scan_params->ssids->data;
1647                         wifi->hidden_scan_params->ssids = g_slist_remove(wifi->hidden_scan_params->ssids, ssid);
1648                 }
1649                 g_supplicant_free_scan_params(wifi->hidden_scan_params);
1650         }
1651 #endif
1652
1653         g_free(wifi->autoscan);
1654         g_free(wifi->identifier);
1655         g_free(wifi);
1656 }
1657
1658 static bool is_duplicate(GSList *list, gchar *ssid, int ssid_len)
1659 {
1660         GSList *iter;
1661
1662         for (iter = list; iter; iter = g_slist_next(iter)) {
1663                 struct scan_ssid *scan_ssid = iter->data;
1664
1665                 if (ssid_len == scan_ssid->ssid_len &&
1666                                 memcmp(ssid, scan_ssid->ssid, ssid_len) == 0)
1667                         return true;
1668         }
1669
1670         return false;
1671 }
1672
1673 static int add_scan_param(gchar *hex_ssid, char *raw_ssid, int ssid_len,
1674                         int freq, GSupplicantScanParams *scan_data,
1675                         int driver_max_scan_ssids, char *ssid_name)
1676 {
1677         unsigned int i;
1678         struct scan_ssid *scan_ssid;
1679
1680         if ((driver_max_scan_ssids == 0 ||
1681                         driver_max_scan_ssids > scan_data->num_ssids) &&
1682                         (hex_ssid || raw_ssid)) {
1683                 gchar *ssid;
1684                 unsigned int j = 0, hex;
1685
1686                 if (hex_ssid) {
1687                         size_t hex_ssid_len = strlen(hex_ssid);
1688
1689                         ssid = g_try_malloc0(hex_ssid_len / 2);
1690                         if (!ssid)
1691                                 return -ENOMEM;
1692
1693                         for (i = 0; i < hex_ssid_len; i += 2) {
1694                                 sscanf(hex_ssid + i, "%02x", &hex);
1695                                 ssid[j++] = hex;
1696                         }
1697                 } else {
1698                         ssid = raw_ssid;
1699                         j = ssid_len;
1700                 }
1701
1702                 /*
1703                  * If we have already added hidden AP to the list,
1704                  * then do not do it again. This might happen if you have
1705                  * used or are using multiple wifi cards, so in that case
1706                  * you might have multiple service files for same AP.
1707                  */
1708                 if (is_duplicate(scan_data->ssids, ssid, j)) {
1709                         if (hex_ssid)
1710                                 g_free(ssid);
1711                         return 0;
1712                 }
1713
1714                 scan_ssid = g_try_new(struct scan_ssid, 1);
1715                 if (!scan_ssid) {
1716                         if (hex_ssid)
1717                                 g_free(ssid);
1718                         return -ENOMEM;
1719                 }
1720
1721                 memcpy(scan_ssid->ssid, ssid, j);
1722                 scan_ssid->ssid_len = j;
1723                 scan_data->ssids = g_slist_prepend(scan_data->ssids,
1724                                                                 scan_ssid);
1725
1726                 scan_data->num_ssids++;
1727
1728                 DBG("SSID %s added to scanned list of %d entries", ssid_name,
1729                                                         scan_data->num_ssids);
1730
1731                 if (hex_ssid)
1732                         g_free(ssid);
1733         } else
1734                 return -EINVAL;
1735
1736         scan_data->ssids = g_slist_reverse(scan_data->ssids);
1737
1738         if (!scan_data->freqs) {
1739                 scan_data->freqs = g_try_malloc0(sizeof(uint16_t));
1740                 if (!scan_data->freqs) {
1741                         g_slist_free_full(scan_data->ssids, g_free);
1742                         return -ENOMEM;
1743                 }
1744
1745                 scan_data->num_freqs = 1;
1746                 scan_data->freqs[0] = freq;
1747         } else {
1748                 bool duplicate = false;
1749
1750                 /* Don't add duplicate entries */
1751                 for (i = 0; i < scan_data->num_freqs; i++) {
1752                         if (scan_data->freqs[i] == freq) {
1753                                 duplicate = true;
1754                                 break;
1755                         }
1756                 }
1757
1758                 if (!duplicate) {
1759                         scan_data->num_freqs++;
1760                         scan_data->freqs = g_try_realloc(scan_data->freqs,
1761                                 sizeof(uint16_t) * scan_data->num_freqs);
1762                         if (!scan_data->freqs) {
1763                                 g_slist_free_full(scan_data->ssids, g_free);
1764                                 return -ENOMEM;
1765                         }
1766                         scan_data->freqs[scan_data->num_freqs - 1] = freq;
1767                 }
1768         }
1769
1770         return 1;
1771 }
1772
1773 static int get_hidden_connections(GSupplicantScanParams *scan_data)
1774 {
1775         struct connman_config_entry **entries;
1776         GKeyFile *keyfile;
1777 #if defined TIZEN_EXT
1778         gchar **services = NULL;
1779 #else
1780         gchar **services;
1781 #endif /* defined TIZEN_EXT */
1782         char *ssid, *name;
1783         int i, ret;
1784         bool value;
1785         int num_ssids = 0, add_param_failed = 0;
1786 #if defined TIZEN_EXT
1787         GSequenceIter *iter;
1788         GSequence *latest_list;
1789         struct last_connected *entry;
1790         GTimeVal modified;
1791
1792         latest_list = g_sequence_new(free_entry);
1793         if (!latest_list)
1794                 goto out;
1795 #endif
1796         services = connman_storage_get_services();
1797         for (i = 0; services && services[i]; i++) {
1798                 if (strncmp(services[i], "wifi_", 5) != 0)
1799                         continue;
1800
1801                 keyfile = connman_storage_load_service(services[i]);
1802                 if (!keyfile)
1803                         continue;
1804
1805                 value = g_key_file_get_boolean(keyfile,
1806                                         services[i], "Hidden", NULL);
1807                 if (!value) {
1808                         g_key_file_free(keyfile);
1809                         continue;
1810                 }
1811
1812                 value = g_key_file_get_boolean(keyfile,
1813                                         services[i], "Favorite", NULL);
1814                 if (!value) {
1815                         g_key_file_free(keyfile);
1816                         continue;
1817                 }
1818
1819 #if defined TIZEN_EXT
1820                 value = g_key_file_get_boolean(keyfile,
1821                                         services[i], "AutoConnect", NULL);
1822                 if (!value) {
1823                         g_key_file_free(keyfile);
1824                         continue;
1825                 }
1826
1827                 gchar *str = g_key_file_get_string(keyfile,
1828                                         services[i], "Modified", NULL);
1829                 if (!str) {
1830                         g_key_file_free(keyfile);
1831                         continue;
1832                 }
1833                 g_time_val_from_iso8601(str, &modified);
1834                 g_free(str);
1835 #endif
1836
1837                 ssid = g_key_file_get_string(keyfile,
1838                                         services[i], "SSID", NULL);
1839
1840                 name = g_key_file_get_string(keyfile, services[i], "Name",
1841                                                                 NULL);
1842
1843 #if defined TIZEN_EXT
1844                 entry = g_try_new(struct last_connected, 1);
1845                 if (!entry) {
1846                         g_sequence_free(latest_list);
1847                         g_free(ssid);
1848                         g_free(name);
1849                         g_key_file_free(keyfile);
1850                         goto out;
1851                 }
1852
1853                 entry->modified = modified;
1854                 entry->ssid = ssid;
1855
1856                 g_sequence_insert_sorted(latest_list, entry,
1857                                 sort_entry, NULL);
1858 #else
1859                 ret = add_scan_param(ssid, NULL, 0, 0, scan_data, 0, name);
1860                 if (ret < 0)
1861                         add_param_failed++;
1862                 else if (ret > 0)
1863                         num_ssids++;
1864
1865                 g_free(ssid);
1866 #endif
1867                 g_free(name);
1868                 g_key_file_free(keyfile);
1869         }
1870
1871 #if defined TIZEN_EXT
1872         gint length = g_sequence_get_length(latest_list);
1873         iter = g_sequence_get_begin_iter(latest_list);
1874
1875         for (i = 0; i < length; i++) {
1876                 entry = g_sequence_get(iter);
1877
1878                 ret = add_scan_param(entry->ssid, NULL, 0, 0, scan_data, 0, entry->ssid);
1879                 if (ret < 0)
1880                         add_param_failed++;
1881                 else if (ret > 0)
1882                         num_ssids++;
1883
1884                 iter = g_sequence_iter_next(iter);
1885         }
1886
1887         g_sequence_free(latest_list);
1888 out:
1889 #endif
1890         /*
1891          * Check if there are any hidden AP that needs to be provisioned.
1892          */
1893         entries = connman_config_get_entries("wifi");
1894         for (i = 0; entries && entries[i]; i++) {
1895                 int len;
1896
1897                 if (!entries[i]->hidden)
1898                         continue;
1899
1900                 if (!entries[i]->ssid) {
1901                         ssid = entries[i]->name;
1902                         len = strlen(ssid);
1903                 } else {
1904                         ssid = entries[i]->ssid;
1905                         len = entries[i]->ssid_len;
1906                 }
1907
1908                 if (!ssid)
1909                         continue;
1910
1911                 ret = add_scan_param(NULL, ssid, len, 0, scan_data, 0, ssid);
1912                 if (ret < 0)
1913                         add_param_failed++;
1914                 else if (ret > 0)
1915                         num_ssids++;
1916         }
1917
1918         connman_config_free_entries(entries);
1919
1920         if (add_param_failed > 0)
1921                 DBG("Unable to scan %d out of %d SSIDs",
1922                                         add_param_failed, num_ssids);
1923
1924         g_strfreev(services);
1925
1926         return num_ssids;
1927 }
1928
1929 static int get_hidden_connections_params(struct wifi_data *wifi,
1930                                         GSupplicantScanParams *scan_params)
1931 {
1932         int driver_max_ssids, i;
1933         GSupplicantScanParams *orig_params;
1934
1935         /*
1936          * Scan hidden networks so that we can autoconnect to them.
1937          * We will assume 1 as a default number of ssid to scan.
1938          */
1939         driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
1940                                                         wifi->interface);
1941         if (driver_max_ssids == 0)
1942                 driver_max_ssids = 1;
1943
1944         DBG("max ssids %d", driver_max_ssids);
1945
1946 #if defined TIZEN_EXT
1947         if (!wifi->hidden_scan_params) {
1948                 wifi->hidden_scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
1949                 if (!wifi->hidden_scan_params)
1950                         return 0;
1951
1952                 if (get_hidden_connections(wifi->hidden_scan_params) == 0) {
1953                         g_supplicant_free_scan_params(wifi->hidden_scan_params);
1954                         wifi->hidden_scan_params = NULL;
1955
1956                         return 0;
1957                 }
1958         }
1959
1960         orig_params = wifi->hidden_scan_params;
1961 #else
1962         if (!wifi->scan_params) {
1963                 wifi->scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
1964                 if (!wifi->scan_params)
1965                         return 0;
1966
1967                 if (get_hidden_connections(wifi->scan_params) == 0) {
1968                         g_supplicant_free_scan_params(wifi->scan_params);
1969                         wifi->scan_params = NULL;
1970
1971                         return 0;
1972                 }
1973         }
1974
1975         orig_params = wifi->scan_params;
1976 #endif
1977
1978         /* Let's transfer driver_max_ssids params */
1979         for (i = 0; i < driver_max_ssids; i++) {
1980                 struct scan_ssid *ssid;
1981
1982 #if defined TIZEN_EXT
1983                 if (!wifi->hidden_scan_params->ssids)
1984 #else
1985                 if (!wifi->scan_params->ssids)
1986 #endif
1987                         break;
1988
1989                 ssid = orig_params->ssids->data;
1990                 orig_params->ssids = g_slist_remove(orig_params->ssids, ssid);
1991                 scan_params->ssids = g_slist_prepend(scan_params->ssids, ssid);
1992         }
1993
1994         if (i > 0) {
1995                 scan_params->num_ssids = i;
1996                 scan_params->ssids = g_slist_reverse(scan_params->ssids);
1997
1998                 scan_params->freqs = g_memdup(orig_params->freqs,
1999                                 sizeof(uint16_t) * orig_params->num_freqs);
2000                 if (!scan_params->freqs)
2001                         goto err;
2002
2003                 scan_params->num_freqs = orig_params->num_freqs;
2004
2005         } else
2006                 goto err;
2007
2008         orig_params->num_ssids -= scan_params->num_ssids;
2009
2010         return scan_params->num_ssids;
2011
2012 err:
2013         g_slist_free_full(scan_params->ssids, g_free);
2014 #if defined TIZEN_EXT
2015         g_supplicant_free_scan_params(wifi->hidden_scan_params);
2016         wifi->hidden_scan_params = NULL;
2017 #else
2018         g_supplicant_free_scan_params(wifi->scan_params);
2019         wifi->scan_params = NULL;
2020 #endif
2021
2022         return 0;
2023 }
2024
2025 static int throw_wifi_scan(struct connman_device *device,
2026                         GSupplicantInterfaceCallback callback)
2027 {
2028         struct wifi_data *wifi = connman_device_get_data(device);
2029         int ret;
2030
2031         if (!wifi)
2032                 return -ENODEV;
2033
2034         DBG("device %p %p", device, wifi->interface);
2035
2036         if (wifi->tethering)
2037                 return -EBUSY;
2038
2039 #if defined TIZEN_EXT
2040         if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI)
2041             && !wifi->allow_full_scan)
2042 #else
2043         if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI))
2044 #endif
2045                 return -EALREADY;
2046
2047         connman_device_ref(device);
2048
2049         ret = g_supplicant_interface_scan(wifi->interface, NULL,
2050                                                 callback, device);
2051         if (ret == 0) {
2052                 connman_device_set_scanning(device,
2053                                 CONNMAN_SERVICE_TYPE_WIFI, true);
2054         } else
2055                 connman_device_unref(device);
2056
2057         return ret;
2058 }
2059
2060 static void hidden_free(struct hidden_params *hidden)
2061 {
2062         if (!hidden)
2063                 return;
2064
2065         if (hidden->scan_params)
2066                 g_supplicant_free_scan_params(hidden->scan_params);
2067         g_free(hidden->identity);
2068         g_free(hidden->passphrase);
2069         g_free(hidden->security);
2070         g_free(hidden);
2071 }
2072
2073 #if defined TIZEN_EXT
2074 static void service_state_changed(struct connman_service *service,
2075                                         enum connman_service_state state);
2076
2077 static int network_connect(struct connman_network *network);
2078
2079 static struct connman_notifier notifier = {
2080         .name                   = "wifi",
2081         .priority               = CONNMAN_NOTIFIER_PRIORITY_DEFAULT,
2082         .service_state_changed  = service_state_changed,
2083 };
2084
2085 static void service_state_changed(struct connman_service *service,
2086                                         enum connman_service_state state)
2087 {
2088         enum connman_service_type type;
2089
2090         type = connman_service_get_type(service);
2091         if (type != CONNMAN_SERVICE_TYPE_WIFI)
2092                 return;
2093
2094         DBG("service %p state %d", service, state);
2095
2096         switch (state) {
2097         case CONNMAN_SERVICE_STATE_READY:
2098         case CONNMAN_SERVICE_STATE_ONLINE:
2099         case CONNMAN_SERVICE_STATE_FAILURE:
2100                 connman_notifier_unregister(&notifier);
2101                 is_wifi_notifier_registered = FALSE;
2102
2103                 __connman_device_request_scan(type);
2104                 break;
2105
2106         default:
2107                 break;
2108         }
2109 }
2110
2111 static gboolean need_bss_transition(uint16_t freq, int snr, int strength)
2112 {
2113         /*
2114          * Since bssid->strength is a positive value,
2115          * it need to be changed to its original value.
2116          */
2117         int signal = strength - 120;
2118
2119         /*
2120          * If the currently connected AP matches the following conditions,
2121          * scan for BSS transition is started.
2122          *   - SNR is less than 20 or RSSI level is less than 3
2123          */
2124         if (snr < 20 && snr != 0)
2125                 return TRUE;
2126         else if (freq > 4900 && signal <= RSSI_LEVEL_2_5G)
2127                 return TRUE;
2128         else if (freq <= 4900 && signal <= RSSI_LEVEL_2_24G)
2129                 return TRUE;
2130
2131         return FALSE;
2132 }
2133
2134 static gboolean check_bss_condition(uint16_t freq, int snr, uint16_t strength)
2135 {
2136         /*
2137          * Since bssid->strength is a positive value,
2138          * it need to be changed to its original value.
2139          */
2140         int signal = strength - 120;
2141
2142         /*
2143          * If the AP that matches the following conditions exists in the SCAN result,
2144          * BSS transition is started.
2145          *   - SNR is 25 or more and RSSI level is greater than 3
2146          */
2147         if (snr < 25 && snr != 0)
2148                 return FALSE;
2149
2150         if (freq > 4900 && signal > RSSI_LEVEL_3_5G)
2151                 return TRUE;
2152         else if (freq <= 4900 && signal > RSSI_LEVEL_3_24G)
2153                 return TRUE;
2154
2155         return FALSE;
2156 }
2157
2158 static void scan_callback_hidden(int result,
2159                         GSupplicantInterface *interface, void *user_data);
2160
2161 static int network_disconnect(struct connman_network *network);
2162 #endif
2163
2164 static void scan_callback(int result, GSupplicantInterface *interface,
2165                                                 void *user_data)
2166 {
2167         struct connman_device *device = user_data;
2168         struct wifi_data *wifi = connman_device_get_data(device);
2169         bool scanning;
2170 #if defined TIZEN_EXT
2171         bool roaming_needed = false;
2172         bool roaming_ap_found = false;
2173         GSList *list = NULL;
2174         GSList *bssid_list = NULL;
2175         bool favorite_exists = false;
2176         struct connman_network *network = NULL;
2177         struct connman_service *service = NULL;
2178 #endif
2179
2180         DBG("result %d wifi %p", result, wifi);
2181
2182         if (wifi) {
2183                 if (wifi->hidden && !wifi->postpone_hidden) {
2184                         connman_network_clear_hidden(wifi->hidden->user_data);
2185                         hidden_free(wifi->hidden);
2186                         wifi->hidden = NULL;
2187                 }
2188
2189                 if (wifi->scan_params) {
2190                         g_supplicant_free_scan_params(wifi->scan_params);
2191                         wifi->scan_params = NULL;
2192                 }
2193
2194 #if defined TIZEN_EXT
2195                 if (wifi->hidden_scan_params && !wifi->hidden_scan_params->ssids) {
2196                         g_supplicant_free_scan_params(wifi->hidden_scan_params);
2197                         wifi->hidden_scan_params = NULL;
2198                 }
2199 #endif
2200         }
2201
2202         if (result < 0)
2203                 connman_device_reset_scanning(device);
2204
2205         /* User is connecting to a hidden AP, let's wait for finished event */
2206         if (wifi && wifi->hidden && wifi->postpone_hidden) {
2207                 GSupplicantScanParams *scan_params;
2208                 int ret;
2209
2210                 wifi->postpone_hidden = false;
2211                 scan_params = wifi->hidden->scan_params;
2212                 wifi->hidden->scan_params = NULL;
2213
2214                 reset_autoscan(device);
2215
2216                 ret = g_supplicant_interface_scan(wifi->interface, scan_params,
2217                                                         scan_callback, device);
2218                 if (ret == 0)
2219                         return;
2220
2221                 /* On error, let's recall scan_callback, which will cleanup */
2222                 return scan_callback(ret, interface, user_data);
2223         }
2224
2225 #if defined TIZEN_EXT
2226         if (wifi) {
2227                 for (list = wifi->networks; list; list = list->next) {
2228                         network = list->data;
2229                         service = connman_service_lookup_from_network(network);
2230
2231                         if (service != NULL &&
2232                                 (connman_service_get_favorite(service) == true) &&
2233                                 (connman_service_get_autoconnect(service) == true)) {
2234                                 DBG("Favorite service exists [%s]",
2235                                                 connman_network_get_string(network, "Name"));
2236                                 favorite_exists = true;
2237                                 break;
2238                         }
2239                 }
2240         }
2241
2242         if (favorite_exists == false) {
2243                 if (wifi && wifi->allow_full_scan) {
2244                         int ret;
2245                         DBG("Trigger full channel scan");
2246                         wifi->allow_full_scan = false;
2247
2248                         ret = g_supplicant_interface_scan(wifi->interface, NULL,
2249                                                                 scan_callback_hidden, device);
2250                         if (ret == 0)
2251                                 return;
2252
2253                         /* On error, let's recall scan_callback, which will cleanup */
2254                         return scan_callback(ret, interface, user_data);
2255                 }
2256         } else
2257                 wifi->allow_full_scan = false;
2258 #endif
2259
2260         scanning = connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI);
2261
2262         if (scanning) {
2263                 connman_device_set_scanning(device,
2264                                 CONNMAN_SERVICE_TYPE_WIFI, false);
2265         }
2266
2267         if (result != -ENOLINK)
2268 #if defined TIZEN_EXT
2269         if (result != -EIO)
2270 #endif
2271                 start_autoscan(device);
2272
2273         /*
2274          * If we are here then we were scanning; however, if we are
2275          * also mid-flight disabling the interface, then wifi_disable
2276          * has already cleared the device scanning state and
2277          * unreferenced the device, obviating the need to do it here.
2278          */
2279
2280         if (scanning)
2281                 connman_device_unref(device);
2282
2283 #if defined TIZEN_EXT
2284         if (wifi && wifi->scan_pending_network && result != -EIO) {
2285                 network_connect(wifi->scan_pending_network);
2286                 wifi->scan_pending_network = NULL;
2287                 connman_network_set_connecting(wifi->network);
2288         } else if (connman_setting_get_bool("WifiRoaming") && wifi->network) {
2289                 bssid_list = connman_network_get_bssid_list(wifi->network);
2290
2291                 if (g_slist_length(bssid_list) <= 1)
2292                         goto done;
2293
2294                 if (!connman_network_get_connected(wifi->network))
2295                         goto done;
2296
2297                 if (connman_network_get_bool(wifi->network, "WiFi.Roaming"))
2298                         goto done;
2299
2300                 if (!need_bss_transition(
2301                                 connman_network_get_frequency(wifi->network),
2302                                 connman_network_get_snr(wifi->network),
2303                                 connman_network_get_strength(wifi->network)))
2304                         goto done;
2305
2306                 for (bssid_list; bssid_list; bssid_list = bssid_list->next) {
2307                         struct g_connman_bssids *bssid = bssid_list->data;
2308
2309                         if (check_bss_condition(bssid->frequency,
2310                                         bssid->score_snr, bssid->strength))
2311                                 roaming_ap_found = true;
2312                 }
2313
2314                 if (roaming_ap_found) {
2315                         char bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
2316                         char *bssid_str = bssid_buff;
2317                         unsigned char *bssid;
2318
2319                         bssid = connman_network_get_bssid(wifi->network);
2320                         snprintf(bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bssid));
2321                         connman_network_set_string(wifi->network,
2322                                         "WiFi.RoamingCurBSSID", bssid_str);
2323
2324                         network_disconnect(wifi->network);
2325                         wifi->pending_network = wifi->network;
2326                         connman_network_set_bool(wifi->network, "WiFi.Roaming", true);
2327                 }
2328         }
2329
2330 done:
2331         if (is_wifi_notifier_registered != true &&
2332                         wifi_first_scan == true && found_with_first_scan == true) {
2333                 wifi_first_scan = false;
2334                 found_with_first_scan = false;
2335
2336                 connman_notifier_register(&notifier);
2337                 is_wifi_notifier_registered = true;
2338         }
2339 #endif
2340 }
2341
2342 static void scan_callback_hidden(int result,
2343                         GSupplicantInterface *interface, void *user_data)
2344 {
2345         struct connman_device *device = user_data;
2346         struct wifi_data *wifi = connman_device_get_data(device);
2347         GSupplicantScanParams *scan_params;
2348         int ret;
2349
2350         DBG("result %d wifi %p", result, wifi);
2351
2352         if (!wifi)
2353                 goto out;
2354
2355         /* User is trying to connect to a hidden AP */
2356         if (wifi->hidden && wifi->postpone_hidden)
2357                 goto out;
2358
2359         scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
2360         if (!scan_params)
2361                 goto out;
2362
2363         if (get_hidden_connections_params(wifi, scan_params) > 0) {
2364                 ret = g_supplicant_interface_scan(wifi->interface,
2365                                                         scan_params,
2366 #if defined TIZEN_EXT
2367                                                         scan_callback,
2368 #else
2369                                                         scan_callback_hidden,
2370 #endif
2371                                                         device);
2372                 if (ret == 0)
2373                         return;
2374         }
2375
2376         g_supplicant_free_scan_params(scan_params);
2377
2378 out:
2379         scan_callback(result, interface, user_data);
2380 }
2381
2382 static gboolean autoscan_timeout(gpointer data)
2383 {
2384         struct connman_device *device = data;
2385         struct wifi_data *wifi = connman_device_get_data(device);
2386         struct autoscan_params *autoscan;
2387         int interval;
2388
2389         if (!wifi)
2390                 return FALSE;
2391
2392         autoscan = wifi->autoscan;
2393
2394 #if defined TIZEN_EXT
2395         if (!autoscan)
2396                 return FALSE;
2397 #endif
2398
2399         if (autoscan->interval <= 0) {
2400                 interval = autoscan->base;
2401                 goto set_interval;
2402         } else
2403                 interval = autoscan->interval * autoscan->base;
2404
2405 #if defined TIZEN_EXT
2406         if (autoscan->interval >= autoscan->limit)
2407 #else
2408         if (interval > autoscan->limit)
2409 #endif
2410                 interval = autoscan->limit;
2411
2412         throw_wifi_scan(wifi->device, scan_callback_hidden);
2413
2414         /*
2415          * In case BackgroundScanning is disabled, interval will reach the
2416          * limit exactly after the very first passive scanning. It allows
2417          * to ensure at most one passive scan is performed in such cases.
2418          */
2419         if (!connman_setting_get_bool("BackgroundScanning") &&
2420                                         interval == autoscan->limit) {
2421                 g_source_remove(autoscan->timeout);
2422                 autoscan->timeout = 0;
2423
2424                 connman_device_unref(device);
2425
2426                 return FALSE;
2427         }
2428
2429 set_interval:
2430         DBG("interval %d", interval);
2431
2432         autoscan->interval = interval;
2433
2434         autoscan->timeout = g_timeout_add_seconds(interval,
2435                                                 autoscan_timeout, device);
2436
2437         return FALSE;
2438 }
2439
2440 static void start_autoscan(struct connman_device *device)
2441 {
2442         struct wifi_data *wifi = connman_device_get_data(device);
2443         struct autoscan_params *autoscan;
2444
2445         DBG("");
2446
2447         if (!wifi)
2448                 return;
2449
2450         if (wifi->p2p_device)
2451                 return;
2452
2453         if (wifi->connected)
2454                 return;
2455
2456         autoscan = wifi->autoscan;
2457         if (!autoscan)
2458                 return;
2459
2460         if (autoscan->timeout > 0 || autoscan->interval > 0)
2461                 return;
2462
2463         connman_device_ref(device);
2464
2465         autoscan_timeout(device);
2466 }
2467
2468 static struct autoscan_params *parse_autoscan_params(const char *params)
2469 {
2470         struct autoscan_params *autoscan;
2471         char **list_params;
2472         int limit;
2473         int base;
2474
2475         DBG("");
2476
2477         list_params = g_strsplit(params, ":", 0);
2478         if (list_params == 0)
2479                 return NULL;
2480
2481         if (!g_strcmp0(list_params[0], "exponential") &&
2482                                 g_strv_length(list_params) == 3) {
2483                 base = atoi(list_params[1]);
2484                 limit = atoi(list_params[2]);
2485         } else if (!g_strcmp0(list_params[0], "single") &&
2486                                 g_strv_length(list_params) == 2)
2487                 base = limit = atoi(list_params[1]);
2488         else {
2489                 g_strfreev(list_params);
2490                 return NULL;
2491         }
2492
2493         DBG("Setup %s autoscanning", list_params[0]);
2494
2495         g_strfreev(list_params);
2496
2497         autoscan = g_try_malloc0(sizeof(struct autoscan_params));
2498         if (!autoscan) {
2499                 DBG("Could not allocate memory for autoscan");
2500                 return NULL;
2501         }
2502
2503         DBG("base %d - limit %d", base, limit);
2504         autoscan->base = base;
2505         autoscan->limit = limit;
2506
2507         return autoscan;
2508 }
2509
2510 static void setup_autoscan(struct wifi_data *wifi)
2511 {
2512         /*
2513          * If BackgroundScanning is enabled, setup exponential
2514          * autoscanning if it has not been previously done.
2515          */
2516         if (connman_setting_get_bool("BackgroundScanning")) {
2517                 wifi->autoscan = parse_autoscan_params(AUTOSCAN_EXPONENTIAL);
2518                 return;
2519         }
2520 #if defined TIZEN_EXT
2521         else {
2522                 if (wifi->autoscan) {
2523                         g_free(wifi->autoscan);
2524                         wifi->autoscan = NULL;
2525                 }
2526
2527                 DBG("BackgroundScanning is disabled");
2528
2529                 return;
2530         }
2531 #else
2532
2533         /*
2534          * On the contrary, if BackgroundScanning is disabled, update autoscan
2535          * parameters based on the type of scanning that is being performed.
2536          */
2537         if (wifi->autoscan) {
2538                 g_free(wifi->autoscan);
2539                 wifi->autoscan = NULL;
2540         }
2541
2542         switch (wifi->scanning_type) {
2543         case WIFI_SCANNING_PASSIVE:
2544                 /* Do not setup autoscan. */
2545                 break;
2546         case WIFI_SCANNING_ACTIVE:
2547                 /* Setup one single passive scan after active. */
2548                 wifi->autoscan = parse_autoscan_params(AUTOSCAN_SINGLE);
2549                 break;
2550         case WIFI_SCANNING_UNKNOWN:
2551                 /* Setup autoscan in this case but we should never fall here. */
2552                 wifi->autoscan = parse_autoscan_params(AUTOSCAN_SINGLE);
2553                 break;
2554         }
2555 #endif
2556 }
2557
2558 static void finalize_interface_creation(struct wifi_data *wifi)
2559 {
2560         DBG("interface is ready wifi %p tethering %d", wifi, wifi->tethering);
2561
2562         if (!wifi->device) {
2563                 connman_error("WiFi device not set");
2564                 return;
2565         }
2566
2567         connman_device_set_powered(wifi->device, true);
2568
2569         if (wifi->p2p_device)
2570                 return;
2571
2572         if (!wifi->autoscan)
2573                 setup_autoscan(wifi);
2574
2575         start_autoscan(wifi->device);
2576 }
2577
2578 static void interface_create_callback(int result,
2579                                         GSupplicantInterface *interface,
2580                                                         void *user_data)
2581 {
2582         struct wifi_data *wifi = user_data;
2583
2584         DBG("result %d ifname %s, wifi %p", result,
2585                                 g_supplicant_interface_get_ifname(interface),
2586                                 wifi);
2587
2588         if (result < 0 || !wifi)
2589                 return;
2590
2591         wifi->interface = interface;
2592         g_supplicant_interface_set_data(interface, wifi);
2593
2594         if (g_supplicant_interface_get_ready(interface)) {
2595                 wifi->interface_ready = true;
2596                 finalize_interface_creation(wifi);
2597         }
2598 }
2599
2600 static int wifi_enable(struct connman_device *device)
2601 {
2602         struct wifi_data *wifi = connman_device_get_data(device);
2603         int index;
2604         char *interface;
2605         const char *driver = connman_option_get_string("wifi");
2606         int ret;
2607
2608         DBG("device %p %p", device, wifi);
2609
2610         index = connman_device_get_index(device);
2611         if (!wifi || index < 0)
2612                 return -ENODEV;
2613
2614         if (is_p2p_connecting())
2615                 return -EINPROGRESS;
2616
2617         interface = connman_inet_ifname(index);
2618         ret = g_supplicant_interface_create(interface, driver, NULL,
2619 #ifdef TIZEN_EXT
2620                         connman_device_get_mac_policy(device),
2621                         connman_device_get_preassoc_mac_policy(device),
2622                         connman_device_get_random_mac_lifetime(device),
2623 #endif /* TIZEN_EXT */
2624                                                 interface_create_callback,
2625                                                         wifi);
2626         g_free(interface);
2627
2628         if (ret < 0)
2629                 return ret;
2630
2631         return -EINPROGRESS;
2632 }
2633
2634 static int wifi_disable(struct connman_device *device)
2635 {
2636         struct wifi_data *wifi = connman_device_get_data(device);
2637         int ret;
2638
2639         DBG("device %p wifi %p", device, wifi);
2640
2641         if (!wifi)
2642                 return -ENODEV;
2643
2644         wifi->connected = false;
2645         wifi->disconnecting = false;
2646
2647         if (wifi->pending_network)
2648                 wifi->pending_network = NULL;
2649
2650 #if !defined TIZEN_EXT
2651         stop_autoscan(device);
2652 #endif
2653
2654         if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_P2P)) {
2655                 g_source_remove(wifi->p2p_find_timeout);
2656                 wifi->p2p_find_timeout = 0;
2657                 connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_P2P, false);
2658                 connman_device_unref(wifi->device);
2659         }
2660
2661 #if defined TIZEN_EXT
2662         if (wifi->automaxspeed_timeout != 0) {
2663                 g_source_remove(wifi->automaxspeed_timeout);
2664                 wifi->automaxspeed_timeout = 0;
2665         }
2666 #endif
2667
2668         /* In case of a user scan, device is still referenced */
2669         if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI)) {
2670                 connman_device_set_scanning(device,
2671                                 CONNMAN_SERVICE_TYPE_WIFI, false);
2672                 connman_device_unref(wifi->device);
2673         }
2674
2675 #if defined TIZEN_EXT
2676         stop_autoscan(device);
2677 #endif
2678
2679         remove_networks(device, wifi);
2680         remove_peers(wifi);
2681
2682 #if defined TIZEN_EXT
2683         wifi->scan_pending_network = NULL;
2684
2685         if (is_wifi_notifier_registered == true) {
2686                 connman_notifier_unregister(&notifier);
2687                 is_wifi_notifier_registered = false;
2688         }
2689 #endif
2690
2691         ret = g_supplicant_interface_remove(wifi->interface, NULL, NULL);
2692         if (ret < 0)
2693                 return ret;
2694
2695         return -EINPROGRESS;
2696 }
2697
2698 static int get_latest_connections(int max_ssids,
2699                                 GSupplicantScanParams *scan_data)
2700 {
2701         GSequenceIter *iter;
2702         GSequence *latest_list;
2703         struct last_connected *entry;
2704         GKeyFile *keyfile;
2705         GTimeVal modified;
2706         gchar **services;
2707         gchar *str;
2708         char *ssid;
2709         int i, freq;
2710         int num_ssids = 0;
2711
2712         latest_list = g_sequence_new(free_entry);
2713         if (!latest_list)
2714                 return -ENOMEM;
2715
2716         services = connman_storage_get_services();
2717         for (i = 0; services && services[i]; i++) {
2718                 if (strncmp(services[i], "wifi_", 5) != 0)
2719                         continue;
2720
2721                 keyfile = connman_storage_load_service(services[i]);
2722                 if (!keyfile)
2723                         continue;
2724
2725                 str = g_key_file_get_string(keyfile,
2726                                         services[i], "Favorite", NULL);
2727                 if (!str || g_strcmp0(str, "true")) {
2728                         g_free(str);
2729                         g_key_file_free(keyfile);
2730                         continue;
2731                 }
2732                 g_free(str);
2733
2734                 str = g_key_file_get_string(keyfile,
2735                                         services[i], "AutoConnect", NULL);
2736                 if (!str || g_strcmp0(str, "true")) {
2737                         g_free(str);
2738                         g_key_file_free(keyfile);
2739                         continue;
2740                 }
2741                 g_free(str);
2742
2743                 str = g_key_file_get_string(keyfile,
2744                                         services[i], "Modified", NULL);
2745                 if (!str) {
2746                         g_key_file_free(keyfile);
2747                         continue;
2748                 }
2749                 util_iso8601_to_timeval(str, &modified);
2750                 g_free(str);
2751
2752                 ssid = g_key_file_get_string(keyfile,
2753                                         services[i], "SSID", NULL);
2754
2755                 freq = g_key_file_get_integer(keyfile, services[i],
2756                                         "Frequency", NULL);
2757                 if (freq) {
2758                         entry = g_try_new(struct last_connected, 1);
2759                         if (!entry) {
2760                                 g_sequence_free(latest_list);
2761                                 g_key_file_free(keyfile);
2762                                 g_free(ssid);
2763 #if defined TIZEN_EXT
2764                                 g_strfreev(services);
2765 #endif
2766                                 return -ENOMEM;
2767                         }
2768
2769                         entry->ssid = ssid;
2770                         entry->modified = modified;
2771                         entry->freq = freq;
2772
2773                         g_sequence_insert_sorted(latest_list, entry,
2774                                                 sort_entry, NULL);
2775                         num_ssids++;
2776                 } else
2777                         g_free(ssid);
2778
2779                 g_key_file_free(keyfile);
2780         }
2781
2782         g_strfreev(services);
2783
2784         num_ssids = num_ssids > max_ssids ? max_ssids : num_ssids;
2785
2786         iter = g_sequence_get_begin_iter(latest_list);
2787
2788         for (i = 0; i < num_ssids; i++) {
2789                 entry = g_sequence_get(iter);
2790
2791                 DBG("ssid %s freq %d modified %lu", entry->ssid, entry->freq,
2792                                                 entry->modified.tv_sec);
2793
2794                 add_scan_param(entry->ssid, NULL, 0, entry->freq, scan_data,
2795                                                 max_ssids, entry->ssid);
2796
2797                 iter = g_sequence_iter_next(iter);
2798         }
2799
2800         g_sequence_free(latest_list);
2801         return num_ssids;
2802 }
2803
2804 static void wifi_update_scanner_type(struct wifi_data *wifi,
2805                                         enum wifi_scanning_type new_type)
2806 {
2807         DBG("");
2808
2809         if (!wifi || wifi->scanning_type == new_type)
2810                 return;
2811
2812         wifi->scanning_type = new_type;
2813
2814         setup_autoscan(wifi);
2815 }
2816
2817 static int wifi_scan_simple(struct connman_device *device)
2818 {
2819         struct wifi_data *wifi = connman_device_get_data(device);
2820
2821         reset_autoscan(device);
2822
2823         /* Distinguish between devices performing passive and active scanning */
2824         if (wifi)
2825                 wifi_update_scanner_type(wifi, WIFI_SCANNING_PASSIVE);
2826
2827         return throw_wifi_scan(device, scan_callback_hidden);
2828 }
2829
2830 static gboolean p2p_find_stop(gpointer data)
2831 {
2832         struct connman_device *device = data;
2833         struct wifi_data *wifi = connman_device_get_data(device);
2834
2835         DBG("");
2836
2837         if (wifi) {
2838                 wifi->p2p_find_timeout = 0;
2839
2840                 g_supplicant_interface_p2p_stop_find(wifi->interface);
2841         }
2842
2843         connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_P2P, false);
2844
2845         connman_device_unref(device);
2846         start_autoscan(device);
2847
2848         return FALSE;
2849 }
2850
2851 static void p2p_find_callback(int result, GSupplicantInterface *interface,
2852                                                         void *user_data)
2853 {
2854         struct connman_device *device = user_data;
2855         struct wifi_data *wifi = connman_device_get_data(device);
2856
2857         DBG("result %d wifi %p", result, wifi);
2858
2859         if (!wifi)
2860                 goto error;
2861
2862         if (wifi->p2p_find_timeout) {
2863                 g_source_remove(wifi->p2p_find_timeout);
2864                 wifi->p2p_find_timeout = 0;
2865         }
2866
2867         if (result)
2868                 goto error;
2869
2870         wifi->p2p_find_timeout = g_timeout_add_seconds(P2P_FIND_TIMEOUT,
2871                                                         p2p_find_stop, device);
2872         if (!wifi->p2p_find_timeout)
2873                 goto error;
2874
2875         return;
2876 error:
2877         p2p_find_stop(device);
2878 }
2879
2880 static int p2p_find(struct connman_device *device)
2881 {
2882         struct wifi_data *wifi;
2883         int ret;
2884
2885         DBG("");
2886
2887         if (!p2p_technology)
2888                 return -ENOTSUP;
2889
2890         wifi = connman_device_get_data(device);
2891
2892         if (g_supplicant_interface_is_p2p_finding(wifi->interface))
2893                 return -EALREADY;
2894
2895         reset_autoscan(device);
2896         connman_device_ref(device);
2897
2898         ret = g_supplicant_interface_p2p_find(wifi->interface,
2899                                                 p2p_find_callback, device);
2900         if (ret) {
2901                 connman_device_unref(device);
2902                 start_autoscan(device);
2903         } else {
2904                 connman_device_set_scanning(device,
2905                                 CONNMAN_SERVICE_TYPE_P2P, true);
2906         }
2907
2908         return ret;
2909 }
2910
2911 #if defined TIZEN_EXT
2912 static void specific_scan_callback(int result, GSupplicantInterface *interface,
2913                                                 void *user_data)
2914 {
2915         struct connman_device *device = user_data;
2916         struct wifi_data *wifi = connman_device_get_data(device);
2917         bool scanning;
2918
2919         DBG("result %d wifi %p", result, wifi);
2920
2921         if (wifi && wifi->scan_params) {
2922                 g_supplicant_free_scan_params(wifi->scan_params);
2923                 wifi->scan_params = NULL;
2924         }
2925
2926         scanning = connman_device_get_scanning(device,
2927                                                CONNMAN_SERVICE_TYPE_WIFI);
2928         if (scanning) {
2929                 connman_device_set_scanning(device,
2930                                 CONNMAN_SERVICE_TYPE_WIFI, false);
2931                 connman_device_unref(device);
2932         }
2933 }
2934
2935 static int wifi_specific_scan(enum connman_service_type type,
2936                         struct connman_device *device, int scan_type,
2937                         GSList *specific_scan_list, void *user_data)
2938 {
2939         GSList *list = NULL;
2940         char *ssid = NULL;
2941         struct wifi_data *wifi = connman_device_get_data(device);
2942         GSupplicantScanParams *scan_params = NULL;
2943         struct scan_ssid *scan_ssid = NULL;
2944         bool scanning;
2945         int ret;
2946         int freq;
2947         int count = 0;
2948
2949         if (!wifi)
2950                 return -ENODEV;
2951
2952         if (wifi->p2p_device)
2953                 return 0;
2954
2955         if (type == CONNMAN_SERVICE_TYPE_P2P)
2956                 return p2p_find(device);
2957
2958         if (wifi->tethering)
2959                 return 0;
2960
2961         scanning =
2962                 connman_device_get_scanning(device,
2963                                             CONNMAN_SERVICE_TYPE_WIFI);
2964         if (scanning)
2965                 return -EALREADY;
2966
2967         DBG("scan_type: %d", scan_type);
2968         if (scan_type == CONNMAN_MULTI_SCAN_SSID) { /* ssid based scan */
2969                 scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
2970                 if (!scan_params) {
2971                         DBG("Failed to allocate memory.");
2972                         return -ENOMEM;
2973                 }
2974
2975                 for (list = specific_scan_list; list; list = list->next) {
2976                         ssid = (char *)list->data;
2977                         int ssid_len = strlen(ssid);
2978
2979                         scan_ssid = g_try_new0(struct scan_ssid, 1);
2980                         if (!scan_ssid) {
2981                                 DBG("Failed to allocate memory.");
2982                                 g_supplicant_free_scan_params(scan_params);
2983                                 return -ENOMEM;
2984                         }
2985
2986                         memcpy(scan_ssid->ssid, ssid, (ssid_len + 1));
2987                         /* DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); */
2988                         scan_ssid->ssid_len = ssid_len;
2989                         scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid);
2990                         count++;
2991                 }
2992                 scan_params->num_ssids = count;
2993
2994         } else if (scan_type == CONNMAN_MULTI_SCAN_FREQ) { /* frequency based scan */
2995
2996                 scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
2997                 if (!scan_params) {
2998                         DBG("Failed to allocate memory.");
2999                         return -ENOMEM;
3000                 }
3001
3002                 guint num_freqs = g_slist_length(specific_scan_list);
3003                 DBG("num_freqs: %d", num_freqs);
3004
3005                 scan_params->freqs = g_try_new0(uint16_t, num_freqs);
3006                 if (!scan_params->freqs) {
3007                         DBG("Failed to allocate memory.");
3008                         g_free(scan_params);
3009                         return -ENOMEM;
3010                 }
3011
3012                 count = 0;
3013                 for (list = specific_scan_list; list; list = list->next) {
3014                         freq = (int)list->data;
3015
3016                         scan_params->freqs[count] = freq;
3017                         DBG("scan_params->freqs[%d]: %d", count, scan_params->freqs[count]);
3018                         count++;
3019                 }
3020                 scan_params->num_freqs = count;
3021
3022         } else if (scan_type == CONNMAN_MULTI_SCAN_SSID_FREQ) { /* SSID & Frequency mixed scan */
3023                 int freq_count, ap_count;
3024                 scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
3025                 if (!scan_params) {
3026                         DBG("Failed to allocate memory.");
3027                         return -ENOMEM;
3028                 }
3029
3030                 guint size = g_slist_length(specific_scan_list);
3031
3032                 scan_params->freqs = g_try_new0(uint16_t, size/2);
3033                 if (!scan_params->freqs) {
3034                         DBG("Failed to allocate memory.");
3035                         g_free(scan_params);
3036                         return -ENOMEM;
3037                 }
3038
3039                 ap_count = freq_count = 0;
3040                 for (list = specific_scan_list; list; list = list->next) {
3041                         if (((connman_multi_scan_ap_s *)list->data)->flag == true) { /** ssid */
3042                                 ssid = ((connman_multi_scan_ap_s *)list->data)->str;
3043                                 int ssid_len = strlen(ssid);
3044
3045                                 scan_ssid = g_try_new0(struct scan_ssid, 1);
3046                                 if (!scan_ssid) {
3047                                         DBG("Failed to allocate memory.");
3048                                         g_supplicant_free_scan_params(scan_params);
3049                                         return -ENOMEM;
3050                                 }
3051
3052                                 memcpy(scan_ssid->ssid, ssid, (ssid_len + 1));
3053                                 /* DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); */
3054                                 scan_ssid->ssid_len = ssid_len;
3055                                 scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid);
3056                                 ap_count++;
3057
3058                         } else { /* freq */
3059                                 freq = atoi(((connman_multi_scan_ap_s *)list->data)->str);
3060                                 scan_params->freqs[freq_count] = freq;
3061                                 DBG("scan_params->freqs[%d]: %d", freq_count, scan_params->freqs[freq_count]);
3062                                 freq_count++;
3063                         }
3064                 }
3065                 scan_params->num_ssids = ap_count;
3066                 scan_params->num_freqs = freq_count;
3067         } else {
3068                 DBG("Invalid scan");
3069                 return -EINVAL;
3070         }
3071
3072         reset_autoscan(device);
3073         connman_device_ref(device);
3074
3075         ret = g_supplicant_interface_scan(wifi->interface, scan_params,
3076                                                 specific_scan_callback, device);
3077
3078         if (ret == 0) {
3079                 connman_device_set_scanning(device,
3080                                 CONNMAN_SERVICE_TYPE_WIFI, true);
3081         } else {
3082                 g_supplicant_free_scan_params(scan_params);
3083                 connman_device_unref(device);
3084         }
3085
3086         return ret;
3087 }
3088
3089 static void wifi_mac_policy_callback(int result,
3090                                         unsigned int policy,
3091                                                 void *user_data)
3092 {
3093         struct connman_device *device = user_data;
3094
3095         if (result == 0)
3096                 connman_device_mac_policy_notify(device, result, policy);
3097
3098         connman_device_unref(device);
3099 }
3100
3101 int wifi_set_mac_policy(struct connman_device *device, unsigned int policy)
3102 {
3103         struct wifi_data *wifi = connman_device_get_data(device);
3104         int ret;
3105
3106         if (!wifi)
3107                 return -EINVAL;
3108
3109         connman_device_ref(device);
3110
3111         ret = g_supplicant_interface_set_mac_policy(wifi->interface,
3112                                         wifi_mac_policy_callback,
3113                                         policy, device);
3114         if (ret != 0)
3115                 connman_device_unref(device);
3116
3117         return ret;
3118 }
3119
3120 static void wifi_preassoc_mac_policy_callback(int result,
3121                                         unsigned int policy,
3122                                                 void *user_data)
3123 {
3124         struct connman_device *device = user_data;
3125
3126         if (result == 0)
3127                 connman_device_preassoc_mac_policy_notify(device, result, policy);
3128
3129         connman_device_unref(device);
3130 }
3131
3132 int wifi_set_preassoc_mac_policy(struct connman_device *device, unsigned int policy)
3133 {
3134         struct wifi_data *wifi = connman_device_get_data(device);
3135         int ret;
3136
3137         if (!wifi)
3138                 return -EINVAL;
3139
3140         connman_device_ref(device);
3141
3142         ret = g_supplicant_interface_set_preassoc_mac_policy(wifi->interface,
3143                                         wifi_preassoc_mac_policy_callback,
3144                                         policy, device);
3145         if (ret != 0)
3146                 connman_device_unref(device);
3147
3148         return ret;
3149 }
3150
3151 static void wifi_random_mac_lifetime_callback(int result,
3152                                         unsigned int lifetime,
3153                                                 void *user_data)
3154 {
3155         struct connman_device *device = user_data;
3156
3157         if (result == 0)
3158                 connman_device_random_mac_lifetime_notify(device, result, lifetime);
3159
3160         connman_device_unref(device);
3161 }
3162
3163 int wifi_set_random_mac_lifetime(struct connman_device *device, unsigned int lifetime)
3164 {
3165         struct wifi_data *wifi = connman_device_get_data(device);
3166         int ret;
3167
3168         if (!wifi)
3169                 return -EINVAL;
3170
3171         connman_device_ref(device);
3172
3173         ret = g_supplicant_interface_set_random_mac_lifetime(wifi->interface,
3174                                         wifi_random_mac_lifetime_callback,
3175                                         lifetime, device);
3176         if (ret != 0)
3177                 connman_device_unref(device);
3178
3179         return ret;
3180 }
3181 #endif
3182
3183 #if defined TIZEN_EXT_WIFI_MESH
3184 static void mesh_scan_callback(int result, GSupplicantInterface *interface,
3185                                                 void *user_data)
3186 {
3187         struct connman_device *device = user_data;
3188         struct wifi_data *wifi = connman_device_get_data(device);
3189         bool scanning;
3190
3191         DBG("result %d wifi %p", result, wifi);
3192
3193         scanning = connman_device_get_scanning(device,
3194                                                CONNMAN_SERVICE_TYPE_MESH);
3195         if (scanning)
3196                 connman_device_set_scanning(device,
3197                                 CONNMAN_SERVICE_TYPE_MESH, false);
3198
3199         if (scanning)
3200                 connman_device_unref(device);
3201 }
3202
3203 static int mesh_scan(struct connman_device *device)
3204 {
3205         struct wifi_data *wifi;
3206         struct wifi_mesh_info *mesh_info;
3207         int ret;
3208
3209         DBG("");
3210
3211         wifi = connman_device_get_data(device);
3212
3213         if (!wifi || !wifi->mesh_interface)
3214                 return -ENOTSUP;
3215
3216         mesh_info = wifi->mesh_info;
3217         reset_autoscan(device);
3218         connman_device_ref(device);
3219
3220         ret = g_supplicant_interface_scan(mesh_info->interface, NULL,
3221                                                 mesh_scan_callback, device);
3222         if (ret)
3223                 connman_device_unref(device);
3224         else
3225                 connman_device_set_scanning(device,
3226                                 CONNMAN_SERVICE_TYPE_MESH, true);
3227
3228         return ret;
3229 }
3230
3231 static void abort_scan_callback(int result, GSupplicantInterface *interface,
3232                                                 void *user_data)
3233 {
3234         struct connman_device *device = user_data;
3235         struct wifi_data *wifi = connman_device_get_data(device);
3236
3237         DBG("result %d wifi %p", result, wifi);
3238
3239         __connman_technology_notify_abort_scan(CONNMAN_SERVICE_TYPE_MESH, result);
3240 }
3241
3242 static int mesh_abort_scan(enum connman_service_type type,
3243                                                 struct connman_device *device)
3244 {
3245         struct wifi_data *wifi = connman_device_get_data(device);
3246         struct wifi_mesh_info *mesh_info;
3247         bool scanning;
3248         int ret;
3249
3250         if (!wifi || !wifi->mesh_interface)
3251                 return -ENODEV;
3252
3253         if (type != CONNMAN_SERVICE_TYPE_MESH)
3254                 return -EINVAL;
3255
3256         mesh_info = wifi->mesh_info;
3257
3258         scanning = connman_device_get_scanning(device,
3259                                                CONNMAN_SERVICE_TYPE_MESH);
3260         if (!scanning)
3261                 return -EEXIST;
3262
3263         ret = g_supplicant_interface_abort_scan(mesh_info->interface,
3264                                                 abort_scan_callback, device);
3265
3266         return ret;
3267 }
3268
3269 static int mesh_specific_scan(enum connman_service_type type,
3270                               struct connman_device *device, const char *ssid,
3271                               unsigned int freq, void *user_data)
3272 {
3273         struct wifi_data *wifi = connman_device_get_data(device);
3274         GSupplicantScanParams *scan_params = NULL;
3275         struct wifi_mesh_info *mesh_info;
3276         struct scan_ssid *scan_ssid;
3277         bool scanning;
3278         int ret;
3279
3280         if (!wifi || !wifi->mesh_interface)
3281                 return -ENODEV;
3282
3283         if (type != CONNMAN_SERVICE_TYPE_MESH)
3284                 return -EINVAL;
3285
3286         if (wifi->p2p_device)
3287                 return 0;
3288
3289         mesh_info = wifi->mesh_info;
3290
3291         scanning = connman_device_get_scanning(device,
3292                                                CONNMAN_SERVICE_TYPE_MESH);
3293         if (scanning)
3294                 return -EALREADY;
3295
3296         scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
3297         if (!scan_params)
3298                 return -ENOMEM;
3299
3300         scan_ssid = g_try_new(struct scan_ssid, 1);
3301         if (!scan_ssid) {
3302                 g_free(scan_params);
3303                 return -ENOMEM;
3304         }
3305
3306         scan_ssid->ssid_len = strlen(ssid);
3307         memcpy(scan_ssid->ssid, ssid, scan_ssid->ssid_len);
3308         scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid);
3309         scan_params->num_ssids = 1;
3310
3311         scan_params->freqs = g_try_new(uint16_t, 1);
3312         if (!scan_params->freqs) {
3313                 g_slist_free_full(scan_params->ssids, g_free);
3314                 g_free(scan_params);
3315                 return -ENOMEM;
3316         }
3317
3318         scan_params->freqs[0] = freq;
3319         scan_params->num_freqs = 1;
3320
3321         reset_autoscan(device);
3322         connman_device_ref(device);
3323
3324         ret = g_supplicant_interface_scan(mesh_info->interface, scan_params,
3325                                                 mesh_scan_callback, device);
3326
3327         if (ret == 0) {
3328                 connman_device_set_scanning(device,
3329                                 CONNMAN_SERVICE_TYPE_MESH, true);
3330         } else {
3331                 g_supplicant_free_scan_params(scan_params);
3332                 connman_device_unref(device);
3333         }
3334
3335         return ret;
3336 }
3337 #endif
3338
3339 /*
3340  * Note that the hidden scan is only used when connecting to this specific
3341  * hidden AP first time. It is not used when system autoconnects to hidden AP.
3342  */
3343 static int wifi_scan(struct connman_device *device,
3344                         struct connman_device_scan_params *params)
3345 {
3346         struct wifi_data *wifi = connman_device_get_data(device);
3347         GSupplicantScanParams *scan_params = NULL;
3348         struct scan_ssid *scan_ssid;
3349         struct hidden_params *hidden;
3350         int ret;
3351         int driver_max_ssids = 0;
3352         bool do_hidden;
3353         bool scanning;
3354
3355         if (!wifi)
3356                 return -ENODEV;
3357
3358         if (wifi->p2p_device)
3359                 return -EBUSY;
3360
3361         if (wifi->tethering)
3362                 return -EBUSY;
3363
3364         if (params->type == CONNMAN_SERVICE_TYPE_P2P)
3365                 return p2p_find(device);
3366
3367 #if defined TIZEN_EXT_WIFI_MESH
3368         if (params->type == CONNMAN_SERVICE_TYPE_MESH)
3369                 return mesh_scan(device);
3370 #endif
3371
3372         DBG("device %p wifi %p hidden ssid %s", device, wifi->interface,
3373                 params->ssid);
3374
3375         scanning = connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI);
3376
3377         if (!params->ssid || params->ssid_len == 0 || params->ssid_len > 32) {
3378                 if (scanning)
3379                         return -EALREADY;
3380
3381                 driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
3382                                                         wifi->interface);
3383                 DBG("max ssids %d", driver_max_ssids);
3384                 if (driver_max_ssids == 0)
3385                         return wifi_scan_simple(device);
3386
3387                 do_hidden = false;
3388         } else {
3389                 if (scanning && wifi->hidden && wifi->postpone_hidden)
3390                         return -EALREADY;
3391
3392                 do_hidden = true;
3393         }
3394
3395         scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
3396         if (!scan_params)
3397                 return -ENOMEM;
3398
3399         if (do_hidden) {
3400                 scan_ssid = g_try_new(struct scan_ssid, 1);
3401                 if (!scan_ssid) {
3402                         g_free(scan_params);
3403                         return -ENOMEM;
3404                 }
3405
3406                 memcpy(scan_ssid->ssid, params->ssid, params->ssid_len);
3407                 scan_ssid->ssid_len = params->ssid_len;
3408                 scan_params->ssids = g_slist_prepend(scan_params->ssids,
3409                                                                 scan_ssid);
3410                 scan_params->num_ssids = 1;
3411
3412                 hidden = g_try_new0(struct hidden_params, 1);
3413                 if (!hidden) {
3414                         g_supplicant_free_scan_params(scan_params);
3415                         return -ENOMEM;
3416                 }
3417
3418                 if (wifi->hidden) {
3419                         hidden_free(wifi->hidden);
3420                         wifi->hidden = NULL;
3421                 }
3422
3423                 memcpy(hidden->ssid, params->ssid, params->ssid_len);
3424                 hidden->ssid_len = params->ssid_len;
3425                 hidden->identity = g_strdup(params->identity);
3426                 hidden->passphrase = g_strdup(params->passphrase);
3427                 hidden->security = g_strdup(params->security);
3428                 hidden->user_data = params->user_data;
3429                 wifi->hidden = hidden;
3430
3431                 if (scanning) {
3432                         /* Let's keep this active scan for later,
3433                          * when current scan will be over. */
3434                         wifi->postpone_hidden = TRUE;
3435                         hidden->scan_params = scan_params;
3436
3437                         return 0;
3438                 }
3439         } else if (wifi->connected) {
3440                 g_supplicant_free_scan_params(scan_params);
3441                 return wifi_scan_simple(device);
3442         } else if (!params->force_full_scan) {
3443                 ret = get_latest_connections(driver_max_ssids, scan_params);
3444                 if (ret <= 0) {
3445                         g_supplicant_free_scan_params(scan_params);
3446                         return wifi_scan_simple(device);
3447                 }
3448         }
3449
3450         /* Distinguish between devices performing passive and active scanning */
3451         wifi_update_scanner_type(wifi, WIFI_SCANNING_ACTIVE);
3452
3453         connman_device_ref(device);
3454
3455         reset_autoscan(device);
3456 #if defined TIZEN_EXT
3457         /*
3458          * When doing a full scan, stored hidden networks also need to be scanned
3459          * so that we can autoconnect to them.
3460          */
3461         if (params->force_full_scan)
3462                 ret = g_supplicant_interface_scan(wifi->interface, scan_params,
3463                                                         scan_callback_hidden, device);
3464         else
3465 #endif
3466         ret = g_supplicant_interface_scan(wifi->interface, scan_params,
3467                                                 scan_callback, device);
3468         if (ret == 0) {
3469                 connman_device_set_scanning(device,
3470                                 CONNMAN_SERVICE_TYPE_WIFI, true);
3471 #if defined TIZEN_EXT
3472                 /*
3473                  * To allow the Full Scan after ssid based scan, set the flag here
3474                  * It is required because Tizen does not use the ConnMan specific
3475                  * backgroung Scan feature.Tizen has added the BG Scan feature in
3476                  * net-config. To sync with up ConnMan, we need to issue the Full Scan
3477                  * after SSID specific scan.
3478                  */
3479                 if (!params->force_full_scan && !do_hidden)
3480                         wifi->allow_full_scan = TRUE;
3481 #endif
3482         } else {
3483                 g_supplicant_free_scan_params(scan_params);
3484                 connman_device_unref(device);
3485
3486                 if (do_hidden) {
3487                         hidden_free(wifi->hidden);
3488                         wifi->hidden = NULL;
3489                 }
3490         }
3491
3492         return ret;
3493 }
3494
3495 static void wifi_stop_scan(enum connman_service_type type,
3496                         struct connman_device *device)
3497 {
3498         struct wifi_data *wifi = connman_device_get_data(device);
3499
3500         DBG("device %p wifi %p", device, wifi);
3501
3502         if (!wifi)
3503                 return;
3504
3505         if (type == CONNMAN_SERVICE_TYPE_P2P) {
3506                 if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_P2P)) {
3507                         g_source_remove(wifi->p2p_find_timeout);
3508                         p2p_find_stop(device);
3509                 }
3510         }
3511 }
3512
3513 static void wifi_regdom_callback(int result,
3514                                         const char *alpha2,
3515                                                 void *user_data)
3516 {
3517         struct connman_device *device = user_data;
3518
3519         connman_device_regdom_notify(device, result, alpha2);
3520
3521         connman_device_unref(device);
3522 }
3523
3524 static int wifi_set_regdom(struct connman_device *device, const char *alpha2)
3525 {
3526         struct wifi_data *wifi = connman_device_get_data(device);
3527         int ret;
3528
3529         if (!wifi)
3530                 return -EINVAL;
3531
3532         connman_device_ref(device);
3533
3534         ret = g_supplicant_interface_set_country(wifi->interface,
3535                                                 wifi_regdom_callback,
3536                                                         alpha2, device);
3537         if (ret != 0)
3538                 connman_device_unref(device);
3539
3540         return ret;
3541 }
3542
3543 static struct connman_device_driver wifi_ng_driver = {
3544         .name           = "wifi",
3545         .type           = CONNMAN_DEVICE_TYPE_WIFI,
3546         .priority       = CONNMAN_DEVICE_PRIORITY_LOW,
3547         .probe          = wifi_probe,
3548         .remove         = wifi_remove,
3549         .enable         = wifi_enable,
3550         .disable        = wifi_disable,
3551         .scan           = wifi_scan,
3552         .stop_scan      = wifi_stop_scan,
3553         .set_regdom     = wifi_set_regdom,
3554 #if defined TIZEN_EXT
3555         .specific_scan  = wifi_specific_scan,
3556         .set_mac_policy           = wifi_set_mac_policy,
3557         .set_preassoc_mac_policy  = wifi_set_preassoc_mac_policy,
3558         .set_random_mac_lifetime  = wifi_set_random_mac_lifetime,
3559 #endif
3560 #if defined TIZEN_EXT_WIFI_MESH
3561         .abort_scan     = mesh_abort_scan,
3562         .mesh_specific_scan     = mesh_specific_scan,
3563 #endif
3564 };
3565
3566 static void system_ready(void)
3567 {
3568         DBG("");
3569
3570         if (connman_device_driver_register(&wifi_ng_driver) < 0)
3571                 connman_error("Failed to register WiFi driver");
3572 }
3573
3574 static void system_killed(void)
3575 {
3576         DBG("");
3577
3578         connman_device_driver_unregister(&wifi_ng_driver);
3579 }
3580
3581 static int network_probe(struct connman_network *network)
3582 {
3583 #if defined TIZEN_EXT
3584         if (!simplified_log)
3585 #endif
3586         DBG("network %p", network);
3587
3588         return 0;
3589 }
3590
3591 static void network_remove(struct connman_network *network)
3592 {
3593         struct connman_device *device = connman_network_get_device(network);
3594         struct wifi_data *wifi;
3595
3596         DBG("network %p", network);
3597
3598         wifi = connman_device_get_data(device);
3599         if (!wifi)
3600                 return;
3601
3602         if (wifi->network != network)
3603                 return;
3604
3605         wifi->network = NULL;
3606
3607 #if defined TIZEN_EXT
3608         wifi->disconnecting = false;
3609
3610         if (wifi->pending_network == network)
3611                 wifi->pending_network = NULL;
3612
3613         if (wifi->scan_pending_network == network)
3614                 wifi->scan_pending_network = NULL;
3615 #endif
3616 }
3617
3618 static void connect_callback(int result, GSupplicantInterface *interface,
3619                                                         void *user_data)
3620 {
3621 #if defined TIZEN_EXT
3622         GList *list;
3623         struct wifi_data *wifi;
3624 #endif
3625         struct connman_network *network = user_data;
3626
3627         DBG("network %p result %d", network, result);
3628
3629 #if defined TIZEN_EXT
3630         const char *ifname = g_supplicant_interface_get_ifname(interface);
3631         set_connman_bssid(RESET_BSSID, NULL, ifname);
3632
3633         for (list = iface_list; list; list = list->next) {
3634                 wifi = list->data;
3635
3636                 if (wifi && wifi->network == network)
3637                         goto found;
3638         }
3639
3640         /* wifi_data may be invalid because wifi is already disabled */
3641         return;
3642
3643 found:
3644         if (connman_network_get_bool(network, "WiFi.Roaming")) {
3645                 if (result < 0 ) {
3646                         connman_network_set_bool(network, "WiFi.Roaming", false);
3647                         connman_network_set_string(network,
3648                                         "WiFi.RoamingCurBSSID", NULL);
3649                 } else {
3650                         char bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
3651                         char *bssid_str = bssid_buff;
3652                         unsigned char *bssid;
3653                         const char *cur_bssid;
3654
3655                         bssid = g_supplicant_interface_get_add_network_bssid(interface);
3656                         if (!bssid) {
3657                                 connman_network_set_bool(network, "WiFi.Roaming", false);
3658                                 connman_network_set_string(network,
3659                                                 "WiFi.RoamingCurBSSID", NULL);
3660                         } else {
3661                                 snprintf(bssid_str,
3662                                                 WIFI_BSSID_STR_LEN,
3663                                                 MACSTR, MAC2STR(bssid));
3664
3665                                 connman_network_set_string(network,
3666                                                 "WiFi.RoamingDstBSSID", bssid_str);
3667
3668                                 cur_bssid = connman_network_get_string(network,
3669                                                 "WiFi.RoamingCurBSSID");
3670
3671                                 __connman_technology_notify_roaming_state(ifname,
3672                                                 "started", cur_bssid, bssid_str);
3673                         }
3674                 }
3675         }
3676 #endif
3677         if (result == -ENOKEY) {
3678                 connman_network_set_error(network,
3679                                         CONNMAN_NETWORK_ERROR_INVALID_KEY);
3680         } else if (result < 0) {
3681                 connman_network_set_error(network,
3682                                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
3683         }
3684
3685         connman_network_unref(network);
3686 }
3687
3688 static GSupplicantSecurity network_security(const char *security)
3689 {
3690         if (g_str_equal(security, "none"))
3691                 return G_SUPPLICANT_SECURITY_NONE;
3692         else if (g_str_equal(security, "wep"))
3693                 return G_SUPPLICANT_SECURITY_WEP;
3694         else if (g_str_equal(security, "psk"))
3695                 return G_SUPPLICANT_SECURITY_PSK;
3696         else if (g_str_equal(security, "wpa"))
3697                 return G_SUPPLICANT_SECURITY_PSK;
3698         else if (g_str_equal(security, "rsn"))
3699                 return G_SUPPLICANT_SECURITY_PSK;
3700         else if (g_str_equal(security, "ieee8021x"))
3701                 return G_SUPPLICANT_SECURITY_IEEE8021X;
3702 #if defined TIZEN_EXT
3703         else if (g_str_equal(security, "ft_psk") == TRUE)
3704                 return G_SUPPLICANT_SECURITY_FT_PSK;
3705         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
3706                 return G_SUPPLICANT_SECURITY_FT_IEEE8021X;
3707         else if (g_str_equal(security, "sae"))
3708                 return G_SUPPLICANT_SECURITY_SAE;
3709         else if (g_str_equal(security, "owe"))
3710                 return G_SUPPLICANT_SECURITY_OWE;
3711         else if (g_str_equal(security, "dpp"))
3712                 return G_SUPPLICANT_SECURITY_DPP;
3713 #endif
3714
3715         return G_SUPPLICANT_SECURITY_UNKNOWN;
3716 }
3717
3718 #if defined TIZEN_EXT
3719 static GSupplicantEapKeymgmt network_eap_keymgmt(const char *security)
3720 {
3721         if (security == NULL)
3722                 return G_SUPPLICANT_EAP_KEYMGMT_NONE;
3723
3724         if (g_str_equal(security, "FT") == TRUE)
3725                 return G_SUPPLICANT_EAP_KEYMGMT_FT;
3726         else if (g_str_equal(security, "CCKM") == TRUE)
3727                 return G_SUPPLICANT_EAP_KEYMGMT_CCKM;
3728
3729         return G_SUPPLICANT_EAP_KEYMGMT_NONE;
3730 }
3731 #endif
3732
3733 static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
3734 {
3735         const char *security;
3736 #if defined TIZEN_EXT
3737         const void *ssid_data;
3738 #endif
3739
3740         memset(ssid, 0, sizeof(*ssid));
3741         ssid->mode = G_SUPPLICANT_MODE_INFRA;
3742 #if defined TIZEN_EXT
3743         ssid_data = connman_network_get_blob(network, "WiFi.SSID",
3744                                                 &ssid->ssid_len);
3745         ssid->ssid = g_try_malloc0(ssid->ssid_len);
3746
3747         if (!ssid->ssid)
3748                 ssid->ssid_len = 0;
3749         else
3750                 memcpy(ssid->ssid, ssid_data, ssid->ssid_len);
3751 #else
3752         ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
3753                                                 &ssid->ssid_len);
3754 #endif
3755         ssid->scan_ssid = 1;
3756         security = connman_network_get_string(network, "WiFi.Security");
3757         ssid->security = network_security(security);
3758 #if defined TIZEN_EXT
3759         ssid->ieee80211w = 1;
3760 #endif
3761         ssid->passphrase = connman_network_get_string(network,
3762                                                 "WiFi.Passphrase");
3763
3764         ssid->eap = connman_network_get_string(network, "WiFi.EAP");
3765
3766         /*
3767          * If our private key password is unset,
3768          * we use the supplied passphrase. That is needed
3769          * for PEAP where 2 passphrases (identity and client
3770          * cert may have to be provided.
3771          */
3772         if (!connman_network_get_string(network, "WiFi.PrivateKeyPassphrase"))
3773                 connman_network_set_string(network,
3774                                                 "WiFi.PrivateKeyPassphrase",
3775                                                 ssid->passphrase);
3776         /* We must have an identity for both PEAP and TLS */
3777         ssid->identity = connman_network_get_string(network, "WiFi.Identity");
3778
3779         /* Use agent provided identity as a fallback */
3780         if (!ssid->identity || strlen(ssid->identity) == 0)
3781                 ssid->identity = connman_network_get_string(network,
3782                                                         "WiFi.AgentIdentity");
3783
3784         ssid->anonymous_identity = connman_network_get_string(network,
3785                                                 "WiFi.AnonymousIdentity");
3786         ssid->ca_cert_path = connman_network_get_string(network,
3787                                                         "WiFi.CACertFile");
3788         ssid->subject_match = connman_network_get_string(network,
3789                                                         "WiFi.SubjectMatch");
3790         ssid->altsubject_match = connman_network_get_string(network,
3791                                                         "WiFi.AltSubjectMatch");
3792         ssid->domain_suffix_match = connman_network_get_string(network,
3793                                                         "WiFi.DomainSuffixMatch");
3794         ssid->domain_match = connman_network_get_string(network,
3795                                                         "WiFi.DomainMatch");
3796         ssid->client_cert_path = connman_network_get_string(network,
3797                                                         "WiFi.ClientCertFile");
3798         ssid->private_key_path = connman_network_get_string(network,
3799                                                         "WiFi.PrivateKeyFile");
3800         ssid->private_key_passphrase = connman_network_get_string(network,
3801                                                 "WiFi.PrivateKeyPassphrase");
3802         ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
3803
3804         ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS");
3805         ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS");
3806 #if defined TIZEN_EXT
3807         ssid->connector = connman_network_get_string(network,
3808                                                         "WiFi.Connector");
3809         ssid->c_sign_key = connman_network_get_string(network,
3810                                                         "WiFi.CSignKey");
3811         ssid->net_access_key = connman_network_get_string(network,
3812                                                 "WiFi.NetAccessKey");
3813 #endif
3814
3815 #if defined TIZEN_EXT
3816         const char *ifname = connman_device_get_string(
3817                         connman_network_get_device(network), "Interface");
3818         if (set_connman_bssid(CHECK_BSSID, NULL, ifname) == 6) {
3819                 ssid->bssid_for_connect_len = 6;
3820                 set_connman_bssid(GET_BSSID, (char *)ssid->bssid_for_connect, ifname);
3821                 DBG("BSSID : %02x:%02x:%02x:%02x:%02x:%02x",
3822                         ssid->bssid_for_connect[0], ssid->bssid_for_connect[1],
3823                         ssid->bssid_for_connect[2], ssid->bssid_for_connect[3],
3824                         ssid->bssid_for_connect[4], ssid->bssid_for_connect[5]);
3825         } else {
3826                 ssid->freq = connman_network_get_frequency(network);
3827         }
3828
3829         GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network);
3830         if (bssid_list && g_slist_length(bssid_list) > 1) {
3831
3832                 /* If there are more than one bssid,
3833                  * the user-specified bssid is tried only once at the beginning.
3834                  * After that, the bssids in the list are tried in order.
3835                  */
3836                 if (set_connman_bssid(CHECK_BSSID, NULL, ifname) == 6) {
3837                         set_connman_bssid(RESET_BSSID, NULL, ifname);
3838                         goto done;
3839                 }
3840
3841                 GSList *list;
3842                 char buff[MAC_ADDRESS_LENGTH];
3843                 for (list = bssid_list; list; list = list->next) {
3844                         struct connman_bssids * bssids = (struct connman_bssids *)list->data;
3845
3846                         g_snprintf(buff, MAC_ADDRESS_LENGTH, "%02x:%02x:%02x:%02x:%02x:%02x",
3847                                         bssids->bssid[0], bssids->bssid[1], bssids->bssid[2],
3848                                         bssids->bssid[3], bssids->bssid[4], bssids->bssid[5]);
3849                         buff[MAC_ADDRESS_LENGTH - 1] = '\0';
3850
3851                         gchar *curr_bssid = g_strdup((const gchar *)buff);
3852
3853                         if (g_hash_table_contains(failed_bssids, curr_bssid)) {
3854                                 DBG("bssid match, try next bssid");
3855                                 g_free(curr_bssid);
3856                                 continue;
3857                         } else {
3858                                 g_hash_table_add(failed_bssids, curr_bssid);
3859
3860                                 memcpy(buff_bssid, bssids->bssid, WIFI_BSSID_LEN_MAX);
3861                                 ssid->bssid = buff_bssid;
3862                                 ssid->freq = (unsigned int)bssids->frequency;
3863                                 break;
3864                         }
3865                 }
3866
3867                 if (!list) {
3868                         ssid->bssid = connman_network_get_bssid(network);
3869                         g_hash_table_remove_all(failed_bssids);
3870                 }
3871         } else
3872                 ssid->bssid = connman_network_get_bssid(network);
3873
3874 done:
3875         ssid->eap_keymgmt = network_eap_keymgmt(
3876                         connman_network_get_string(network, "WiFi.KeymgmtType"));
3877         ssid->phase1 = connman_network_get_string(network, "WiFi.Phase1");
3878
3879         if(g_strcmp0(ssid->eap, "fast") == 0)
3880                 ssid->pac_file = g_strdup(WIFI_EAP_FAST_PAC_FILE);
3881
3882         ssid->keymgmt = connman_network_get_keymgmt(network);
3883 #endif
3884
3885         if (connman_setting_get_bool("BackgroundScanning"))
3886                 ssid->bgscan = BGSCAN_DEFAULT;
3887 }
3888
3889 static int network_connect(struct connman_network *network)
3890 {
3891         struct connman_device *device = connman_network_get_device(network);
3892         struct wifi_data *wifi;
3893         GSupplicantInterface *interface;
3894         GSupplicantSSID *ssid;
3895
3896         DBG("network %p", network);
3897
3898         if (!device)
3899                 return -ENODEV;
3900
3901         wifi = connman_device_get_data(device);
3902         if (!wifi)
3903                 return -ENODEV;
3904
3905         ssid = g_try_malloc0(sizeof(GSupplicantSSID));
3906         if (!ssid)
3907                 return -ENOMEM;
3908
3909         interface = wifi->interface;
3910
3911         ssid_init(ssid, network);
3912
3913         if (wifi->disconnecting) {
3914                 wifi->pending_network = network;
3915 #if defined TIZEN_EXT
3916                 g_free(ssid->ssid);
3917 #endif
3918                 g_free(ssid);
3919         } else {
3920                 wifi->network = connman_network_ref(network);
3921                 wifi->retries = 0;
3922 #if defined TIZEN_EXT
3923                 wifi->scan_pending_network = NULL;
3924 #endif
3925
3926                 return g_supplicant_interface_connect(interface, ssid,
3927                                                 connect_callback, network);
3928         }
3929
3930         return -EINPROGRESS;
3931 }
3932
3933 static void disconnect_callback(int result, GSupplicantInterface *interface,
3934                                                                 void *user_data)
3935 {
3936 #if defined TIZEN_EXT
3937         GList *list;
3938         struct wifi_data *wifi;
3939         struct connman_network *network = user_data;
3940
3941         DBG("network %p result %d", network, result);
3942
3943         for (list = iface_list; list; list = list->next) {
3944                 wifi = list->data;
3945
3946                 if (wifi->network == NULL && wifi->disconnecting == true)
3947                         wifi->disconnecting = false;
3948
3949                 if (wifi->network == network)
3950                         goto found;
3951         }
3952
3953         /* wifi_data may be invalid because wifi is already disabled */
3954         return;
3955
3956 found:
3957 #else
3958         struct wifi_data *wifi = user_data;
3959 #endif
3960
3961         DBG("result %d supplicant interface %p wifi %p",
3962                         result, interface, wifi);
3963
3964         if (result == -ECONNABORTED) {
3965                 DBG("wifi interface no longer available");
3966                 return;
3967         }
3968
3969 #if defined TIZEN_EXT
3970         if (wifi->network &&
3971                         (wifi->network != wifi->pending_network ||
3972                         connman_network_get_bool(wifi->network, "WiFi.Roaming")))
3973 #else
3974         if (wifi->network && wifi->network != wifi->pending_network)
3975 #endif
3976                 connman_network_set_connected(wifi->network, false);
3977         wifi->network = NULL;
3978
3979         wifi->disconnecting = false;
3980         wifi->connected = false;
3981
3982         if (wifi->pending_network) {
3983                 network_connect(wifi->pending_network);
3984                 wifi->pending_network = NULL;
3985         }
3986
3987         start_autoscan(wifi->device);
3988 }
3989
3990 static int network_disconnect(struct connman_network *network)
3991 {
3992         struct connman_device *device = connman_network_get_device(network);
3993         struct wifi_data *wifi;
3994         int err;
3995 #if defined TIZEN_EXT
3996         struct connman_service *service;
3997 #endif
3998
3999         DBG("network %p", network);
4000
4001         wifi = connman_device_get_data(device);
4002         if (!wifi || !wifi->interface)
4003                 return -ENODEV;
4004
4005 #if defined TIZEN_EXT
4006         if (connman_network_get_associating(network) == true) {
4007                 connman_network_clear_associating(network);
4008                 connman_network_set_bool(network, "WiFi.UseWPS", false);
4009         } else {
4010                 service = connman_service_lookup_from_network(network);
4011
4012                 if (service != NULL &&
4013                         (__connman_service_is_connected_state(service,
4014                                         CONNMAN_IPCONFIG_TYPE_IPV4) == false &&
4015                         __connman_service_is_connected_state(service,
4016                                         CONNMAN_IPCONFIG_TYPE_IPV6) == false) &&
4017                         (connman_service_get_favorite(service) == false))
4018                                         __connman_service_set_passphrase(service, NULL);
4019         }
4020
4021         if (wifi->pending_network == network)
4022                 wifi->pending_network = NULL;
4023
4024         if (wifi->scan_pending_network == network)
4025                 wifi->scan_pending_network = NULL;
4026
4027 #endif
4028         connman_network_set_associating(network, false);
4029
4030         if (wifi->disconnecting)
4031                 return -EALREADY;
4032
4033         wifi->disconnecting = true;
4034
4035 #if defined TIZEN_EXT
4036         err = g_supplicant_interface_disconnect(wifi->interface,
4037                                                 disconnect_callback, network);
4038 #else
4039         err = g_supplicant_interface_disconnect(wifi->interface,
4040                                                 disconnect_callback, wifi);
4041 #endif
4042
4043         if (err < 0)
4044                 wifi->disconnecting = false;
4045
4046         return err;
4047 }
4048
4049 #if defined TIZEN_EXT
4050 static void set_connection_mode(struct connman_network *network,
4051                 int linkspeed)
4052 {
4053         ieee80211_modes_e phy_mode;
4054         connection_mode_e conn_mode;
4055
4056         phy_mode = connman_network_get_phy_mode(network);
4057         switch (phy_mode) {
4058         case IEEE80211_MODE_B:
4059                 if (linkspeed > 0 && linkspeed <= 11)
4060                         conn_mode = CONNECTION_MODE_IEEE80211B;
4061                 else
4062                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4063
4064                 break;
4065         case IEEE80211_MODE_BG:
4066                 if (linkspeed > 0 && linkspeed <= 11)
4067                         conn_mode = CONNECTION_MODE_IEEE80211B;
4068                 else if (linkspeed > 11 && linkspeed <= 54)
4069                         conn_mode = CONNECTION_MODE_IEEE80211G;
4070                 else
4071                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4072
4073                 break;
4074         case IEEE80211_MODE_BGN:
4075                 if (linkspeed > 0 && linkspeed <= 11)
4076                         conn_mode = CONNECTION_MODE_IEEE80211B;
4077                 else if (linkspeed > 11 && linkspeed <= 54)
4078                         conn_mode = CONNECTION_MODE_IEEE80211G;
4079                 else if (linkspeed > 54 && linkspeed <= 450)
4080                         conn_mode = CONNECTION_MODE_IEEE80211N;
4081                 else
4082                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4083
4084                 break;
4085         case IEEE80211_MODE_A:
4086                 if (linkspeed > 0 && linkspeed <= 54)
4087                         conn_mode = CONNECTION_MODE_IEEE80211A;
4088                 else
4089                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4090
4091                 break;
4092         case IEEE80211_MODE_AN:
4093                 if (linkspeed > 0 && linkspeed <= 54)
4094                         conn_mode = CONNECTION_MODE_IEEE80211A;
4095                 else if (linkspeed > 54 && linkspeed <= 450)
4096                         conn_mode = CONNECTION_MODE_IEEE80211N;
4097                 else
4098                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4099
4100                 break;
4101         case IEEE80211_MODE_ANAC:
4102                 if (linkspeed > 0 && linkspeed <= 54)
4103                         conn_mode = CONNECTION_MODE_IEEE80211A;
4104                 else if (linkspeed > 54 && linkspeed <= 450)
4105                         conn_mode = CONNECTION_MODE_IEEE80211N;
4106                 else if (linkspeed > 450 && linkspeed <= 1300)
4107                         conn_mode = CONNECTION_MODE_IEEE80211AC;
4108                 else
4109                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4110
4111                 break;
4112         default:
4113                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4114                 break;
4115         }
4116
4117         DBG("connection mode(%d)", conn_mode);
4118         connman_network_set_connection_mode(network, conn_mode);
4119 }
4120
4121 static void signalpoll_callback(int result, int maxspeed, int strength,
4122                                 int snr, void *user_data)
4123 {
4124         char bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
4125         char *bssid_str = bssid_buff;
4126         unsigned char *bssid;
4127         const char *interface = NULL;
4128         struct connman_device *device;
4129         struct connman_network *network = user_data;
4130         uint16_t freq = connman_network_get_frequency(network);
4131
4132         if (result != 0) {
4133                 DBG("Failed to get maxspeed from signalpoll !");
4134                 connman_network_unref(network);
4135                 return;
4136         }
4137
4138         strength += 120;
4139         if (strength > 100)
4140                 strength = 100;
4141
4142         DBG("freq = %u, maxspeed = %d, strength = %d, snr = %d", freq, maxspeed, strength, snr);
4143
4144         connman_network_set_strength(network, (uint8_t)strength);
4145         connman_network_set_snr(network, snr);
4146         connman_network_set_maxspeed(network, maxspeed);
4147         set_connection_mode(network, maxspeed);
4148
4149         bssid = connman_network_get_bssid(network);
4150         device = connman_network_get_device(network);
4151
4152         if (device)
4153                 interface = connman_device_get_string(device, "Interface");
4154
4155         connman_network_unref(network);
4156
4157         if (need_bss_transition(freq, snr, strength)) {
4158                 snprintf(bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bssid));
4159                 __connman_technology_notify_roaming_state(interface, "required", bssid_str, NULL);
4160
4161                 if (connman_setting_get_bool("WifiRoamingScan") == false)
4162                         return;
4163
4164                 throw_wifi_scan(device, scan_callback);
4165         }
4166 }
4167
4168 static int network_signalpoll(struct wifi_data *wifi)
4169 {
4170         GSupplicantInterface *interface;
4171         struct connman_network *network;
4172
4173         if (!wifi || !wifi->network)
4174                 return -ENODEV;
4175
4176         wifi->network = connman_network_ref(wifi->network);
4177
4178         interface = wifi->interface;
4179         network = wifi->network;
4180
4181         DBG("network %p", network);
4182
4183         return g_supplicant_interface_signalpoll(interface, signalpoll_callback, network);
4184 }
4185
4186 static gboolean autosignalpoll_timeout(gpointer data)
4187 {
4188         struct wifi_data *wifi = data;
4189
4190         if (!wifi || !wifi->automaxspeed_timeout) {
4191                 DBG("automaxspeed_timeout is found to be zero. i.e. currently in disconnected state. !!");
4192                 return FALSE;
4193         }
4194
4195         int ret = network_signalpoll(wifi);
4196         if (ret < 0) {
4197                 DBG("Fail to get max speed !!");
4198                 wifi->automaxspeed_timeout = 0;
4199
4200                 if (wifi->network)
4201                         connman_network_unref(wifi->network);
4202
4203                 return FALSE;
4204         }
4205
4206         return TRUE;
4207 }
4208 #endif
4209
4210 static struct connman_network_driver network_driver = {
4211         .name           = "wifi",
4212         .type           = CONNMAN_NETWORK_TYPE_WIFI,
4213         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
4214         .probe          = network_probe,
4215         .remove         = network_remove,
4216         .connect        = network_connect,
4217         .disconnect     = network_disconnect,
4218 };
4219
4220 static void interface_added(GSupplicantInterface *interface)
4221 {
4222         const char *ifname = g_supplicant_interface_get_ifname(interface);
4223         const char *driver = g_supplicant_interface_get_driver(interface);
4224 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
4225         /*
4226          * Note: If supplicant interface's driver is wired then skip it,
4227          * because it meanti only for ethernet not Wi-Fi.
4228          */
4229         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
4230                 return;
4231 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
4232
4233 #if defined TIZEN_EXT
4234         bool is_5_0_ghz_supported = g_supplicant_interface_get_is_5_0_ghz_supported(interface);
4235 #endif
4236
4237         struct wifi_data *wifi;
4238
4239         wifi = g_supplicant_interface_get_data(interface);
4240         if (!wifi) {
4241                 wifi = get_pending_wifi_data(ifname);
4242                 if (!wifi)
4243                         return;
4244
4245                 wifi->interface = interface;
4246                 g_supplicant_interface_set_data(interface, wifi);
4247                 p2p_iface_list = g_list_append(p2p_iface_list, wifi);
4248                 wifi->p2p_device = true;
4249         }
4250
4251         DBG("ifname %s driver %s wifi %p tethering %d",
4252                         ifname, driver, wifi, wifi->tethering);
4253
4254         if (!wifi->device) {
4255                 connman_error("WiFi device not set");
4256                 return;
4257         }
4258
4259         connman_device_set_powered(wifi->device, true);
4260 #if defined TIZEN_EXT
4261         connman_device_set_wifi_5ghz_supported(wifi->device, is_5_0_ghz_supported);
4262         /* Max number of SSIDs supported by wlan chipset that can be scanned */
4263         int max_scan_ssids = g_supplicant_interface_get_max_scan_ssids(interface);
4264         connman_device_set_max_scan_ssids(wifi->device, max_scan_ssids);
4265 #endif
4266 }
4267
4268 static bool is_idle(struct wifi_data *wifi)
4269 {
4270         DBG("state %d", wifi->state);
4271
4272         switch (wifi->state) {
4273         case G_SUPPLICANT_STATE_UNKNOWN:
4274         case G_SUPPLICANT_STATE_DISABLED:
4275         case G_SUPPLICANT_STATE_DISCONNECTED:
4276         case G_SUPPLICANT_STATE_INACTIVE:
4277         case G_SUPPLICANT_STATE_SCANNING:
4278                 return true;
4279
4280         case G_SUPPLICANT_STATE_AUTHENTICATING:
4281         case G_SUPPLICANT_STATE_ASSOCIATING:
4282         case G_SUPPLICANT_STATE_ASSOCIATED:
4283         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4284         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4285         case G_SUPPLICANT_STATE_COMPLETED:
4286                 return false;
4287         }
4288
4289         return false;
4290 }
4291
4292 static bool is_idle_wps(GSupplicantInterface *interface,
4293                                                 struct wifi_data *wifi)
4294 {
4295         /* First, let's check if WPS processing did not went wrong */
4296         if (g_supplicant_interface_get_wps_state(interface) ==
4297                 G_SUPPLICANT_WPS_STATE_FAIL)
4298                 return false;
4299
4300         /* Unlike normal connection, being associated while processing wps
4301          * actually means that we are idling. */
4302         switch (wifi->state) {
4303         case G_SUPPLICANT_STATE_UNKNOWN:
4304         case G_SUPPLICANT_STATE_DISABLED:
4305         case G_SUPPLICANT_STATE_DISCONNECTED:
4306         case G_SUPPLICANT_STATE_INACTIVE:
4307         case G_SUPPLICANT_STATE_SCANNING:
4308         case G_SUPPLICANT_STATE_ASSOCIATED:
4309                 return true;
4310         case G_SUPPLICANT_STATE_AUTHENTICATING:
4311         case G_SUPPLICANT_STATE_ASSOCIATING:
4312         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4313         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4314         case G_SUPPLICANT_STATE_COMPLETED:
4315                 return false;
4316         }
4317
4318         return false;
4319 }
4320
4321 static bool handle_wps_completion(GSupplicantInterface *interface,
4322                                         struct connman_network *network,
4323                                         struct connman_device *device,
4324                                         struct wifi_data *wifi)
4325 {
4326         bool wps;
4327
4328         wps = connman_network_get_bool(network, "WiFi.UseWPS");
4329         if (wps) {
4330                 const unsigned char *ssid, *wps_ssid;
4331                 unsigned int ssid_len, wps_ssid_len;
4332                 const char *wps_key;
4333
4334                 /* Checking if we got associated with requested
4335                  * network */
4336                 ssid = connman_network_get_blob(network, "WiFi.SSID",
4337                                                 &ssid_len);
4338
4339                 wps_ssid = g_supplicant_interface_get_wps_ssid(
4340                         interface, &wps_ssid_len);
4341
4342                 if (!wps_ssid || wps_ssid_len != ssid_len ||
4343                                 memcmp(ssid, wps_ssid, ssid_len) != 0) {
4344                         connman_network_set_associating(network, false);
4345 #if defined TIZEN_EXT
4346                         g_supplicant_interface_disconnect(wifi->interface,
4347                                                 disconnect_callback, wifi->network);
4348
4349                         connman_network_set_bool(network, "WiFi.UseWPS", false);
4350                         connman_network_set_string(network, "WiFi.PinWPS", NULL);
4351 #else
4352                         g_supplicant_interface_disconnect(wifi->interface,
4353                                                 disconnect_callback, wifi);
4354 #endif
4355                         return false;
4356                 }
4357
4358                 wps_key = g_supplicant_interface_get_wps_key(interface);
4359 #if defined TIZEN_EXT
4360                 /* Check the passphrase and encrypt it
4361                  */
4362                  int ret;
4363                  gchar *passphrase = g_strdup(wps_key);
4364
4365                  connman_network_set_string(network, "WiFi.PinWPS", NULL);
4366
4367                  if (check_passphrase_ext(network, passphrase) < 0) {
4368                          DBG("[WPS] Invalid passphrase");
4369                          g_free(passphrase);
4370                          return true;
4371                  }
4372
4373                  ret = send_encryption_request(passphrase, network);
4374
4375                  g_free(passphrase);
4376
4377                  if (!ret)
4378                          DBG("[WPS] Encryption request succeeded");
4379                  else
4380                          DBG("[WPS] Encryption request failed %d", ret);
4381
4382 #else
4383                 connman_network_set_string(network, "WiFi.Passphrase",
4384                                         wps_key);
4385
4386                 connman_network_set_string(network, "WiFi.PinWPS", NULL);
4387 #endif
4388         }
4389
4390         return true;
4391 }
4392
4393 static bool handle_assoc_status_code(GSupplicantInterface *interface,
4394                                      struct wifi_data *wifi)
4395 {
4396         if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING &&
4397 #if defined TIZEN_EXT
4398                         wifi->assoc_code > 0 &&
4399 #else
4400                         wifi->assoc_code == ASSOC_STATUS_NO_CLIENT &&
4401 #endif
4402                         wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) {
4403                 wifi->load_shaping_retries ++;
4404                 return TRUE;
4405         }
4406         wifi->load_shaping_retries = 0;
4407         return FALSE;
4408 }
4409
4410 static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
4411                                         struct connman_network *network,
4412                                         struct wifi_data *wifi)
4413 {
4414 #if defined TIZEN_EXT
4415         const char *security;
4416         struct connman_service *service;
4417
4418         if (wifi->connected)
4419                 return false;
4420
4421         security = connman_network_get_string(network, "WiFi.Security");
4422
4423         if (security && g_str_equal(security, "ieee8021x") == true &&
4424                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
4425                 wifi->retries = 0;
4426                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
4427
4428                 return false;
4429         }
4430
4431         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
4432                 return false;
4433 #else
4434         struct connman_service *service;
4435
4436         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
4437                 return false;
4438
4439         if (wifi->connected)
4440                 return false;
4441 #endif
4442
4443         service = connman_service_lookup_from_network(network);
4444         if (!service)
4445                 return false;
4446
4447         wifi->retries++;
4448
4449         if (connman_service_get_favorite(service)) {
4450                 if (wifi->retries < FAVORITE_MAXIMUM_RETRIES)
4451                         return true;
4452         }
4453
4454         wifi->retries = 0;
4455         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
4456
4457         return false;
4458 }
4459
4460 #if defined TIZEN_EXT
4461 static bool handle_wifi_assoc_retry(struct connman_network *network,
4462                                         struct wifi_data *wifi)
4463 {
4464         const char *security;
4465
4466         if (!wifi->network || wifi->connected || wifi->disconnecting ||
4467                         connman_network_get_connecting(network) != true) {
4468                 wifi->assoc_retry_count = 0;
4469                 return false;
4470         }
4471
4472         if (wifi->state != G_SUPPLICANT_STATE_ASSOCIATING &&
4473                         wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) {
4474                 wifi->assoc_retry_count = 0;
4475                 return false;
4476         }
4477
4478         security = connman_network_get_string(network, "WiFi.Security");
4479         if (security && g_str_equal(security, "ieee8021x") == true &&
4480                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
4481                 wifi->assoc_retry_count = 0;
4482                 return false;
4483         }
4484
4485         if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) {
4486                 wifi->assoc_retry_count = 0;
4487
4488                 /* Honestly it's not an invalid-key error,
4489                  * however QA team recommends that the invalid-key error
4490                  * might be better to display for user experience.
4491                  */
4492                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
4493
4494                 return false;
4495         }
4496
4497         return true;
4498 }
4499 #endif
4500
4501 static void interface_state(GSupplicantInterface *interface)
4502 {
4503         struct connman_network *network;
4504         struct connman_device *device;
4505         struct wifi_data *wifi;
4506         GSupplicantState state = g_supplicant_interface_get_state(interface);
4507 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
4508         /*
4509          * Note: If supplicant interface's driver is wired then skip it,
4510          * because it meanti only for ethernet not Wi-Fi.
4511          */
4512         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
4513                 return;
4514 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
4515
4516         bool wps;
4517         bool old_connected;
4518
4519         wifi = g_supplicant_interface_get_data(interface);
4520
4521         DBG("wifi %p interface state %d", wifi, state);
4522
4523         if (!wifi)
4524                 return;
4525
4526         device = wifi->device;
4527         if (!device)
4528                 return;
4529
4530         if (state == G_SUPPLICANT_STATE_COMPLETED) {
4531                 if (wifi->tethering_param) {
4532                         g_free(wifi->tethering_param->ssid);
4533                         g_free(wifi->tethering_param);
4534                         wifi->tethering_param = NULL;
4535                 }
4536
4537                 if (wifi->tethering)
4538                         stop_autoscan(device);
4539         }
4540
4541         if (g_supplicant_interface_get_ready(interface) &&
4542                                         !wifi->interface_ready) {
4543                 wifi->interface_ready = true;
4544                 finalize_interface_creation(wifi);
4545         }
4546
4547         network = wifi->network;
4548         if (!network)
4549                 return;
4550
4551         switch (state) {
4552         case G_SUPPLICANT_STATE_SCANNING:
4553 #if defined TIZEN_EXT
4554                 if (wifi->automaxspeed_timeout != 0) {
4555                         g_source_remove(wifi->automaxspeed_timeout);
4556                         wifi->automaxspeed_timeout = 0;
4557                         DBG("Remove signalpoll timer!!");
4558                 }
4559 #endif
4560                 if (wifi->connected)
4561                         connman_network_set_connected(network, false);
4562
4563                 break;
4564
4565         case G_SUPPLICANT_STATE_AUTHENTICATING:
4566         case G_SUPPLICANT_STATE_ASSOCIATING:
4567 #if defined TIZEN_EXT
4568                 reset_autoscan(device);
4569 #else
4570                 stop_autoscan(device);
4571 #endif
4572
4573                 if (!wifi->connected)
4574                         connman_network_set_associating(network, true);
4575
4576                 break;
4577
4578         case G_SUPPLICANT_STATE_COMPLETED:
4579 #if defined TIZEN_EXT
4580                 /* though it should be already reset: */
4581                 reset_autoscan(device);
4582
4583                 wifi->assoc_retry_count = 0;
4584
4585                 wifi->scan_pending_network = NULL;
4586
4587                 /* should be cleared scanning flag */
4588                 bool scanning = connman_device_get_scanning(device,
4589                                                CONNMAN_SERVICE_TYPE_WIFI);
4590                 if (scanning){
4591                         connman_device_set_scanning(device,
4592                                 CONNMAN_SERVICE_TYPE_WIFI, false);
4593                         connman_device_unref(device);
4594                 }
4595
4596                 if (!wifi->automaxspeed_timeout) {
4597                         DBG("Going to start signalpoll timer!!");
4598                         int ret = network_signalpoll(wifi);
4599                         if (ret < 0)
4600                                 DBG("Fail to get max speed !!");
4601                         else
4602                                 wifi->automaxspeed_timeout = g_timeout_add_seconds(10, autosignalpoll_timeout, wifi);
4603                 }
4604
4605                 g_hash_table_remove_all(failed_bssids);
4606 #else
4607                 /* though it should be already stopped: */
4608                 stop_autoscan(device);
4609 #endif
4610
4611                 if (!handle_wps_completion(interface, network, device, wifi))
4612                         break;
4613
4614                 connman_network_set_connected(network, true);
4615
4616                 wifi->disconnect_code = 0;
4617                 wifi->assoc_code = 0;
4618                 wifi->load_shaping_retries = 0;
4619                 break;
4620
4621         case G_SUPPLICANT_STATE_DISCONNECTED:
4622 #if defined TIZEN_EXT
4623                 connman_network_set_strength(network, 0);
4624                 connman_network_set_maxspeed(network, 0);
4625
4626                 if (wifi->automaxspeed_timeout != 0) {
4627                         g_source_remove(wifi->automaxspeed_timeout);
4628                         wifi->automaxspeed_timeout = 0;
4629                         DBG("Remove signalpoll timer!!");
4630                 }
4631 #endif
4632                 /*
4633                  * If we're in one of the idle modes, we have
4634                  * not started association yet and thus setting
4635                  * those ones to FALSE could cancel an association
4636                  * in progress.
4637                  */
4638                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
4639                 if (wps)
4640                         if (is_idle_wps(interface, wifi))
4641                                 break;
4642
4643                 if (is_idle(wifi))
4644                         break;
4645
4646 #if defined TIZEN_EXT
4647                 if (handle_assoc_status_code(interface, wifi)) {
4648                         const char *group = connman_network_get_group(network);
4649                         GSupplicantNetwork *supplicant_network;
4650                         GSList *bssid_list = NULL;
4651                         guint bssid_length = 0;
4652
4653                         if (group) {
4654                                 supplicant_network = g_supplicant_interface_get_network(interface, group);
4655
4656                                 connman_network_set_assoc_reject_table(network,
4657                                         g_supplicant_network_get_assoc_reject_table(supplicant_network));
4658
4659                                 g_supplicant_network_update_assoc_reject(interface, supplicant_network);
4660                         }
4661
4662                         bssid_list = (GSList *)connman_network_get_bssid_list(network);
4663                         if (bssid_list)
4664                                 bssid_length = g_slist_length(bssid_list);
4665
4666                         if (bssid_length > 1 && bssid_length > g_hash_table_size(failed_bssids)) {
4667                                 network_connect(network);
4668                                 break;
4669                         }
4670
4671                         wifi->load_shaping_retries = 0;
4672                 }
4673
4674                 g_hash_table_remove_all(failed_bssids);
4675 #else
4676                 if (handle_assoc_status_code(interface, wifi))
4677                         break;
4678 #endif
4679
4680                 /* If previous state was 4way-handshake, then
4681                  * it's either: psk was incorrect and thus we retry
4682                  * or if we reach the maximum retries we declare the
4683                  * psk as wrong */
4684                 if (handle_4way_handshake_failure(interface,
4685                                                 network, wifi))
4686                         break;
4687
4688                 /* See table 8-36 Reason codes in IEEE Std 802.11 */
4689                 switch (wifi->disconnect_code) {
4690                 case 1: /* Unspecified reason */
4691                         /* Let's assume it's because we got blocked */
4692
4693                 case 6: /* Class 2 frame received from nonauthenticated STA */
4694                         connman_network_set_error(network,
4695                                                 CONNMAN_NETWORK_ERROR_BLOCKED);
4696                         break;
4697
4698                 default:
4699                         break;
4700                 }
4701
4702 #if defined TIZEN_EXT
4703                 /* Some of Wi-Fi networks are not comply Wi-Fi specification.
4704                  * Retry association until its retry count is expired */
4705                 if (handle_wifi_assoc_retry(network, wifi) == true) {
4706                         throw_wifi_scan(wifi->device, scan_callback);
4707                         wifi->scan_pending_network = wifi->network;
4708                         break;
4709                 }
4710
4711                 if(wifi->disconnect_code > 0){
4712                         DBG("Set disconnect reason code(%d)", wifi->disconnect_code);
4713                         connman_network_set_disconnect_reason(network, wifi->disconnect_code);
4714                 }
4715 #endif
4716
4717                 if (network != wifi->pending_network) {
4718                         connman_network_set_connected(network, false);
4719                         connman_network_set_associating(network, false);
4720                 }
4721                 wifi->disconnecting = false;
4722
4723                 start_autoscan(device);
4724
4725                 break;
4726
4727         case G_SUPPLICANT_STATE_INACTIVE:
4728 #if defined TIZEN_EXT
4729                 if (handle_wps_completion(interface, network, device, wifi) == false)
4730                         break;
4731 #endif
4732                 connman_network_set_associating(network, false);
4733                 start_autoscan(device);
4734
4735                 break;
4736
4737         case G_SUPPLICANT_STATE_UNKNOWN:
4738         case G_SUPPLICANT_STATE_DISABLED:
4739         case G_SUPPLICANT_STATE_ASSOCIATED:
4740         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4741         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4742                 break;
4743         }
4744
4745         old_connected = wifi->connected;
4746         wifi->state = state;
4747
4748         /* Saving wpa_s state policy:
4749          * If connected and if the state changes are roaming related:
4750          * --> We stay connected
4751          * If completed
4752          * --> We are connected
4753          * All other case:
4754          * --> We are not connected
4755          * */
4756         switch (state) {
4757         case G_SUPPLICANT_STATE_AUTHENTICATING:
4758         case G_SUPPLICANT_STATE_ASSOCIATING:
4759         case G_SUPPLICANT_STATE_ASSOCIATED:
4760         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4761         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4762                 if (wifi->connected)
4763                         connman_warn("Probably roaming right now!"
4764                                                 " Staying connected...");
4765                 break;
4766         case G_SUPPLICANT_STATE_SCANNING:
4767                 wifi->connected = false;
4768
4769                 if (old_connected)
4770                         start_autoscan(device);
4771                 break;
4772         case G_SUPPLICANT_STATE_COMPLETED:
4773                 wifi->connected = true;
4774                 break;
4775         default:
4776                 wifi->connected = false;
4777                 break;
4778         }
4779
4780         DBG("DONE");
4781 }
4782
4783 static void interface_removed(GSupplicantInterface *interface)
4784 {
4785         const char *ifname = g_supplicant_interface_get_ifname(interface);
4786         struct wifi_data *wifi;
4787 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
4788         /*
4789          * Note: If supplicant interface's driver is wired then skip it,
4790          * because it meanti only for ethernet not Wi-Fi.
4791          */
4792         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
4793                 return;
4794 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
4795
4796
4797         DBG("ifname %s", ifname);
4798
4799         wifi = g_supplicant_interface_get_data(interface);
4800
4801 #if defined TIZEN_EXT_WIFI_MESH
4802         if (wifi && wifi->mesh_interface) {
4803                 DBG("Notify mesh interface remove");
4804                 connman_mesh_notify_interface_remove(true);
4805                 struct wifi_mesh_info *mesh_info = wifi->mesh_info;
4806                 g_free(mesh_info->parent_ifname);
4807                 g_free(mesh_info->ifname);
4808                 g_free(mesh_info->identifier);
4809                 g_free(mesh_info);
4810                 wifi->mesh_interface = false;
4811                 wifi->mesh_info = NULL;
4812                 return;
4813         }
4814 #endif
4815
4816         if (wifi)
4817                 wifi->interface = NULL;
4818
4819         if (wifi && wifi->tethering)
4820                 return;
4821
4822         if (!wifi || !wifi->device) {
4823                 DBG("wifi interface already removed");
4824                 return;
4825         }
4826
4827         connman_device_set_powered(wifi->device, false);
4828
4829         check_p2p_technology();
4830 #if defined TIZEN_EXT_WIFI_MESH
4831         check_mesh_technology();
4832 #endif
4833 }
4834
4835 static void set_device_type(const char *type, char dev_type[17])
4836 {
4837         const char *oui = "0050F204";
4838         const char *category = "0001";
4839         const char *sub_category = "0000";
4840
4841         if (!g_strcmp0(type, "handset")) {
4842                 category = "000A";
4843                 sub_category = "0005";
4844         } else if (!g_strcmp0(type, "vm") || !g_strcmp0(type, "container"))
4845                 sub_category = "0001";
4846         else if (!g_strcmp0(type, "server"))
4847                 sub_category = "0002";
4848         else if (!g_strcmp0(type, "laptop"))
4849                 sub_category = "0005";
4850         else if (!g_strcmp0(type, "desktop"))
4851                 sub_category = "0006";
4852         else if (!g_strcmp0(type, "tablet"))
4853                 sub_category = "0009";
4854         else if (!g_strcmp0(type, "watch"))
4855                 category = "00FF";
4856
4857         snprintf(dev_type, 17, "%s%s%s", category, oui, sub_category);
4858 }
4859
4860 static void p2p_support(GSupplicantInterface *interface)
4861 {
4862         char dev_type[17] = {};
4863         const char *hostname;
4864 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
4865         /*
4866          * Note: If supplicant interface's driver is wired then skip it,
4867          * because it meanti only for ethernet not Wi-Fi.
4868          */
4869         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
4870                 return;
4871 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
4872
4873
4874         DBG("");
4875
4876         if (!interface)
4877                 return;
4878
4879         if (!g_supplicant_interface_has_p2p(interface))
4880                 return;
4881
4882         if (connman_technology_driver_register(&p2p_tech_driver) < 0) {
4883                 DBG("Could not register P2P technology driver");
4884                 return;
4885         }
4886
4887         hostname = connman_utsname_get_hostname();
4888         if (!hostname)
4889                 hostname = "ConnMan";
4890
4891         set_device_type(connman_machine_get_type(), dev_type);
4892         g_supplicant_interface_set_p2p_device_config(interface,
4893                                                         hostname, dev_type);
4894         connman_peer_driver_register(&peer_driver);
4895 }
4896
4897 static void scan_started(GSupplicantInterface *interface)
4898 {
4899 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
4900         /*
4901          * Note: If supplicant interface's driver is wired then skip it,
4902          * because it meanti only for ethernet not Wi-Fi.
4903          */
4904         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
4905                 return;
4906 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
4907
4908         DBG("");
4909 }
4910
4911 static void scan_finished(GSupplicantInterface *interface)
4912 {
4913 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
4914         /*
4915          * Note: If supplicant interface's driver is wired then skip it,
4916          * because it meanti only for ethernet not Wi-Fi.
4917          */
4918         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
4919                 return;
4920 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
4921
4922 #if defined TIZEN_EXT
4923         struct wifi_data *wifi;
4924         bool is_associating = false;
4925         static bool is_scanning = true;
4926 #endif
4927
4928         DBG("");
4929
4930 #if defined TIZEN_EXT
4931         wifi = g_supplicant_interface_get_data(interface);
4932         if (wifi && wifi->scan_pending_network) {
4933                 network_connect(wifi->scan_pending_network);
4934                 wifi->scan_pending_network = NULL;
4935         }
4936
4937         //service state - associating
4938         if(!wifi || !wifi->network)
4939                 return;
4940
4941         is_associating = connman_network_get_associating(wifi->network);
4942         if(is_associating && is_scanning){
4943                 is_scanning = false;
4944                 DBG("send scan for connecting");
4945                 throw_wifi_scan(wifi->device, scan_callback);
4946
4947                 return;
4948         }
4949         is_scanning = true;
4950
4951         //go scan
4952
4953 #endif
4954 }
4955
4956 static void ap_create_fail(GSupplicantInterface *interface)
4957 {
4958 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
4959         /*
4960          * Note: If supplicant interface's driver is wired then skip it,
4961          * because it meanti only for ethernet not Wi-Fi.
4962          */
4963         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
4964                 return;
4965 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
4966
4967         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
4968         int ret;
4969
4970         if ((wifi->tethering) && (wifi->tethering_param)) {
4971                 DBG("%s create AP fail \n",
4972                                 g_supplicant_interface_get_ifname(wifi->interface));
4973
4974                 connman_inet_remove_from_bridge(wifi->index, wifi->bridge);
4975                 wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
4976                 wifi->tethering = false;
4977
4978                 ret = tech_set_tethering(wifi->tethering_param->technology,
4979                                 wifi->tethering_param->ssid->ssid,
4980                                 wifi->tethering_param->ssid->passphrase,
4981                                 wifi->bridge, true);
4982
4983                 if ((ret == -EOPNOTSUPP) && (wifi_technology)) {
4984                         connman_technology_tethering_notify(wifi_technology,false);
4985                 }
4986
4987                 g_free(wifi->tethering_param->ssid);
4988                 g_free(wifi->tethering_param);
4989                 wifi->tethering_param = NULL;
4990         }
4991 }
4992
4993 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
4994 {
4995         unsigned char strength;
4996
4997         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
4998 #if !defined TIZEN_EXT
4999         if (strength > 100)
5000                 strength = 100;
5001 #endif
5002
5003         return strength;
5004 }
5005
5006 #if defined TIZEN_EXT_WIFI_MESH
5007 static void mesh_peer_added(GSupplicantNetwork *supplicant_network)
5008 {
5009         GSupplicantInterface *interface;
5010         struct wifi_data *wifi;
5011         const char *name, *security;
5012         struct connman_mesh *connman_mesh;
5013         struct wifi_mesh_info *mesh_info;
5014         const unsigned char *bssid;
5015         const char *identifier;
5016         char *address;
5017         uint16_t frequency;
5018         int ret;
5019
5020         interface = g_supplicant_network_get_interface(supplicant_network);
5021         wifi = g_supplicant_interface_get_data(interface);
5022         if (!wifi || !wifi->mesh_interface) {
5023                 DBG("Virtual Mesh interface not created");
5024                 return;
5025         }
5026
5027         bssid = g_supplicant_network_get_bssid(supplicant_network);
5028         address = g_malloc0(19);
5029         snprintf(address, 19, "%02x:%02x:%02x:%02x:%02x:%02x", bssid[0], bssid[1],
5030                                                                  bssid[2], bssid[3], bssid[4], bssid[5]);
5031
5032         identifier = g_supplicant_network_get_identifier(supplicant_network);
5033         name = g_supplicant_network_get_name(supplicant_network);
5034         security = g_supplicant_network_get_security(supplicant_network);
5035         frequency = g_supplicant_network_get_frequency(supplicant_network);
5036
5037         mesh_info = wifi->mesh_info;
5038         connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
5039         if (connman_mesh)
5040                 goto done;
5041
5042         DBG("Mesh Peer name %s identifier %s security %s added", name, identifier,
5043                                         security);
5044         connman_mesh = connman_mesh_create(mesh_info->identifier, identifier);
5045         connman_mesh_set_name(connman_mesh, name);
5046         connman_mesh_set_security(connman_mesh, security);
5047         connman_mesh_set_frequency(connman_mesh, frequency);
5048         connman_mesh_set_address(connman_mesh, address);
5049         connman_mesh_set_index(connman_mesh, mesh_info->index);
5050         connman_mesh_set_strength(connman_mesh,
5051                                                 calculate_strength(supplicant_network));
5052         connman_mesh_set_peer_type(connman_mesh, CONNMAN_MESH_PEER_TYPE_DISCOVERED);
5053
5054         ret = connman_mesh_register(connman_mesh);
5055         if (ret == -EALREADY)
5056                 DBG("Mesh Peer is already registered");
5057
5058 done:
5059         g_free(address);
5060 }
5061
5062 static void mesh_peer_removed(GSupplicantNetwork *supplicant_network)
5063 {
5064         GSupplicantInterface *interface;
5065         struct wifi_data *wifi;
5066         struct connman_mesh *connman_mesh;
5067         struct wifi_mesh_info *mesh_info;
5068         const char *identifier;
5069
5070         interface = g_supplicant_network_get_interface(supplicant_network);
5071         wifi = g_supplicant_interface_get_data(interface);
5072         if (!wifi || !wifi->mesh_interface) {
5073                 DBG("Virtual Mesh interface not created");
5074                 return;
5075         }
5076
5077         identifier = g_supplicant_network_get_identifier(supplicant_network);
5078         if (!identifier) {
5079                 DBG("Failed to get Mesh Peer identifier");
5080                 return;
5081         }
5082
5083         mesh_info = wifi->mesh_info;
5084         connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
5085         if (connman_mesh) {
5086                 /* Do not unregister connected mesh peer */
5087                 if (connman_mesh_peer_is_connected_state(connman_mesh)) {
5088                         DBG("Mesh Peer %s is connected", identifier);
5089                         return;
5090                 }
5091                 DBG("Mesh Peer identifier %s removed", identifier);
5092                 connman_mesh_unregister(connman_mesh);
5093         }
5094 }
5095 #endif
5096
5097
5098 #if defined TIZEN_EXT
5099 static GSList *get_supported_security_list(unsigned int keymgmt,
5100                                         bool owe_transition_mode,
5101                                         GSupplicantNetwork *supplicant_network)
5102 {
5103         GSList *sec_list = NULL;
5104         dbus_bool_t privacy = g_supplicant_network_get_privacy(supplicant_network);
5105         const char *enc_mode = g_supplicant_network_get_enc_mode(supplicant_network);
5106
5107         if (keymgmt &
5108                         (G_SUPPLICANT_KEYMGMT_WPA_EAP |
5109                                         G_SUPPLICANT_KEYMGMT_WPA_EAP_256))
5110                 sec_list = g_slist_prepend (sec_list, "ieee8021x");
5111         else if (keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_EAP)
5112                 sec_list = g_slist_prepend (sec_list, "ft_ieee8021x");
5113
5114         if (sec_list)
5115                 return sec_list;
5116
5117         if (keymgmt &
5118                         (G_SUPPLICANT_KEYMGMT_WPA_PSK |
5119                                         G_SUPPLICANT_KEYMGMT_WPA_PSK_256)) {
5120                 if (!g_strcmp0(enc_mode, "aes"))
5121                         sec_list = g_slist_prepend (sec_list, "rsn");
5122                 else if (!g_strcmp0(enc_mode, "tkip"))
5123                         sec_list = g_slist_prepend (sec_list, "psk");
5124                 else if (!g_strcmp0(enc_mode, "mixed")) {
5125                         sec_list = g_slist_prepend (sec_list, "psk");
5126                         sec_list = g_slist_prepend (sec_list, "rsn");
5127                 }
5128         } else if (keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_PSK)
5129                 sec_list = g_slist_prepend (sec_list, "ft_psk");
5130
5131         if (keymgmt & G_SUPPLICANT_KEYMGMT_SAE)
5132                 sec_list = g_slist_prepend (sec_list, "sae");
5133         if (keymgmt & G_SUPPLICANT_KEYMGMT_OWE || owe_transition_mode)
5134                 sec_list = g_slist_prepend (sec_list, "owe");
5135         if (keymgmt & G_SUPPLICANT_KEYMGMT_DPP)
5136                 sec_list = g_slist_prepend (sec_list, "dpp");
5137
5138         if (sec_list)
5139                 return sec_list;
5140
5141         if (privacy)
5142                 sec_list = g_slist_prepend (sec_list, "wep");
5143         else
5144                 sec_list = g_slist_prepend (sec_list, "none");
5145
5146         return sec_list;
5147 }
5148 #endif
5149
5150 static void network_added(GSupplicantNetwork *supplicant_network)
5151 {
5152         struct connman_network *network;
5153         GSupplicantInterface *interface;
5154         struct wifi_data *wifi;
5155         const char *name, *identifier, *security, *group, *mode;
5156         const unsigned char *ssid;
5157         unsigned int ssid_len;
5158         bool wps;
5159         bool wps_pbc;
5160         bool wps_ready;
5161         bool wps_advertizing;
5162
5163 #if defined TIZEN_EXT
5164         bool owe_transition_mode;
5165         const unsigned char *transition_mode_ssid;
5166         const unsigned char *transition_mode_bssid;
5167         unsigned int transition_mode_ssid_len;
5168         unsigned int keymgmt;
5169         GSList *vsie_list = NULL;
5170         GSList *sec_list = NULL;
5171         const unsigned char *country_code;
5172         ieee80211_modes_e phy_mode;
5173 #endif
5174
5175         mode = g_supplicant_network_get_mode(supplicant_network);
5176         identifier = g_supplicant_network_get_identifier(supplicant_network);
5177 #if defined TIZEN_EXT
5178         if (!simplified_log)
5179 #endif
5180         DBG("%s", identifier);
5181
5182         if (!g_strcmp0(mode, "adhoc"))
5183                 return;
5184
5185 #if defined TIZEN_EXT_WIFI_MESH
5186         if (!g_strcmp0(mode, "mesh")) {
5187                 mesh_peer_added(supplicant_network);
5188                 return;
5189         }
5190 #endif
5191
5192         interface = g_supplicant_network_get_interface(supplicant_network);
5193 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5194         /*
5195          * Note: If supplicant interface's driver is wired then skip it,
5196          * because it meanti only for ethernet not Wi-Fi.
5197          */
5198         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5199                 return;
5200 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5201
5202         wifi = g_supplicant_interface_get_data(interface);
5203         name = g_supplicant_network_get_name(supplicant_network);
5204         security = g_supplicant_network_get_security(supplicant_network);
5205         group = g_supplicant_network_get_identifier(supplicant_network);
5206         wps = g_supplicant_network_get_wps(supplicant_network);
5207         wps_pbc = g_supplicant_network_is_wps_pbc(supplicant_network);
5208         wps_ready = g_supplicant_network_is_wps_active(supplicant_network);
5209         wps_advertizing = g_supplicant_network_is_wps_advertizing(
5210                                                         supplicant_network);
5211
5212         if (!wifi)
5213                 return;
5214
5215         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
5216
5217         network = connman_device_get_network(wifi->device, identifier);
5218
5219         if (!network) {
5220                 network = connman_network_create(identifier,
5221                                                 CONNMAN_NETWORK_TYPE_WIFI);
5222                 if (!network)
5223                         return;
5224
5225                 connman_network_set_index(network, wifi->index);
5226
5227                 if (connman_device_add_network(wifi->device, network) < 0) {
5228                         connman_network_unref(network);
5229                         return;
5230                 }
5231
5232                 wifi->networks = g_slist_prepend(wifi->networks, network);
5233         }
5234
5235         if (name && name[0] != '\0')
5236                 connman_network_set_name(network, name);
5237
5238         connman_network_set_blob(network, "WiFi.SSID",
5239                                                 ssid, ssid_len);
5240 #if defined TIZEN_EXT
5241         vsie_list = (GSList *)g_supplicant_network_get_wifi_vsie(supplicant_network);
5242         if (vsie_list)
5243                 connman_network_set_vsie_list(network, vsie_list);
5244         else
5245                 DBG("vsie_list is NULL");
5246         country_code = g_supplicant_network_get_countrycode(supplicant_network);
5247         connman_network_set_countrycode(network, country_code);
5248         phy_mode = g_supplicant_network_get_phy_mode(supplicant_network);
5249         connman_network_set_phy_mode(network, phy_mode);
5250 #endif
5251         connman_network_set_string(network, "WiFi.Security", security);
5252         connman_network_set_strength(network,
5253                                 calculate_strength(supplicant_network));
5254         connman_network_set_bool(network, "WiFi.WPS", wps);
5255         connman_network_set_bool(network, "WiFi.WPSAdvertising",
5256                                 wps_advertizing);
5257
5258         if (wps) {
5259                 /* Is AP advertizing for WPS association?
5260                  * If so, we decide to use WPS by default */
5261                 if (wps_ready && wps_pbc &&
5262                                                 wps_advertizing)
5263 #if !defined TIZEN_EXT
5264                         connman_network_set_bool(network, "WiFi.UseWPS", true);
5265 #else
5266                         DBG("wps is activating by ap but ignore it.");
5267 #endif
5268         }
5269
5270         connman_network_set_frequency(network,
5271                         g_supplicant_network_get_frequency(supplicant_network));
5272
5273 #if defined TIZEN_EXT
5274         keymgmt = g_supplicant_network_get_keymgmt(supplicant_network);
5275         connman_network_set_bssid(network,
5276                         g_supplicant_network_get_bssid(supplicant_network));
5277         owe_transition_mode = (bool)g_supplicant_network_get_transition_mode(supplicant_network);
5278         connman_network_set_bool(network, "WiFi.TRANSITION_MODE", owe_transition_mode);
5279         if (owe_transition_mode) {
5280                 transition_mode_ssid = (unsigned char *)g_supplicant_network_get_transition_mode_ssid(supplicant_network, &transition_mode_ssid_len);
5281                 connman_network_set_blob(network, "WiFi.TRANSITION_MODE_SSID",
5282                                                         transition_mode_ssid, transition_mode_ssid_len);
5283                 transition_mode_bssid = g_supplicant_network_get_transition_mode_bssid(supplicant_network);
5284                 connman_network_set_transition_mode_bssid(network, transition_mode_bssid);
5285         }
5286
5287         sec_list = get_supported_security_list(keymgmt,
5288                         owe_transition_mode, supplicant_network);
5289
5290         connman_network_set_sec_list(network, sec_list);
5291         connman_network_set_maxrate(network,
5292                         g_supplicant_network_get_maxrate(supplicant_network));
5293         connman_network_set_enc_mode(network,
5294                         g_supplicant_network_get_enc_mode(supplicant_network));
5295         connman_network_set_rsn_mode(network,
5296                         g_supplicant_network_get_rsn_mode(supplicant_network));
5297         connman_network_set_keymgmt(network, keymgmt);
5298         connman_network_set_bool(network, "WiFi.HS20AP",
5299                         g_supplicant_network_is_hs20AP(supplicant_network));
5300         connman_network_set_bssid_list(network,
5301                         (GSList *)g_supplicant_network_get_bssid_list(supplicant_network));
5302         connman_network_set_last_connected_bssid(network,
5303                         g_supplicant_network_get_last_connected_bssid(supplicant_network));
5304         connman_network_set_assoc_reject_table(network,
5305                         g_supplicant_network_get_assoc_reject_table(supplicant_network));
5306 #endif
5307         connman_network_set_available(network, true);
5308         connman_network_set_string(network, "WiFi.Mode", mode);
5309
5310 #if defined TIZEN_EXT
5311         if (group)
5312 #else
5313         if (ssid)
5314 #endif
5315                 connman_network_set_group(network, group);
5316
5317 #if defined TIZEN_EXT
5318         g_supplicant_network_set_last_connected_bssid(supplicant_network,
5319                         connman_network_get_last_connected_bssid(network));
5320 #endif
5321
5322 #if defined TIZEN_EXT
5323         if (wifi_first_scan == true)
5324                 found_with_first_scan = true;
5325 #endif
5326
5327         if (wifi->hidden && ssid) {
5328 #if defined TIZEN_EXT
5329                 if (network_security(wifi->hidden->security) ==
5330                         network_security(security) &&
5331 #else
5332                 if (!g_strcmp0(wifi->hidden->security, security) &&
5333 #endif
5334                                 wifi->hidden->ssid_len == ssid_len &&
5335                                 !memcmp(wifi->hidden->ssid, ssid, ssid_len)) {
5336                         connman_network_connect_hidden(network,
5337                                         wifi->hidden->identity,
5338                                         wifi->hidden->passphrase,
5339                                         wifi->hidden->user_data);
5340                         wifi->hidden->user_data = NULL;
5341                         hidden_free(wifi->hidden);
5342                         wifi->hidden = NULL;
5343                 }
5344         }
5345 }
5346
5347 static void network_removed(GSupplicantNetwork *network)
5348 {
5349         GSupplicantInterface *interface;
5350         struct wifi_data *wifi;
5351         const char *name, *identifier;
5352         struct connman_network *connman_network;
5353
5354 #if defined TIZEN_EXT_WIFI_MESH
5355         const char *mode;
5356         mode = g_supplicant_network_get_mode(network);
5357         if (!g_strcmp0(mode, "mesh")) {
5358                 mesh_peer_removed(network);
5359                 return;
5360         }
5361 #endif
5362
5363         interface = g_supplicant_network_get_interface(network);
5364 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5365         /*
5366          * Note: If supplicant interface's driver is wired then skip it,
5367          * because it meanti only for ethernet not Wi-Fi.
5368          */
5369         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5370                 return;
5371 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5372
5373         wifi = g_supplicant_interface_get_data(interface);
5374         identifier = g_supplicant_network_get_identifier(network);
5375         name = g_supplicant_network_get_name(network);
5376
5377         DBG("name %s", name);
5378
5379         if (!wifi)
5380                 return;
5381
5382         connman_network = connman_device_get_network(wifi->device, identifier);
5383         if (!connman_network)
5384                 return;
5385
5386 #if defined TIZEN_EXT
5387         if (connman_network == wifi->scan_pending_network)
5388                 wifi->scan_pending_network = NULL;
5389
5390         if (connman_network == wifi->pending_network)
5391                 wifi->pending_network = NULL;
5392
5393         if(connman_network_get_connecting(connman_network) == true){
5394                 connman_network_set_connected(connman_network, false);
5395         }
5396 #endif
5397
5398         wifi->networks = g_slist_remove(wifi->networks, connman_network);
5399
5400         connman_device_remove_network(wifi->device, connman_network);
5401         connman_network_unref(connman_network);
5402 }
5403
5404 static void network_changed(GSupplicantNetwork *network, const char *property)
5405 {
5406         GSupplicantInterface *interface;
5407         struct wifi_data *wifi;
5408         const char *name, *identifier;
5409         struct connman_network *connman_network;
5410         bool update_needed;
5411
5412 #if defined TIZEN_EXT
5413         const unsigned char *bssid;
5414         unsigned int maxrate;
5415         uint16_t frequency;
5416         bool wps;
5417         const unsigned char *country_code;
5418         ieee80211_modes_e phy_mode;
5419         GSList *bssid_list;
5420 #endif
5421
5422         interface = g_supplicant_network_get_interface(network);
5423 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5424         /*
5425          * Note: If supplicant interface's driver is wired then skip it,
5426          * because it meanti only for ethernet not Wi-Fi.
5427          */
5428         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5429                 return;
5430 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5431
5432         wifi = g_supplicant_interface_get_data(interface);
5433         identifier = g_supplicant_network_get_identifier(network);
5434         name = g_supplicant_network_get_name(network);
5435
5436 #if defined TIZEN_EXT
5437         if (!simplified_log)
5438                 DBG("name %s property %s", name, property);
5439 #else
5440         DBG("name %s", name);
5441 #endif
5442
5443         if (!wifi)
5444                 return;
5445
5446         connman_network = connman_device_get_network(wifi->device, identifier);
5447         if (!connman_network)
5448                 return;
5449
5450         if (g_str_equal(property, "WPSCapabilities")) {
5451                 bool wps;
5452                 bool wps_pbc;
5453                 bool wps_ready;
5454                 bool wps_advertizing;
5455
5456                 wps = g_supplicant_network_get_wps(network);
5457                 wps_pbc = g_supplicant_network_is_wps_pbc(network);
5458                 wps_ready = g_supplicant_network_is_wps_active(network);
5459                 wps_advertizing =
5460                         g_supplicant_network_is_wps_advertizing(network);
5461
5462                 connman_network_set_bool(connman_network, "WiFi.WPS", wps);
5463                 connman_network_set_bool(connman_network,
5464                                 "WiFi.WPSAdvertising", wps_advertizing);
5465
5466                 if (wps) {
5467                         /*
5468                          * Is AP advertizing for WPS association?
5469                          * If so, we decide to use WPS by default
5470                          */
5471                         if (wps_ready && wps_pbc && wps_advertizing)
5472                                 connman_network_set_bool(connman_network,
5473                                                         "WiFi.UseWPS", true);
5474                 }
5475
5476                 update_needed = true;
5477         } else if (g_str_equal(property, "Signal")) {
5478                 connman_network_set_strength(connman_network,
5479                                         calculate_strength(network));
5480                 update_needed = true;
5481         }
5482 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
5483         else if (g_str_equal(property, "LastConnectedBSSID")) {
5484                 const char *ident, *group;
5485                 char *service_ident;
5486                 bool need_save;
5487
5488                 ident = connman_device_get_ident(wifi->device);
5489                 group = connman_network_get_group(connman_network);
5490                 if (ident && group) {
5491                         service_ident = g_strdup_printf("%s_%s_%s",
5492                                 __connman_network_get_type(connman_network), ident, group);
5493
5494                         need_save = connman_device_set_last_connected_ident(wifi->device, service_ident);
5495                         if (need_save)
5496                                 connman_device_save_last_connected(wifi->device);
5497
5498                         g_free(service_ident);
5499                 }
5500
5501                 connman_network_set_last_connected_bssid(connman_network,
5502                                         g_supplicant_network_get_last_connected_bssid(network));
5503
5504                 update_needed = true;
5505         }
5506 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
5507 #if defined TIZEN_EXT
5508         else if (g_str_equal(property, "UpdateAssocReject")) {
5509                 connman_network_set_assoc_reject_table(connman_network,
5510                                         g_supplicant_network_get_assoc_reject_table(network));
5511                 update_needed = true;
5512         }
5513 #endif
5514         else
5515                 update_needed = false;
5516
5517         if (update_needed)
5518                 connman_network_update(connman_network);
5519
5520 #if defined TIZEN_EXT
5521         bssid = g_supplicant_network_get_bssid(network);
5522         maxrate = g_supplicant_network_get_maxrate(network);
5523         frequency = g_supplicant_network_get_frequency(network);
5524         wps = g_supplicant_network_get_wps(network);
5525         phy_mode = g_supplicant_network_get_phy_mode(network);
5526
5527         connman_network_set_bssid(connman_network, bssid);
5528         connman_network_set_maxrate(connman_network, maxrate);
5529         connman_network_set_frequency(connman_network, frequency);
5530         connman_network_set_bool(connman_network, "WiFi.WPS", wps);
5531         country_code = g_supplicant_network_get_countrycode(network);
5532         connman_network_set_countrycode(connman_network, country_code);
5533         bssid_list = (GSList *)g_supplicant_network_get_bssid_list(network);
5534         connman_network_set_bssid_list(connman_network, bssid_list);
5535         connman_network_set_phy_mode(connman_network, phy_mode);
5536
5537         if (g_str_equal(property, "CheckMultiBssidConnect") &&
5538                         connman_network_get_associating(connman_network))
5539                 network_connect(connman_network);
5540 #endif
5541 }
5542
5543 static void network_associated(GSupplicantNetwork *network)
5544 {
5545         GSupplicantInterface *interface;
5546         struct wifi_data *wifi;
5547         struct connman_network *connman_network;
5548         const char *identifier;
5549
5550         DBG("");
5551
5552         interface = g_supplicant_network_get_interface(network);
5553         if (!interface)
5554                 return;
5555 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5556         /*
5557          * Note: If supplicant interface's driver is wired then skip it,
5558          * because it meanti only for ethernet not Wi-Fi.
5559          */
5560         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5561                 return;
5562 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5563
5564
5565         wifi = g_supplicant_interface_get_data(interface);
5566         if (!wifi)
5567                 return;
5568
5569         /* P2P networks must not be treated as WiFi networks */
5570         if (wifi->p2p_connecting || wifi->p2p_device)
5571                 return;
5572
5573         identifier = g_supplicant_network_get_identifier(network);
5574
5575         connman_network = connman_device_get_network(wifi->device, identifier);
5576         if (!connman_network)
5577                 return;
5578
5579         if (wifi->network) {
5580                 if (wifi->network == connman_network)
5581                         return;
5582 #if TIZEN_EXT
5583                 unsigned int ssid_len;
5584                 DBG("network1 ssid[%s] , OWE[%d],ssid[%s]",
5585                         (char *)connman_network_get_blob(wifi->network,"WiFi.SSID", &ssid_len),
5586                         connman_network_get_bool(wifi->network,"WiFi.TRANSITION_MODE"),
5587                         (char *)connman_network_get_blob(wifi->network,"WiFi.TRANSITION_MODE_SSID", &ssid_len));
5588
5589                 DBG("network1 ssid[%s], OWE[%d], ssid[%s]",
5590                         (char *)connman_network_get_blob(connman_network,"WiFi.SSID",&ssid_len),
5591                         connman_network_get_bool(connman_network,"WiFi.TRANSITION_MODE"),
5592                         (char *)connman_network_get_blob(connman_network,"WiFi.TRANSITION_MODE_SSID", &ssid_len));
5593                 if (connman_network_check_transition_mode(wifi->network, connman_network)) {//OWE trasition mode check
5594                         DBG("OWE transition mode is TRUE");
5595                         return;
5596                 }
5597 #endif
5598                 /*
5599                  * This should never happen, we got associated with
5600                  * a network different than the one we were expecting.
5601                  */
5602                 DBG("Associated to %p while expecting %p",
5603                                         connman_network, wifi->network);
5604
5605                 connman_network_set_associating(wifi->network, false);
5606         }
5607
5608         DBG("Reconnecting to previous network %p from wpa_s", connman_network);
5609
5610         wifi->network = connman_network_ref(connman_network);
5611         wifi->retries = 0;
5612
5613         /*
5614          * Interface state changes callback (interface_state) is always
5615          * called before network_associated callback thus we need to call
5616          * interface_state again in order to process the new state now that
5617          * we have the network properly set.
5618          */
5619         interface_state(interface);
5620 }
5621
5622 static void sta_authorized(GSupplicantInterface *interface,
5623                                         const char *addr)
5624 {
5625 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5626         /*
5627          * Note: If supplicant interface's driver is wired then skip it,
5628          * because it meanti only for ethernet not Wi-Fi.
5629          */
5630         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5631                 return;
5632 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5633
5634         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5635
5636         DBG("wifi %p station %s authorized", wifi, addr);
5637
5638         if (!wifi || !wifi->tethering)
5639                 return;
5640
5641         __connman_tethering_client_register(addr);
5642 }
5643
5644 static void sta_deauthorized(GSupplicantInterface *interface,
5645                                         const char *addr)
5646 {
5647 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5648         /*
5649          * Note: If supplicant interface's driver is wired then skip it,
5650          * because it meanti only for ethernet not Wi-Fi.
5651          */
5652         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5653                 return;
5654 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5655
5656         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5657
5658         DBG("wifi %p station %s deauthorized", wifi, addr);
5659
5660         if (!wifi || !wifi->tethering)
5661                 return;
5662
5663         __connman_tethering_client_unregister(addr);
5664 }
5665
5666 static void apply_peer_services(GSupplicantPeer *peer,
5667                                 struct connman_peer *connman_peer)
5668 {
5669         const unsigned char *data;
5670         int length;
5671
5672         DBG("");
5673
5674         connman_peer_reset_services(connman_peer);
5675
5676         data = g_supplicant_peer_get_widi_ies(peer, &length);
5677         if (data) {
5678                 connman_peer_add_service(connman_peer,
5679                         CONNMAN_PEER_SERVICE_WIFI_DISPLAY, data, length);
5680         }
5681 }
5682
5683 static void peer_found(GSupplicantPeer *peer)
5684 {
5685         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
5686         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
5687         struct connman_peer *connman_peer;
5688         const char *identifier, *name;
5689         int ret;
5690
5691 #if defined TIZEN_EXT
5692         if (!wifi)
5693                 return;
5694 #endif
5695         identifier = g_supplicant_peer_get_identifier(peer);
5696         name = g_supplicant_peer_get_name(peer);
5697
5698         DBG("ident: %s", identifier);
5699
5700         connman_peer = connman_peer_get(wifi->device, identifier);
5701         if (connman_peer)
5702                 return;
5703
5704         connman_peer = connman_peer_create(identifier);
5705         connman_peer_set_name(connman_peer, name);
5706         connman_peer_set_device(connman_peer, wifi->device);
5707         apply_peer_services(peer, connman_peer);
5708
5709         ret = connman_peer_register(connman_peer);
5710         if (ret < 0 && ret != -EALREADY)
5711                 connman_peer_unref(connman_peer);
5712         else
5713                 wifi->peers = g_slist_prepend(wifi->peers, connman_peer);
5714 }
5715
5716 static void peer_lost(GSupplicantPeer *peer)
5717 {
5718         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
5719         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
5720         struct connman_peer *connman_peer;
5721         const char *identifier;
5722
5723         if (!wifi)
5724                 return;
5725
5726         identifier = g_supplicant_peer_get_identifier(peer);
5727
5728         DBG("ident: %s", identifier);
5729
5730         connman_peer = connman_peer_get(wifi->device, identifier);
5731         if (connman_peer) {
5732                 if (wifi->p2p_connecting &&
5733                                 wifi->pending_peer == connman_peer) {
5734                         peer_connect_timeout(wifi);
5735                 }
5736                 connman_peer_unregister(connman_peer);
5737                 connman_peer_unref(connman_peer);
5738         }
5739
5740         wifi->peers = g_slist_remove(wifi->peers, connman_peer);
5741 }
5742
5743 static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state)
5744 {
5745         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
5746         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
5747         enum connman_peer_state p_state = CONNMAN_PEER_STATE_UNKNOWN;
5748         struct connman_peer *connman_peer;
5749         const char *identifier;
5750
5751         identifier = g_supplicant_peer_get_identifier(peer);
5752
5753         DBG("ident: %s", identifier);
5754
5755         if (!wifi)
5756                 return;
5757
5758         connman_peer = connman_peer_get(wifi->device, identifier);
5759         if (!connman_peer)
5760                 return;
5761
5762         switch (state) {
5763         case G_SUPPLICANT_PEER_SERVICES_CHANGED:
5764                 apply_peer_services(peer, connman_peer);
5765                 connman_peer_services_changed(connman_peer);
5766                 return;
5767         case G_SUPPLICANT_PEER_GROUP_CHANGED:
5768                 if (!g_supplicant_peer_is_in_a_group(peer))
5769                         p_state = CONNMAN_PEER_STATE_IDLE;
5770                 else
5771                         p_state = CONNMAN_PEER_STATE_CONFIGURATION;
5772                 break;
5773         case G_SUPPLICANT_PEER_GROUP_STARTED:
5774                 break;
5775         case G_SUPPLICANT_PEER_GROUP_FINISHED:
5776                 p_state = CONNMAN_PEER_STATE_IDLE;
5777                 break;
5778         case G_SUPPLICANT_PEER_GROUP_JOINED:
5779                 connman_peer_set_iface_address(connman_peer,
5780                                 g_supplicant_peer_get_iface_address(peer));
5781                 break;
5782         case G_SUPPLICANT_PEER_GROUP_DISCONNECTED:
5783                 p_state = CONNMAN_PEER_STATE_IDLE;
5784                 break;
5785         case G_SUPPLICANT_PEER_GROUP_FAILED:
5786                 if (g_supplicant_peer_has_requested_connection(peer))
5787                         p_state = CONNMAN_PEER_STATE_IDLE;
5788                 else
5789                         p_state = CONNMAN_PEER_STATE_FAILURE;
5790                 break;
5791         }
5792
5793         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION ||
5794                                         p_state == CONNMAN_PEER_STATE_FAILURE) {
5795                 if (wifi->p2p_connecting
5796                                 && connman_peer == wifi->pending_peer)
5797                         peer_cancel_timeout(wifi);
5798                 else
5799                         p_state = CONNMAN_PEER_STATE_UNKNOWN;
5800         }
5801
5802         if (p_state == CONNMAN_PEER_STATE_UNKNOWN)
5803                 return;
5804
5805         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION) {
5806                 GSupplicantInterface *g_iface;
5807                 struct wifi_data *g_wifi;
5808
5809                 g_iface = g_supplicant_peer_get_group_interface(peer);
5810                 if (!g_iface)
5811                         return;
5812
5813                 g_wifi = g_supplicant_interface_get_data(g_iface);
5814                 if (!g_wifi)
5815                         return;
5816
5817                 connman_peer_set_as_master(connman_peer,
5818                                         !g_supplicant_peer_is_client(peer));
5819                 connman_peer_set_sub_device(connman_peer, g_wifi->device);
5820
5821                 /*
5822                  * If wpa_supplicant didn't create a dedicated p2p-group
5823                  * interface then mark this interface as p2p_device to avoid
5824                  * scan and auto-scan are launched on it while P2P is connected.
5825                  */
5826                 if (!g_list_find(p2p_iface_list, g_wifi))
5827                         wifi->p2p_device = true;
5828         }
5829
5830         connman_peer_set_state(connman_peer, p_state);
5831 }
5832
5833 static void peer_request(GSupplicantPeer *peer)
5834 {
5835         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
5836         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
5837         struct connman_peer *connman_peer;
5838         const char *identifier;
5839
5840 #if defined TIZEN_EXT
5841         if (!wifi)
5842                 return;
5843 #endif
5844
5845         identifier = g_supplicant_peer_get_identifier(peer);
5846
5847         DBG("ident: %s", identifier);
5848
5849         connman_peer = connman_peer_get(wifi->device, identifier);
5850         if (!connman_peer)
5851                 return;
5852
5853         connman_peer_request_connection(connman_peer);
5854 }
5855
5856 #if defined TIZEN_EXT
5857 static void system_power_off(void)
5858 {
5859         GList *list;
5860         struct wifi_data *wifi;
5861         struct connman_service *service;
5862         struct connman_ipconfig *ipconfig_ipv4;
5863
5864         if (connman_setting_get_bool("WiFiDHCPRelease") == true) {
5865                 for (list = iface_list; list; list = list->next) {
5866                         wifi = list->data;
5867
5868                         if (wifi->network != NULL) {
5869                                 service = connman_service_lookup_from_network(wifi->network);
5870                                 ipconfig_ipv4 = __connman_service_get_ip4config(service);
5871                                 __connman_dhcp_stop(ipconfig_ipv4);
5872                         }
5873                 }
5874         }
5875 }
5876
5877 static void network_merged(GSupplicantNetwork *network)
5878 {
5879         GSupplicantInterface *interface;
5880         GSupplicantState state;
5881         struct wifi_data *wifi;
5882         const char *identifier;
5883         struct connman_network *connman_network;
5884         bool ishs20AP = 0;
5885         char *temp = NULL;
5886
5887         interface = g_supplicant_network_get_interface(network);
5888         if (!interface)
5889                 return;
5890
5891 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5892         /*
5893          * Note: If supplicant interface's driver is wired then skip it,
5894          * because it meanti only for ethernet not Wi-Fi.
5895          */
5896         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5897                 return;
5898 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5899
5900         state = g_supplicant_interface_get_state(interface);
5901         if (state < G_SUPPLICANT_STATE_AUTHENTICATING)
5902                 return;
5903
5904         wifi = g_supplicant_interface_get_data(interface);
5905         if (!wifi)
5906                 return;
5907
5908         identifier = g_supplicant_network_get_identifier(network);
5909
5910         connman_network = connman_device_get_network(wifi->device, identifier);
5911         if (!connman_network)
5912                 return;
5913
5914         DBG("merged identifier %s", identifier);
5915
5916         if (wifi->connected == FALSE) {
5917                 switch (state) {
5918                 case G_SUPPLICANT_STATE_AUTHENTICATING:
5919                 case G_SUPPLICANT_STATE_ASSOCIATING:
5920                 case G_SUPPLICANT_STATE_ASSOCIATED:
5921                 case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
5922                 case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
5923                         connman_network_set_associating(connman_network, TRUE);
5924                         break;
5925                 case G_SUPPLICANT_STATE_COMPLETED:
5926                         connman_network_set_connected(connman_network, TRUE);
5927                         break;
5928                 default:
5929                         DBG("Not handled the state : %d", state);
5930                         break;
5931                 }
5932         }
5933
5934         ishs20AP = g_supplicant_network_is_hs20AP(network);
5935
5936         if (ishs20AP &&
5937                 g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) {
5938                 temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1);
5939                 connman_network_set_string(connman_network, "WiFi.EAP",
5940                                 temp);
5941                 connman_network_set_string(connman_network, "WiFi.Identity",
5942                                 g_supplicant_network_get_identity(network));
5943                 connman_network_set_string(connman_network, "WiFi.Phase2",
5944                                 g_supplicant_network_get_phase2(network));
5945
5946                 g_free(temp);
5947         }
5948
5949         wifi->network = connman_network;
5950 }
5951
5952 static void assoc_failed(void *user_data)
5953 {
5954         struct connman_network *network = user_data;
5955         connman_network_set_associating(network, false);
5956 }
5957
5958 static void scan_done(GSupplicantInterface *interface)
5959 {
5960 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5961         /*
5962          * Note: If supplicant interface's driver is wired then skip it,
5963          * because it meanti only for ethernet not Wi-Fi.
5964          */
5965         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5966                 return;
5967 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5968
5969         GList *list;
5970         int scan_type = CONNMAN_SCAN_TYPE_WPA_SUPPLICANT;
5971         struct wifi_data *wifi;
5972         bool scanning;
5973
5974         for (list = iface_list; list; list = list->next) {
5975                 wifi = list->data;
5976
5977                 if (interface == wifi->interface) {
5978                         scanning = connman_device_get_scanning(wifi->device,
5979                                         CONNMAN_SERVICE_TYPE_WIFI);
5980                         if (!scanning)
5981                                 __connman_technology_notify_scan_done(
5982                                                 connman_device_get_string(wifi->device, "Interface"), scan_type);
5983                         break;
5984                 }
5985         }
5986 }
5987 #endif
5988
5989 static void debug(const char *str)
5990 {
5991 #if defined TIZEN_EXT
5992         if (connman_setting_get_bool("ConnmanSupplicantDebug"))
5993 #else
5994         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
5995 #endif
5996                 connman_debug("%s", str);
5997 }
5998
5999 static void disconnect_reasoncode(GSupplicantInterface *interface,
6000                                 int reasoncode)
6001 {
6002 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
6003         /*
6004          * Note: If supplicant interface's driver is wired then skip it,
6005          * because it meanti only for ethernet not Wi-Fi.
6006          */
6007         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
6008                 return;
6009 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
6010
6011         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
6012
6013         if (wifi != NULL) {
6014                 wifi->disconnect_code = reasoncode;
6015         }
6016 }
6017
6018 static void assoc_status_code(GSupplicantInterface *interface, int status_code)
6019 {
6020 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
6021         /*
6022          * Note: If supplicant interface's driver is wired then skip it,
6023          * because it meanti only for ethernet not Wi-Fi.
6024          */
6025         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
6026                 return;
6027 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
6028
6029         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
6030
6031         if (wifi != NULL) {
6032                 wifi->assoc_code = status_code;
6033         }
6034 }
6035
6036 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
6037 static GSupplicantCallbacks callbacks = {
6038 #else /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
6039 static const GSupplicantCallbacks callbacks = {
6040 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
6041         .system_ready           = system_ready,
6042         .system_killed          = system_killed,
6043         .interface_added        = interface_added,
6044         .interface_state        = interface_state,
6045         .interface_removed      = interface_removed,
6046         .p2p_support            = p2p_support,
6047         .scan_started           = scan_started,
6048         .scan_finished          = scan_finished,
6049         .ap_create_fail         = ap_create_fail,
6050         .network_added          = network_added,
6051         .network_removed        = network_removed,
6052         .network_changed        = network_changed,
6053         .network_associated     = network_associated,
6054         .sta_authorized         = sta_authorized,
6055         .sta_deauthorized       = sta_deauthorized,
6056         .peer_found             = peer_found,
6057         .peer_lost              = peer_lost,
6058         .peer_changed           = peer_changed,
6059         .peer_request           = peer_request,
6060 #if defined TIZEN_EXT
6061         .system_power_off       = system_power_off,
6062         .network_merged         = network_merged,
6063         .assoc_failed           = assoc_failed,
6064         .scan_done              = scan_done,
6065 #endif
6066         .debug                  = debug,
6067         .disconnect_reasoncode  = disconnect_reasoncode,
6068         .assoc_status_code      = assoc_status_code,
6069 #if defined TIZEN_EXT_WIFI_MESH
6070         .mesh_support           = mesh_support,
6071         .mesh_group_started = mesh_group_started,
6072         .mesh_group_removed = mesh_group_removed,
6073         .mesh_peer_connected = mesh_peer_connected,
6074         .mesh_peer_disconnected = mesh_peer_disconnected,
6075 #endif
6076 };
6077
6078
6079 static int tech_probe(struct connman_technology *technology)
6080 {
6081         wifi_technology = technology;
6082
6083         return 0;
6084 }
6085
6086 static void tech_remove(struct connman_technology *technology)
6087 {
6088         wifi_technology = NULL;
6089 }
6090
6091 static GSupplicantSSID *ssid_ap_init(const char *ssid, const char *passphrase)
6092 {
6093         GSupplicantSSID *ap;
6094
6095         ap = g_try_malloc0(sizeof(GSupplicantSSID));
6096         if (!ap)
6097                 return NULL;
6098
6099         ap->mode = G_SUPPLICANT_MODE_MASTER;
6100 #if defined TIZEN_EXT
6101         ap->ssid = (void *) ssid;
6102 #else
6103         ap->ssid = ssid;
6104 #endif
6105         ap->ssid_len = strlen(ssid);
6106         ap->scan_ssid = 0;
6107         ap->freq = 2412;
6108
6109         if (!passphrase || strlen(passphrase) == 0) {
6110                 ap->security = G_SUPPLICANT_SECURITY_NONE;
6111                 ap->passphrase = NULL;
6112         } else {
6113                ap->security = G_SUPPLICANT_SECURITY_PSK;
6114                ap->protocol = G_SUPPLICANT_PROTO_RSN;
6115                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
6116                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
6117                ap->passphrase = passphrase;
6118         }
6119
6120         return ap;
6121 }
6122
6123 static void ap_start_callback(int result, GSupplicantInterface *interface,
6124                                                         void *user_data)
6125 {
6126         struct wifi_tethering_info *info = user_data;
6127
6128         DBG("result %d index %d bridge %s",
6129                 result, info->wifi->index, info->wifi->bridge);
6130
6131         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
6132                 connman_inet_remove_from_bridge(info->wifi->index,
6133                                                         info->wifi->bridge);
6134
6135                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
6136                         connman_technology_tethering_notify(info->technology, false);
6137                         g_free(info->wifi->tethering_param->ssid);
6138                         g_free(info->wifi->tethering_param);
6139                         info->wifi->tethering_param = NULL;
6140                 }
6141         }
6142
6143         g_free(info->ifname);
6144         g_free(info);
6145 }
6146
6147 static void ap_create_callback(int result,
6148                                 GSupplicantInterface *interface,
6149                                         void *user_data)
6150 {
6151         struct wifi_tethering_info *info = user_data;
6152
6153         DBG("result %d ifname %s", result,
6154                                 g_supplicant_interface_get_ifname(interface));
6155
6156         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
6157                 connman_inet_remove_from_bridge(info->wifi->index,
6158                                                         info->wifi->bridge);
6159
6160                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
6161                         connman_technology_tethering_notify(info->technology, false);
6162                         g_free(info->wifi->tethering_param->ssid);
6163                         g_free(info->wifi->tethering_param);
6164                         info->wifi->tethering_param = NULL;
6165
6166                 }
6167
6168                 g_free(info->ifname);
6169                 g_free(info->ssid);
6170                 g_free(info);
6171                 return;
6172         }
6173
6174         info->wifi->interface = interface;
6175         g_supplicant_interface_set_data(interface, info->wifi);
6176
6177         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
6178                 connman_error("Failed to set interface ap_scan property");
6179
6180         g_supplicant_interface_connect(interface, info->ssid,
6181                                                 ap_start_callback, info);
6182 }
6183
6184 static void sta_remove_callback(int result,
6185                                 GSupplicantInterface *interface,
6186                                         void *user_data)
6187 {
6188         struct wifi_tethering_info *info = user_data;
6189         const char *driver = connman_option_get_string("wifi");
6190
6191         DBG("ifname %s result %d ", info->ifname, result);
6192
6193         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
6194                 info->wifi->tethering = false;
6195                 connman_technology_tethering_notify(info->technology, false);
6196
6197                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
6198                         g_free(info->wifi->tethering_param->ssid);
6199                         g_free(info->wifi->tethering_param);
6200                         info->wifi->tethering_param = NULL;
6201                 }
6202
6203                 g_free(info->ifname);
6204                 g_free(info->ssid);
6205                 g_free(info);
6206                 return;
6207         }
6208
6209         info->wifi->interface = NULL;
6210
6211         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
6212 #ifdef TIZEN_EXT
6213                         0, 0, 60,
6214 #endif /* TIZEN_EXT */
6215                                                 ap_create_callback,
6216                                                         info);
6217 }
6218
6219 static int enable_wifi_tethering(struct connman_technology *technology,
6220                                 const char *bridge, const char *identifier,
6221                                 const char *passphrase, bool available)
6222 {
6223         GList *list;
6224         GSupplicantInterface *interface;
6225         struct wifi_data *wifi;
6226         struct wifi_tethering_info *info;
6227         const char *ifname;
6228         unsigned int mode;
6229         int err, berr = 0;
6230
6231         for (list = iface_list; list; list = list->next) {
6232                 wifi = list->data;
6233
6234                 DBG("wifi %p network %p pending_network %p", wifi,
6235                         wifi->network, wifi->pending_network);
6236
6237                 interface = wifi->interface;
6238
6239                 if (!interface)
6240                         continue;
6241
6242                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
6243                 if (!ifname)
6244                         continue;
6245
6246                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED) {
6247                         DBG("%s does not support AP mode (detected)", ifname);
6248                         continue;
6249                 }
6250
6251                 mode = g_supplicant_interface_get_mode(interface);
6252                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
6253                         wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
6254                         DBG("%s does not support AP mode (capability)", ifname);
6255                         continue;
6256                 }
6257
6258                 if (wifi->network && available)
6259                         continue;
6260
6261                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
6262                 if (!info)
6263                         return -ENOMEM;
6264
6265                 wifi->tethering_param = g_try_malloc0(sizeof(struct wifi_tethering_info));
6266                 if (!wifi->tethering_param) {
6267                         g_free(info);
6268                         return -ENOMEM;
6269                 }
6270
6271                 info->wifi = wifi;
6272                 info->technology = technology;
6273                 info->wifi->bridge = bridge;
6274                 info->ssid = ssid_ap_init(identifier, passphrase);
6275                 if (!info->ssid)
6276                         goto failed;
6277
6278                 info->ifname = g_strdup(ifname);
6279
6280                 wifi->tethering_param->technology = technology;
6281                 wifi->tethering_param->ssid = ssid_ap_init(identifier, passphrase);
6282                 if (!wifi->tethering_param->ssid)
6283                         goto failed;
6284
6285                 info->wifi->tethering = true;
6286                 info->wifi->ap_supported = WIFI_AP_SUPPORTED;
6287
6288                 berr = connman_technology_tethering_notify(technology, true);
6289                 if (berr < 0)
6290                         goto failed;
6291
6292                 err = g_supplicant_interface_remove(interface,
6293                                                 sta_remove_callback,
6294                                                         info);
6295                 if (err >= 0) {
6296                         DBG("tethering wifi %p ifname %s", wifi, ifname);
6297                         return 0;
6298                 }
6299
6300         failed:
6301                 g_free(info->ifname);
6302                 g_free(info->ssid);
6303                 g_free(info);
6304                 g_free(wifi->tethering_param);
6305                 wifi->tethering_param = NULL;
6306
6307                 /*
6308                  * Remove bridge if it was correctly created but remove
6309                  * operation failed. Instead, if bridge creation failed then
6310                  * break out and do not try again on another interface,
6311                  * bridge set-up does not depend on it.
6312                  */
6313                 if (berr == 0)
6314                         connman_technology_tethering_notify(technology, false);
6315                 else
6316                         break;
6317         }
6318
6319         return -EOPNOTSUPP;
6320 }
6321
6322 static int tech_set_tethering(struct connman_technology *technology,
6323                                 const char *identifier, const char *passphrase,
6324                                 const char *bridge, bool enabled)
6325 {
6326         GList *list;
6327         struct wifi_data *wifi;
6328         int err;
6329
6330         DBG("");
6331
6332         if (!enabled) {
6333                 for (list = iface_list; list; list = list->next) {
6334                         wifi = list->data;
6335
6336                         if (wifi->tethering) {
6337                                 wifi->tethering = false;
6338
6339                                 connman_inet_remove_from_bridge(wifi->index,
6340                                                                         bridge);
6341                                 wifi->bridged = false;
6342                         }
6343                 }
6344
6345                 connman_technology_tethering_notify(technology, false);
6346
6347                 return 0;
6348         }
6349
6350         DBG("trying tethering for available devices");
6351         err = enable_wifi_tethering(technology, bridge, identifier, passphrase,
6352                                 true);
6353
6354         if (err < 0) {
6355                 DBG("trying tethering for any device");
6356                 err = enable_wifi_tethering(technology, bridge, identifier,
6357                                         passphrase, false);
6358         }
6359
6360         return err;
6361 }
6362
6363 static void regdom_callback(int result, const char *alpha2, void *user_data)
6364 {
6365         DBG("");
6366
6367         if (!wifi_technology)
6368                 return;
6369
6370         if (result != 0)
6371                 alpha2 = NULL;
6372
6373         connman_technology_regdom_notify(wifi_technology, alpha2);
6374 }
6375
6376 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
6377 {
6378         return g_supplicant_set_country(alpha2, regdom_callback, NULL);
6379 }
6380
6381 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
6382 static void supp_ins_init(void)
6383 {
6384         const char *string;
6385         GSupplicantINSPreferredFreq preferred_freq;
6386
6387         string = connman_option_get_string("INSPreferredFreqBSSID");
6388         if (g_strcmp0(string, "5GHz") == 0)
6389                 preferred_freq = G_SUPPLICANT_INS_PREFERRED_FREQ_5GHZ;
6390         else if (g_strcmp0(string, "2.4GHz") == 0)
6391                 preferred_freq = G_SUPPLICANT_INS_PREFERRED_FREQ_24GHZ;
6392         else
6393                 preferred_freq = G_SUPPLICANT_INS_PREFERRED_FREQ_UNKNOWN;
6394
6395         g_supplicant_set_ins_settings(preferred_freq,
6396                 connman_setting_get_bool("INSLastConnectedBSSID"),
6397                 connman_setting_get_bool("INSAssocReject"),
6398                 connman_setting_get_bool("INSSignalBSSID"),
6399                 connman_setting_get_uint("INSPreferredFreqBSSIDScore"),
6400                 connman_setting_get_uint("INSLastConnectedBSSIDScore"),
6401                 connman_setting_get_uint("INSAssocRejectScore"),
6402                 connman_setting_get_int("INSSignalLevel3_5GHz"),
6403                 connman_setting_get_int("INSSignalLevel3_24GHz")
6404         );
6405 }
6406 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
6407
6408 static struct connman_technology_driver tech_driver = {
6409         .name           = "wifi",
6410         .type           = CONNMAN_SERVICE_TYPE_WIFI,
6411         .probe          = tech_probe,
6412         .remove         = tech_remove,
6413         .set_tethering  = tech_set_tethering,
6414         .set_regdom     = tech_set_regdom,
6415 };
6416
6417 static int wifi_init(void)
6418 {
6419         int err;
6420
6421         err = connman_network_driver_register(&network_driver);
6422         if (err < 0)
6423                 return err;
6424
6425         err = g_supplicant_register(&callbacks);
6426         if (err < 0) {
6427                 connman_network_driver_unregister(&network_driver);
6428                 return err;
6429         }
6430
6431         err = connman_technology_driver_register(&tech_driver);
6432         if (err < 0) {
6433                 g_supplicant_unregister(&callbacks);
6434                 connman_network_driver_unregister(&network_driver);
6435                 return err;
6436         }
6437
6438 #if defined TIZEN_EXT
6439         failed_bssids = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
6440 #endif
6441
6442 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
6443         supp_ins_init();
6444 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
6445         return 0;
6446 }
6447
6448 static void wifi_exit(void)
6449 {
6450         DBG();
6451
6452         connman_technology_driver_unregister(&tech_driver);
6453
6454         g_supplicant_unregister(&callbacks);
6455
6456         connman_network_driver_unregister(&network_driver);
6457
6458 #if defined TIZEN_EXT
6459         g_hash_table_unref(failed_bssids);
6460 #endif
6461 }
6462
6463 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
6464                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)