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