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