DA: Reduce debug log
[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 #endif
3806
3807         return G_SUPPLICANT_SECURITY_UNKNOWN;
3808 }
3809
3810 #if defined TIZEN_EXT
3811 static GSupplicantEapKeymgmt network_eap_keymgmt(const char *security)
3812 {
3813         if (security == NULL)
3814                 return G_SUPPLICANT_EAP_KEYMGMT_NONE;
3815
3816         if (g_str_equal(security, "FT") == TRUE)
3817                 return G_SUPPLICANT_EAP_KEYMGMT_FT;
3818         else if (g_str_equal(security, "CCKM") == TRUE)
3819                 return G_SUPPLICANT_EAP_KEYMGMT_CCKM;
3820
3821         return G_SUPPLICANT_EAP_KEYMGMT_NONE;
3822 }
3823 #endif
3824
3825 static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
3826 {
3827         const char *security;
3828 #if defined TIZEN_EXT
3829         const void *ssid_data;
3830 #endif
3831
3832         memset(ssid, 0, sizeof(*ssid));
3833         ssid->mode = G_SUPPLICANT_MODE_INFRA;
3834 #if defined TIZEN_EXT
3835         ssid_data = connman_network_get_blob(network, "WiFi.SSID",
3836                                                 &ssid->ssid_len);
3837         ssid->ssid = g_try_malloc0(ssid->ssid_len);
3838
3839         if (!ssid->ssid)
3840                 ssid->ssid_len = 0;
3841         else
3842                 memcpy(ssid->ssid, ssid_data, ssid->ssid_len);
3843 #else
3844         ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
3845                                                 &ssid->ssid_len);
3846 #endif
3847         ssid->scan_ssid = 1;
3848         security = connman_network_get_string(network, "WiFi.Security");
3849         ssid->security = network_security(security);
3850 #if defined TIZEN_EXT
3851         ssid->ieee80211w = 1;
3852 #endif
3853         ssid->passphrase = connman_network_get_string(network,
3854                                                 "WiFi.Passphrase");
3855
3856         ssid->eap = connman_network_get_string(network, "WiFi.EAP");
3857
3858         /*
3859          * If our private key password is unset,
3860          * we use the supplied passphrase. That is needed
3861          * for PEAP where 2 passphrases (identity and client
3862          * cert may have to be provided.
3863          */
3864         if (!connman_network_get_string(network, "WiFi.PrivateKeyPassphrase"))
3865                 connman_network_set_string(network,
3866                                                 "WiFi.PrivateKeyPassphrase",
3867                                                 ssid->passphrase);
3868         /* We must have an identity for both PEAP and TLS */
3869         ssid->identity = connman_network_get_string(network, "WiFi.Identity");
3870
3871         /* Use agent provided identity as a fallback */
3872         if (!ssid->identity || strlen(ssid->identity) == 0)
3873                 ssid->identity = connman_network_get_string(network,
3874                                                         "WiFi.AgentIdentity");
3875
3876         ssid->anonymous_identity = connman_network_get_string(network,
3877                                                 "WiFi.AnonymousIdentity");
3878         ssid->ca_cert_path = connman_network_get_string(network,
3879                                                         "WiFi.CACertFile");
3880         ssid->subject_match = connman_network_get_string(network,
3881                                                         "WiFi.SubjectMatch");
3882         ssid->altsubject_match = connman_network_get_string(network,
3883                                                         "WiFi.AltSubjectMatch");
3884         ssid->domain_suffix_match = connman_network_get_string(network,
3885                                                         "WiFi.DomainSuffixMatch");
3886         ssid->domain_match = connman_network_get_string(network,
3887                                                         "WiFi.DomainMatch");
3888         ssid->client_cert_path = connman_network_get_string(network,
3889                                                         "WiFi.ClientCertFile");
3890         ssid->private_key_path = connman_network_get_string(network,
3891                                                         "WiFi.PrivateKeyFile");
3892         ssid->private_key_passphrase = connman_network_get_string(network,
3893                                                 "WiFi.PrivateKeyPassphrase");
3894         ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
3895
3896         ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS");
3897         ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS");
3898 #if defined TIZEN_EXT
3899         ssid->connector = connman_network_get_string(network,
3900                                                         "WiFi.Connector");
3901         ssid->c_sign_key = connman_network_get_string(network,
3902                                                         "WiFi.CSignKey");
3903         ssid->net_access_key = connman_network_get_string(network,
3904                                                 "WiFi.NetAccessKey");
3905 #endif
3906
3907 #if defined TIZEN_EXT
3908         const char *ifname = connman_device_get_string(
3909                         connman_network_get_device(network), "Interface");
3910         if (set_connman_bssid(CHECK_BSSID, NULL, ifname) == 6) {
3911                 ssid->bssid_for_connect_len = 6;
3912                 set_connman_bssid(GET_BSSID, (char *)ssid->bssid_for_connect, ifname);
3913                 DBG("BSSID : %02x:%02x:%02x:%02x:%02x:%02x",
3914                         ssid->bssid_for_connect[0], ssid->bssid_for_connect[1],
3915                         ssid->bssid_for_connect[2], ssid->bssid_for_connect[3],
3916                         ssid->bssid_for_connect[4], ssid->bssid_for_connect[5]);
3917         } else {
3918                 ssid->freq = connman_network_get_frequency(network);
3919         }
3920
3921         GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network);
3922         if (bssid_list && g_slist_length(bssid_list) > 1) {
3923
3924                 /* If there are more than one bssid,
3925                  * the user-specified bssid is tried only once at the beginning.
3926                  * After that, the bssids in the list are tried in order.
3927                  */
3928                 if (set_connman_bssid(CHECK_BSSID, NULL, ifname) == 6) {
3929                         set_connman_bssid(RESET_BSSID, NULL, ifname);
3930                         goto done;
3931                 }
3932
3933                 GSList *list;
3934                 char buff[MAC_ADDRESS_LENGTH];
3935                 for (list = bssid_list; list; list = list->next) {
3936                         struct connman_bssids * bssids = (struct connman_bssids *)list->data;
3937
3938                         g_snprintf(buff, MAC_ADDRESS_LENGTH, "%02x:%02x:%02x:%02x:%02x:%02x",
3939                                         bssids->bssid[0], bssids->bssid[1], bssids->bssid[2],
3940                                         bssids->bssid[3], bssids->bssid[4], bssids->bssid[5]);
3941                         buff[MAC_ADDRESS_LENGTH - 1] = '\0';
3942
3943                         gchar *curr_bssid = g_strdup((const gchar *)buff);
3944
3945                         if (g_hash_table_contains(failed_bssids, curr_bssid)) {
3946                                 DBG("bssid match, try next bssid");
3947                                 g_free(curr_bssid);
3948                                 continue;
3949                         } else {
3950                                 g_hash_table_add(failed_bssids, curr_bssid);
3951
3952                                 memcpy(buff_bssid, bssids->bssid, WIFI_BSSID_LEN_MAX);
3953                                 ssid->bssid = buff_bssid;
3954                                 ssid->freq = (unsigned int)bssids->frequency;
3955                                 break;
3956                         }
3957                 }
3958
3959                 if (!list) {
3960                         ssid->bssid = connman_network_get_bssid(network);
3961                         g_hash_table_remove_all(failed_bssids);
3962                 }
3963         } else
3964                 ssid->bssid = connman_network_get_bssid(network);
3965
3966 done:
3967         ssid->eap_keymgmt = network_eap_keymgmt(
3968                         connman_network_get_string(network, "WiFi.KeymgmtType"));
3969         ssid->phase1 = connman_network_get_string(network, "WiFi.Phase1");
3970
3971         if (g_strcmp0(ssid->eap, "fast") == 0)
3972                 ssid->pac_file = g_strdup(WIFI_EAP_FAST_PAC_FILE);
3973
3974         ssid->keymgmt = connman_network_get_keymgmt(network);
3975 #endif
3976
3977         if (connman_setting_get_bool("BackgroundScanning"))
3978                 ssid->bgscan = BGSCAN_DEFAULT;
3979 }
3980
3981 static int network_connect(struct connman_network *network)
3982 {
3983         struct connman_device *device = connman_network_get_device(network);
3984         struct wifi_data *wifi;
3985         GSupplicantInterface *interface;
3986         GSupplicantSSID *ssid;
3987
3988         DBG("network %p", network);
3989
3990         if (!device)
3991                 return -ENODEV;
3992
3993         wifi = connman_device_get_data(device);
3994         if (!wifi)
3995                 return -ENODEV;
3996
3997         ssid = g_try_malloc0(sizeof(GSupplicantSSID));
3998         if (!ssid)
3999                 return -ENOMEM;
4000
4001         interface = wifi->interface;
4002
4003         ssid_init(ssid, network);
4004
4005         if (wifi->disconnecting) {
4006                 wifi->pending_network = network;
4007 #if defined TIZEN_EXT
4008                 g_free(ssid->ssid);
4009 #endif
4010                 g_free(ssid);
4011         } else {
4012                 wifi->network = connman_network_ref(network);
4013                 wifi->retries = 0;
4014 #if defined TIZEN_EXT
4015                 wifi->scan_pending_network = NULL;
4016 #endif
4017
4018                 return g_supplicant_interface_connect(interface, ssid,
4019                                                 connect_callback, network);
4020         }
4021
4022         return -EINPROGRESS;
4023 }
4024
4025 static void disconnect_callback(int result, GSupplicantInterface *interface,
4026                                                                 void *user_data)
4027 {
4028         struct disconnect_data *dd = user_data;
4029         struct connman_network *network = dd->network;
4030 #if defined TIZEN_EXT
4031         GList *list;
4032         struct wifi_data *wifi = NULL;
4033
4034         g_free(dd);
4035         DBG("network %p result %d", network, result);
4036
4037         for (list = iface_list; list; list = list->next) {
4038                 wifi = list->data;
4039
4040                 if (wifi->network == NULL && wifi->disconnecting == true)
4041                         wifi->disconnecting = false;
4042
4043                 if (wifi->network == network)
4044                         goto found;
4045         }
4046
4047         if (wifi && network == wifi->pending_network)
4048                 wifi->pending_network = NULL;
4049
4050         /* wifi_data may be invalid because wifi is already disabled */
4051         return;
4052
4053 found:
4054 #else
4055         struct wifi_data *wifi = dd->wifi;
4056         g_free(dd);
4057 #endif
4058
4059         DBG("result %d supplicant interface %p wifi %p networks: current %p "
4060                 "pending %p disconnected %p", result, interface, wifi,
4061                 wifi->network, wifi->pending_network, network);
4062
4063         if (result == -ECONNABORTED) {
4064                 DBG("wifi interface no longer available");
4065                 return;
4066         }
4067
4068 #if defined TIZEN_EXT
4069         if (g_slist_find(wifi->networks, network) &&
4070                         wifi->network != wifi->pending_network)
4071 #else
4072         if (g_slist_find(wifi->networks, network))
4073 #endif
4074                 connman_network_set_connected(network, false);
4075
4076         wifi->disconnecting = false;
4077
4078         if (network != wifi->network) {
4079                 if (network == wifi->pending_network)
4080                         wifi->pending_network = NULL;
4081                 DBG("current wifi network has changed since disconnection");
4082                 return;
4083         }
4084
4085         wifi->network = NULL;
4086
4087         wifi->connected = false;
4088
4089         if (wifi->pending_network) {
4090                 network_connect(wifi->pending_network);
4091                 wifi->pending_network = NULL;
4092         }
4093
4094         start_autoscan(wifi->device);
4095 }
4096
4097 static int network_disconnect(struct connman_network *network)
4098 {
4099         struct connman_device *device = connman_network_get_device(network);
4100         struct disconnect_data *dd;
4101         struct wifi_data *wifi;
4102         int err;
4103 #if defined TIZEN_EXT
4104         struct connman_service *service;
4105 #endif
4106
4107         DBG("network %p", network);
4108
4109         wifi = connman_device_get_data(device);
4110         if (!wifi || !wifi->interface)
4111                 return -ENODEV;
4112
4113 #if defined TIZEN_EXT
4114         if (connman_network_get_associating(network) == true) {
4115                 connman_network_clear_associating(network);
4116                 connman_network_set_bool(network, "WiFi.UseWPS", false);
4117         } else {
4118                 service = connman_service_lookup_from_network(network);
4119
4120                 if (service != NULL &&
4121                         (__connman_service_is_connected_state(service,
4122                                         CONNMAN_IPCONFIG_TYPE_IPV4) == false &&
4123                         __connman_service_is_connected_state(service,
4124                                         CONNMAN_IPCONFIG_TYPE_IPV6) == false) &&
4125                         (connman_service_get_favorite(service) == false))
4126                                         __connman_service_set_passphrase(service, NULL);
4127         }
4128
4129         if (wifi->pending_network == network)
4130                 wifi->pending_network = NULL;
4131
4132         if (wifi->scan_pending_network == network)
4133                 wifi->scan_pending_network = NULL;
4134
4135 #endif
4136         connman_network_set_associating(network, false);
4137
4138         if (wifi->disconnecting)
4139                 return -EALREADY;
4140
4141         wifi->disconnecting = true;
4142
4143         dd = g_malloc0(sizeof(*dd));
4144         dd->wifi = wifi;
4145         dd->network = network;
4146
4147         err = g_supplicant_interface_disconnect(wifi->interface,
4148                                                 disconnect_callback, dd);
4149         if (err < 0) {
4150                 wifi->disconnecting = false;
4151                 g_free(dd);
4152         }
4153
4154         return err;
4155 }
4156
4157 #if defined TIZEN_EXT
4158 static void set_connection_mode(struct connman_network *network,
4159                 int linkspeed)
4160 {
4161         ieee80211_modes_e phy_mode;
4162         connection_mode_e conn_mode;
4163
4164         phy_mode = connman_network_get_phy_mode(network);
4165         switch (phy_mode) {
4166         case IEEE80211_MODE_B:
4167                 if (linkspeed > 0 && linkspeed <= 11)
4168                         conn_mode = CONNECTION_MODE_IEEE80211B;
4169                 else
4170                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4171
4172                 break;
4173         case IEEE80211_MODE_BG:
4174                 if (linkspeed > 0 && linkspeed <= 11)
4175                         conn_mode = CONNECTION_MODE_IEEE80211B;
4176                 else if (linkspeed > 11 && linkspeed <= 54)
4177                         conn_mode = CONNECTION_MODE_IEEE80211G;
4178                 else
4179                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4180
4181                 break;
4182         case IEEE80211_MODE_BGN:
4183                 if (linkspeed > 0 && linkspeed <= 11)
4184                         conn_mode = CONNECTION_MODE_IEEE80211B;
4185                 else if (linkspeed > 11 && linkspeed <= 54)
4186                         conn_mode = CONNECTION_MODE_IEEE80211G;
4187                 else if (linkspeed > 54 && linkspeed <= 450)
4188                         conn_mode = CONNECTION_MODE_IEEE80211N;
4189                 else
4190                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4191
4192                 break;
4193         case IEEE80211_MODE_A:
4194                 if (linkspeed > 0 && linkspeed <= 54)
4195                         conn_mode = CONNECTION_MODE_IEEE80211A;
4196                 else
4197                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4198
4199                 break;
4200         case IEEE80211_MODE_AN:
4201                 if (linkspeed > 0 && linkspeed <= 54)
4202                         conn_mode = CONNECTION_MODE_IEEE80211A;
4203                 else if (linkspeed > 54 && linkspeed <= 450)
4204                         conn_mode = CONNECTION_MODE_IEEE80211N;
4205                 else
4206                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4207
4208                 break;
4209         case IEEE80211_MODE_ANAC:
4210                 if (linkspeed > 0 && linkspeed <= 54)
4211                         conn_mode = CONNECTION_MODE_IEEE80211A;
4212                 else if (linkspeed > 54 && linkspeed <= 450)
4213                         conn_mode = CONNECTION_MODE_IEEE80211N;
4214                 else if (linkspeed > 450 && linkspeed <= 1300)
4215                         conn_mode = CONNECTION_MODE_IEEE80211AC;
4216                 else
4217                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4218
4219                 break;
4220         default:
4221                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
4222                 break;
4223         }
4224
4225         DBG("connection mode(%d)", conn_mode);
4226         connman_network_set_connection_mode(network, conn_mode);
4227 }
4228
4229 static void signalpoll_callback(int result, int maxspeed, int strength,
4230                                 int snr, void *user_data)
4231 {
4232         char bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
4233         char *bssid_str = bssid_buff;
4234         unsigned char *bssid;
4235         struct timespec curr_time = {0};
4236         __time_t roam_scan_time;
4237         const char *interface = NULL;
4238         struct connman_device *device;
4239         struct connman_network *network = user_data;
4240         GSupplicantNetwork *supplicant_network;
4241         struct wifi_data *wifi = NULL;
4242         uint16_t freq = connman_network_get_frequency(network);
4243         const char *group = connman_network_get_group(network);
4244
4245         if (result != 0) {
4246                 DBG("Failed to get maxspeed from signalpoll !");
4247                 connman_network_unref(network);
4248                 return;
4249         }
4250
4251         device = connman_network_get_device(network);
4252         if (device)
4253                 wifi = connman_device_get_data(device);
4254
4255         if (group && wifi) {
4256                 supplicant_network = g_supplicant_interface_get_network(wifi->interface, group);
4257                 if (supplicant_network) {
4258                         g_supplicant_network_set_signal(supplicant_network, strength);
4259                         g_supplicant_network_set_bss_signal(supplicant_network, strength, snr);
4260                 }
4261         }
4262
4263         strength += 120;
4264         if (strength > 100)
4265                 strength = 100;
4266
4267         bssid = connman_network_get_bssid(network);
4268         snprintf(bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bssid));
4269
4270         DBG("network %p, bssid %s, freq %u, maxspeed %d, strength %d, snr %d",
4271                         network, bssid_str, freq, maxspeed, strength, snr);
4272
4273         connman_network_set_strength(network, (uint8_t)strength);
4274         connman_network_set_snr(network, snr);
4275         connman_network_set_maxspeed(network, maxspeed);
4276         set_connection_mode(network, maxspeed);
4277
4278         if (connman_network_get_max_bssid_count(network) <= 1)
4279                 goto done;
4280
4281         clock_gettime(CLOCK_MONOTONIC, &curr_time);
4282         roam_scan_time = connman_network_get_roam_scan_time(network);
4283         if (curr_time.tv_sec <= roam_scan_time + ROAM_SCAN_INTERVAL)
4284                 goto done;
4285
4286         if (device && need_bss_transition(freq, snr, strength)) {
4287
4288                 interface = connman_device_get_string(device, "Interface");
4289                 __connman_technology_notify_roaming_state(interface, "required", bssid_str, NULL);
4290
4291                 if (connman_setting_get_bool("WifiRoamingScan") == false)
4292                         goto done;
4293
4294                 throw_wifi_scan(device, scan_callback);
4295                 connman_network_set_roam_scan_time(network, curr_time.tv_sec);
4296         }
4297
4298 done:
4299         connman_network_unref(network);
4300 }
4301
4302 static int network_signalpoll(struct wifi_data *wifi)
4303 {
4304         GSupplicantInterface *interface;
4305         struct connman_network *network;
4306
4307         if (!wifi || !wifi->network)
4308                 return -ENODEV;
4309
4310         wifi->network = connman_network_ref(wifi->network);
4311
4312         interface = wifi->interface;
4313         network = wifi->network;
4314
4315         DBG("network %p", network);
4316
4317         return g_supplicant_interface_signalpoll(interface, signalpoll_callback, network);
4318 }
4319
4320 static gboolean autosignalpoll_timeout(gpointer data)
4321 {
4322         struct wifi_data *wifi = data;
4323
4324         if (!wifi || !wifi->automaxspeed_timeout) {
4325                 DBG("automaxspeed_timeout is found to be zero. i.e. currently in disconnected state. !!");
4326                 return FALSE;
4327         }
4328
4329         int ret = network_signalpoll(wifi);
4330         if (ret < 0) {
4331                 DBG("Fail to get max speed !!");
4332                 wifi->automaxspeed_timeout = 0;
4333
4334                 if (wifi->network)
4335                         connman_network_unref(wifi->network);
4336
4337                 return FALSE;
4338         }
4339
4340         return TRUE;
4341 }
4342 #endif
4343
4344 static struct connman_network_driver network_driver = {
4345         .name           = "wifi",
4346         .type           = CONNMAN_NETWORK_TYPE_WIFI,
4347         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
4348         .probe          = network_probe,
4349         .remove         = network_remove,
4350         .connect        = network_connect,
4351         .disconnect     = network_disconnect,
4352 };
4353
4354 static void interface_added(GSupplicantInterface *interface)
4355 {
4356         const char *ifname = g_supplicant_interface_get_ifname(interface);
4357         const char *driver = g_supplicant_interface_get_driver(interface);
4358 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
4359         /*
4360          * Note: If supplicant interface's driver is wired then skip it,
4361          * because it meanti only for ethernet not Wi-Fi.
4362          */
4363         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
4364                 return;
4365 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
4366
4367 #if defined TIZEN_EXT
4368         bool is_5_0_ghz_supported = g_supplicant_interface_get_is_5_0_ghz_supported(interface);
4369 #endif
4370
4371         struct wifi_data *wifi;
4372
4373         wifi = g_supplicant_interface_get_data(interface);
4374         if (!wifi) {
4375                 wifi = get_pending_wifi_data(ifname);
4376                 if (!wifi)
4377                         return;
4378
4379                 wifi->interface = interface;
4380                 g_supplicant_interface_set_data(interface, wifi);
4381                 p2p_iface_list = g_list_append(p2p_iface_list, wifi);
4382                 wifi->p2p_device = true;
4383         }
4384
4385         DBG("ifname %s driver %s wifi %p tethering %d",
4386                         ifname, driver, wifi, wifi->tethering);
4387
4388         if (!wifi->device) {
4389                 connman_error("WiFi device not set");
4390                 return;
4391         }
4392
4393         connman_device_set_powered(wifi->device, true);
4394 #if defined TIZEN_EXT
4395         connman_device_set_wifi_5ghz_supported(wifi->device, is_5_0_ghz_supported);
4396         /* Max number of SSIDs supported by wlan chipset that can be scanned */
4397         int max_scan_ssids = g_supplicant_interface_get_max_scan_ssids(interface);
4398         connman_device_set_max_scan_ssids(wifi->device, max_scan_ssids);
4399 #endif
4400 }
4401
4402 static bool is_idle(struct wifi_data *wifi)
4403 {
4404         DBG("state %d", wifi->state);
4405
4406         switch (wifi->state) {
4407         case G_SUPPLICANT_STATE_UNKNOWN:
4408         case G_SUPPLICANT_STATE_DISABLED:
4409         case G_SUPPLICANT_STATE_DISCONNECTED:
4410         case G_SUPPLICANT_STATE_INACTIVE:
4411         case G_SUPPLICANT_STATE_SCANNING:
4412                 return true;
4413
4414         case G_SUPPLICANT_STATE_AUTHENTICATING:
4415         case G_SUPPLICANT_STATE_ASSOCIATING:
4416         case G_SUPPLICANT_STATE_ASSOCIATED:
4417         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4418         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4419         case G_SUPPLICANT_STATE_COMPLETED:
4420                 return false;
4421         }
4422
4423         return false;
4424 }
4425
4426 static bool is_idle_wps(GSupplicantInterface *interface,
4427                                                 struct wifi_data *wifi)
4428 {
4429         /* First, let's check if WPS processing did not went wrong */
4430         if (g_supplicant_interface_get_wps_state(interface) ==
4431                 G_SUPPLICANT_WPS_STATE_FAIL)
4432                 return false;
4433
4434         /* Unlike normal connection, being associated while processing wps
4435          * actually means that we are idling. */
4436         switch (wifi->state) {
4437         case G_SUPPLICANT_STATE_UNKNOWN:
4438         case G_SUPPLICANT_STATE_DISABLED:
4439         case G_SUPPLICANT_STATE_DISCONNECTED:
4440         case G_SUPPLICANT_STATE_INACTIVE:
4441         case G_SUPPLICANT_STATE_SCANNING:
4442         case G_SUPPLICANT_STATE_ASSOCIATED:
4443                 return true;
4444         case G_SUPPLICANT_STATE_AUTHENTICATING:
4445         case G_SUPPLICANT_STATE_ASSOCIATING:
4446         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4447         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4448         case G_SUPPLICANT_STATE_COMPLETED:
4449                 return false;
4450         }
4451
4452         return false;
4453 }
4454
4455 static bool handle_wps_completion(GSupplicantInterface *interface,
4456                                         struct connman_network *network,
4457                                         struct connman_device *device,
4458                                         struct wifi_data *wifi)
4459 {
4460         bool wps;
4461
4462         wps = connman_network_get_bool(network, "WiFi.UseWPS");
4463         if (wps) {
4464                 const unsigned char *ssid, *wps_ssid;
4465                 unsigned int ssid_len, wps_ssid_len;
4466                 struct disconnect_data *dd;
4467                 const char *wps_key;
4468
4469                 /* Checking if we got associated with requested
4470                  * network */
4471                 ssid = connman_network_get_blob(network, "WiFi.SSID",
4472                                                 &ssid_len);
4473
4474                 wps_ssid = g_supplicant_interface_get_wps_ssid(
4475                         interface, &wps_ssid_len);
4476
4477                 if (!wps_ssid || wps_ssid_len != ssid_len ||
4478                                 memcmp(ssid, wps_ssid, ssid_len) != 0) {
4479                         dd = g_malloc0(sizeof(*dd));
4480                         dd->wifi = wifi;
4481                         dd->network = network;
4482
4483                         connman_network_set_associating(network, false);
4484                         g_supplicant_interface_disconnect(wifi->interface,
4485                                                 disconnect_callback, dd);
4486 #if defined TIZEN_EXT
4487                         connman_network_set_bool(network, "WiFi.UseWPS", false);
4488                         connman_network_set_string(network, "WiFi.PinWPS", NULL);
4489 #endif
4490                         return false;
4491                 }
4492
4493                 wps_key = g_supplicant_interface_get_wps_key(interface);
4494 #if defined TIZEN_EXT
4495                 /* Check the passphrase and encrypt it
4496                  */
4497                  int ret;
4498                  gchar *passphrase = g_strdup(wps_key);
4499
4500                  connman_network_set_string(network, "WiFi.PinWPS", NULL);
4501
4502                  if (check_passphrase_ext(network, passphrase) < 0) {
4503                          DBG("[WPS] Invalid passphrase");
4504                          g_free(passphrase);
4505                          return true;
4506                  }
4507
4508                  ret = send_encryption_request(passphrase, network);
4509
4510                  g_free(passphrase);
4511
4512                  if (!ret)
4513                          DBG("[WPS] Encryption request succeeded");
4514                  else
4515                          DBG("[WPS] Encryption request failed %d", ret);
4516
4517 #else
4518                 connman_network_set_string(network, "WiFi.Passphrase",
4519                                         wps_key);
4520
4521                 connman_network_set_string(network, "WiFi.PinWPS", NULL);
4522 #endif
4523         }
4524
4525         return true;
4526 }
4527
4528 static bool handle_assoc_status_code(GSupplicantInterface *interface,
4529                                      struct wifi_data *wifi)
4530 {
4531 #if defined TIZEN_EXT
4532         if ((wifi->state == G_SUPPLICANT_STATE_ASSOCIATING ||
4533                         wifi->state == G_SUPPLICANT_STATE_AUTHENTICATING ||
4534                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) &&
4535 #else
4536         if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING &&
4537                         wifi->assoc_code == ASSOC_STATUS_NO_CLIENT &&
4538 #endif
4539                         wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) {
4540                 wifi->load_shaping_retries ++;
4541                 return TRUE;
4542         }
4543         wifi->load_shaping_retries = 0;
4544         return FALSE;
4545 }
4546
4547 static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
4548                                         struct connman_network *network,
4549                                         struct wifi_data *wifi)
4550 {
4551         struct connman_service *service;
4552
4553 #if defined TIZEN_EXT
4554         const char *security;
4555         if (wifi->connected)
4556                 return false;
4557
4558         security = connman_network_get_string(network, "WiFi.Security");
4559
4560         if (security && g_str_equal(security, "ieee8021x") == true &&
4561                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
4562                 wifi->retries = 0;
4563                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
4564
4565                 return false;
4566         }
4567
4568         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
4569                 return false;
4570 #else
4571         if ((wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE) &&
4572                         !((wifi->state == G_SUPPLICANT_STATE_ASSOCIATING) &&
4573                                 (wifi->assoc_code == ASSOC_STATUS_AUTH_TIMEOUT)))
4574                 return false;
4575
4576         if (wifi->connected)
4577                 return false;
4578 #endif
4579
4580         service = connman_service_lookup_from_network(network);
4581         if (!service)
4582                 return false;
4583
4584         wifi->retries++;
4585
4586         if (connman_service_get_favorite(service)) {
4587                 if (wifi->retries < FAVORITE_MAXIMUM_RETRIES)
4588                         return true;
4589         }
4590
4591         wifi->retries = 0;
4592         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
4593
4594         return false;
4595 }
4596
4597 #if defined TIZEN_EXT
4598 static bool handle_wifi_assoc_retry(struct connman_network *network,
4599                                         struct wifi_data *wifi)
4600 {
4601         const char *security;
4602
4603         if (!wifi->network || wifi->connected || wifi->disconnecting ||
4604                         connman_network_get_connecting(network) != true) {
4605                 wifi->assoc_retry_count = 0;
4606                 return false;
4607         }
4608
4609         if (wifi->state != G_SUPPLICANT_STATE_AUTHENTICATING &&
4610                         wifi->state != G_SUPPLICANT_STATE_ASSOCIATING &&
4611                         wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) {
4612                 wifi->assoc_retry_count = 0;
4613                 return false;
4614         }
4615
4616         security = connman_network_get_string(network, "WiFi.Security");
4617         if (security && g_str_equal(security, "ieee8021x") == true &&
4618                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
4619                 wifi->assoc_retry_count = 0;
4620                 return false;
4621         }
4622
4623         if (wifi->state > assoc_last_state)
4624                 assoc_last_state = wifi->state;
4625
4626         if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) {
4627                 wifi->assoc_retry_count = 0;
4628
4629                 /* Honestly it's not an invalid-key error,
4630                  * however QA team recommends that the invalid-key error
4631                  * might be better to display for user experience.
4632                  */
4633                 switch (assoc_last_state) {
4634                 case G_SUPPLICANT_STATE_AUTHENTICATING:
4635                         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_AUTHENTICATE_FAIL);
4636                         break;
4637                 case G_SUPPLICANT_STATE_ASSOCIATED:
4638                         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
4639                         break;
4640                 default:
4641                         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
4642                         break;
4643                 }
4644
4645                 return false;
4646         }
4647
4648         return true;
4649 }
4650
4651 static void handle_wifi_roaming_complete(struct connman_network *network)
4652 {
4653         const char *cur_bssid;
4654         const char *dst_bssid;
4655         const char *ifname;
4656         struct connman_device *device;
4657         struct connman_service *service;
4658         struct connman_ipconfig *ipconfig_ipv4;
4659         enum connman_ipconfig_type type;
4660         enum connman_ipconfig_method method;
4661
4662         if (!connman_setting_get_bool("WifiRoaming") ||
4663                         !connman_network_get_bool(network, "WiFi.Roaming"))
4664                 return;
4665
4666         device = connman_network_get_device(network);
4667         if (device) {
4668                 ifname = connman_device_get_string(device, "Interface");
4669                 cur_bssid = connman_network_get_string(network,
4670                                 "WiFi.RoamingCurBSSID");
4671                 dst_bssid = connman_network_get_string(network,
4672                                 "WiFi.RoamingDstBSSID");
4673         }
4674
4675         if (device && ifname && cur_bssid && dst_bssid) {
4676                 __connman_technology_notify_roaming_state(ifname,
4677                                 "success", cur_bssid, dst_bssid);
4678                 connman_network_set_bool(network,
4679                                 "WiFi.Roaming", false);
4680                 connman_network_set_string(network,
4681                                 "WiFi.RoamingCurBSSID", NULL);
4682                 connman_network_set_string(network,
4683                                 "WiFi.RoamingDstBSSID", NULL);
4684
4685                 service = connman_service_lookup_from_network(network);
4686                 if (!service)
4687                         return;
4688
4689                 ipconfig_ipv4 = __connman_service_get_ip4config(service);
4690                 if (!ipconfig_ipv4) {
4691                         connman_error("Service has no IPv4 configuration");
4692                         return;
4693                 }
4694
4695                 type = __connman_ipconfig_get_config_type(ipconfig_ipv4);
4696                 if (type != CONNMAN_IPCONFIG_TYPE_IPV4)
4697                         return;
4698
4699                 method = __connman_ipconfig_get_method(ipconfig_ipv4);
4700                 if (method != CONNMAN_IPCONFIG_METHOD_DHCP)
4701                         return;
4702
4703                 connman_network_set_bool(network, "WiFi.RoamingDHCP", true);
4704
4705                 if (set_connected_dhcp(network) != 0)
4706                         connman_network_set_bool(network, "WiFi.RoamingDHCP", false);
4707         }
4708 }
4709 #endif
4710
4711 static void interface_state(GSupplicantInterface *interface)
4712 {
4713         struct connman_network *network;
4714         struct connman_device *device;
4715         struct wifi_data *wifi;
4716         GSupplicantState state = g_supplicant_interface_get_state(interface);
4717 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
4718         /*
4719          * Note: If supplicant interface's driver is wired then skip it,
4720          * because it meanti only for ethernet not Wi-Fi.
4721          */
4722         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
4723                 return;
4724 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
4725
4726         bool wps;
4727         bool old_connected;
4728
4729         wifi = g_supplicant_interface_get_data(interface);
4730
4731         DBG("wifi %p interface state %d", wifi, state);
4732
4733         if (!wifi)
4734                 return;
4735
4736         device = wifi->device;
4737         if (!device)
4738                 return;
4739
4740         if (state == G_SUPPLICANT_STATE_COMPLETED) {
4741                 if (wifi->tethering_param) {
4742                         g_free(wifi->tethering_param->ssid);
4743                         g_free(wifi->tethering_param);
4744                         wifi->tethering_param = NULL;
4745                 }
4746
4747                 if (wifi->tethering)
4748                         stop_autoscan(device);
4749         }
4750
4751         if (g_supplicant_interface_get_ready(interface) &&
4752                                         !wifi->interface_ready) {
4753                 wifi->interface_ready = true;
4754                 finalize_interface_creation(wifi);
4755         }
4756
4757         network = wifi->network;
4758         if (!network)
4759                 return;
4760
4761         switch (state) {
4762         case G_SUPPLICANT_STATE_SCANNING:
4763 #if defined TIZEN_EXT
4764                 if (wifi->automaxspeed_timeout != 0) {
4765                         g_source_remove(wifi->automaxspeed_timeout);
4766                         wifi->automaxspeed_timeout = 0;
4767                         DBG("Remove signalpoll timer!!");
4768                 }
4769
4770                 if (!connman_network_get_bool(wifi->network, "WiFi.Roaming"))
4771 #endif
4772                 if (wifi->connected)
4773                         connman_network_set_connected(network, false);
4774
4775                 break;
4776
4777         case G_SUPPLICANT_STATE_AUTHENTICATING:
4778         case G_SUPPLICANT_STATE_ASSOCIATING:
4779 #if defined TIZEN_EXT
4780                 reset_autoscan(device);
4781 #else
4782                 stop_autoscan(device);
4783 #endif
4784 #if defined TIZEN_EXT
4785                 if (!connman_network_get_bool(wifi->network, "WiFi.Roaming"))
4786 #endif
4787                 if (!wifi->connected)
4788                         connman_network_set_associating(network, true);
4789
4790                 break;
4791
4792         case G_SUPPLICANT_STATE_COMPLETED:
4793 #if defined TIZEN_EXT
4794                 /* though it should be already reset: */
4795                 reset_autoscan(device);
4796
4797                 wifi->assoc_retry_count = 0;
4798
4799                 wifi->scan_pending_network = NULL;
4800
4801                 /* should be cleared scanning flag */
4802                 bool scanning = connman_device_get_scanning(device,
4803                                                CONNMAN_SERVICE_TYPE_WIFI);
4804                 if (scanning){
4805                         connman_device_set_scanning(device,
4806                                 CONNMAN_SERVICE_TYPE_WIFI, false);
4807                         connman_device_unref(device);
4808                 }
4809
4810                 if (!wifi->automaxspeed_timeout) {
4811                         DBG("Going to start signalpoll timer!!");
4812                         int ret = network_signalpoll(wifi);
4813                         if (ret < 0)
4814                                 DBG("Fail to get max speed !!");
4815                         else
4816                                 wifi->automaxspeed_timeout = g_timeout_add_seconds(10, autosignalpoll_timeout, wifi);
4817                 }
4818
4819                 g_hash_table_remove_all(failed_bssids);
4820                 handle_wifi_roaming_complete(network);
4821 #else
4822                 /* though it should be already stopped: */
4823                 stop_autoscan(device);
4824 #endif
4825
4826                 if (!handle_wps_completion(interface, network, device, wifi))
4827                         break;
4828
4829                 connman_network_set_connected(network, true);
4830
4831                 wifi->disconnect_code = 0;
4832                 wifi->assoc_code = 0;
4833                 wifi->load_shaping_retries = 0;
4834                 break;
4835
4836         case G_SUPPLICANT_STATE_DISCONNECTED:
4837 #if defined TIZEN_EXT
4838                 connman_network_set_strength(network, 0);
4839                 connman_network_set_maxspeed(network, 0);
4840
4841                 if (wifi->automaxspeed_timeout != 0) {
4842                         g_source_remove(wifi->automaxspeed_timeout);
4843                         wifi->automaxspeed_timeout = 0;
4844                         DBG("Remove signalpoll timer!!");
4845                 }
4846 #endif
4847                 /*
4848                  * If we're in one of the idle modes, we have
4849                  * not started association yet and thus setting
4850                  * those ones to FALSE could cancel an association
4851                  * in progress.
4852                  */
4853                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
4854                 if (wps)
4855                         if (is_idle_wps(interface, wifi))
4856                                 break;
4857
4858                 if (is_idle(wifi))
4859                         break;
4860
4861 #if defined TIZEN_EXT
4862                 if (!wifi->connected && handle_assoc_status_code(interface, wifi)) {
4863                         const char *group = connman_network_get_group(network);
4864                         GSupplicantNetwork *supplicant_network;
4865                         GSList *bssid_list = NULL;
4866                         guint bssid_length = 0;
4867
4868                         if (group) {
4869                                 supplicant_network = g_supplicant_interface_get_network(interface, group);
4870
4871                                 connman_network_set_assoc_reject_table(network,
4872                                                 g_supplicant_network_clone_assoc_reject_table(supplicant_network));
4873
4874                                 g_supplicant_network_update_assoc_reject(interface, supplicant_network);
4875                         }
4876
4877                         bssid_list = (GSList *)connman_network_get_bssid_list(network);
4878                         if (bssid_list)
4879                                 bssid_length = g_slist_length(bssid_list);
4880
4881                         if (bssid_length > 1 && bssid_length > g_hash_table_size(failed_bssids)) {
4882                                 network_connect(network);
4883                                 break;
4884                         }
4885
4886                         wifi->load_shaping_retries = 0;
4887                 }
4888 #else
4889                 if (handle_assoc_status_code(interface, wifi))
4890                         break;
4891 #endif
4892
4893                 /* If previous state was 4way-handshake, then
4894                  * it's either: psk was incorrect and thus we retry
4895                  * or if we reach the maximum retries we declare the
4896                  * psk as wrong */
4897                 if (handle_4way_handshake_failure(interface,
4898                                                 network, wifi))
4899                         break;
4900
4901                 /* See table 8-36 Reason codes in IEEE Std 802.11 */
4902                 switch (wifi->disconnect_code) {
4903 #if defined TIZEN_EXT
4904                 case 1: /* Unspecified reason */
4905                         /* Let's assume it's because we got blocked */
4906 #endif
4907                 case 6: /* Class 2 frame received from nonauthenticated STA */
4908                         connman_network_set_error(network,
4909                                                 CONNMAN_NETWORK_ERROR_BLOCKED);
4910                         break;
4911
4912                 default:
4913                         break;
4914                 }
4915
4916 #if defined TIZEN_EXT
4917                 if (wifi->assoc_retry_count == 0)
4918                         assoc_last_state = G_SUPPLICANT_STATE_UNKNOWN;
4919
4920                 /* Some of Wi-Fi networks are not comply Wi-Fi specification.
4921                  * Retry association until its retry count is expired */
4922                 if (handle_wifi_assoc_retry(network, wifi) == true) {
4923                         throw_wifi_scan(wifi->device, scan_callback);
4924                         wifi->scan_pending_network = wifi->network;
4925                         break;
4926                 }
4927
4928                 if (wifi->disconnect_code > 0){
4929                         DBG("Set disconnect reason code(%d)", wifi->disconnect_code);
4930                         connman_network_set_disconnect_reason(network, wifi->disconnect_code);
4931                 }
4932 #endif
4933
4934                 if (network != wifi->pending_network) {
4935                         connman_network_set_connected(network, false);
4936                         connman_network_set_associating(network, false);
4937                 }
4938                 wifi->disconnecting = false;
4939
4940                 start_autoscan(device);
4941
4942                 break;
4943
4944         case G_SUPPLICANT_STATE_INACTIVE:
4945 #if defined TIZEN_EXT
4946                 if (handle_wps_completion(interface, network, device, wifi) == false)
4947                         break;
4948 #endif
4949                 connman_network_set_associating(network, false);
4950                 start_autoscan(device);
4951
4952                 break;
4953
4954         case G_SUPPLICANT_STATE_UNKNOWN:
4955         case G_SUPPLICANT_STATE_DISABLED:
4956         case G_SUPPLICANT_STATE_ASSOCIATED:
4957         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4958         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4959                 break;
4960         }
4961
4962         old_connected = wifi->connected;
4963         wifi->state = state;
4964
4965         /* Saving wpa_s state policy:
4966          * If connected and if the state changes are roaming related:
4967          * --> We stay connected
4968          * If completed
4969          * --> We are connected
4970          * All other case:
4971          * --> We are not connected
4972          * */
4973         switch (state) {
4974         case G_SUPPLICANT_STATE_AUTHENTICATING:
4975         case G_SUPPLICANT_STATE_ASSOCIATING:
4976         case G_SUPPLICANT_STATE_ASSOCIATED:
4977         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4978         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4979                 if (wifi->connected)
4980                         connman_warn("Probably roaming right now!"
4981                                                 " Staying connected...");
4982                 break;
4983         case G_SUPPLICANT_STATE_SCANNING:
4984                 wifi->connected = false;
4985
4986                 if (old_connected)
4987                         start_autoscan(device);
4988                 break;
4989         case G_SUPPLICANT_STATE_COMPLETED:
4990                 wifi->connected = true;
4991                 break;
4992         default:
4993                 wifi->connected = false;
4994                 break;
4995         }
4996
4997         DBG("DONE");
4998 }
4999
5000 static void interface_removed(GSupplicantInterface *interface)
5001 {
5002         const char *ifname = g_supplicant_interface_get_ifname(interface);
5003         struct wifi_data *wifi;
5004 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5005         /*
5006          * Note: If supplicant interface's driver is wired then skip it,
5007          * because it meanti only for ethernet not Wi-Fi.
5008          */
5009         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5010                 return;
5011 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5012
5013
5014         DBG("ifname %s", ifname);
5015
5016         wifi = g_supplicant_interface_get_data(interface);
5017
5018 #if defined TIZEN_EXT_WIFI_MESH
5019         if (wifi && wifi->mesh_interface) {
5020                 DBG("Notify mesh interface remove");
5021                 connman_mesh_notify_interface_remove(true);
5022                 struct wifi_mesh_info *mesh_info = wifi->mesh_info;
5023                 g_free(mesh_info->parent_ifname);
5024                 g_free(mesh_info->ifname);
5025                 g_free(mesh_info->identifier);
5026                 g_free(mesh_info);
5027                 wifi->mesh_interface = false;
5028                 wifi->mesh_info = NULL;
5029                 return;
5030         }
5031 #endif
5032
5033         if (wifi)
5034                 wifi->interface = NULL;
5035
5036         if (wifi && wifi->tethering)
5037                 return;
5038
5039         if (!wifi || !wifi->device) {
5040                 DBG("wifi interface already removed");
5041                 return;
5042         }
5043
5044         connman_device_set_powered(wifi->device, false);
5045
5046         check_p2p_technology();
5047 #if defined TIZEN_EXT_WIFI_MESH
5048         check_mesh_technology();
5049 #endif
5050 }
5051
5052 static void set_device_type(const char *type, char dev_type[17])
5053 {
5054         const char *oui = "0050F204";
5055         const char *category = "0001";
5056         const char *sub_category = "0000";
5057
5058         if (!g_strcmp0(type, "handset")) {
5059                 category = "000A";
5060                 sub_category = "0005";
5061         } else if (!g_strcmp0(type, "vm") || !g_strcmp0(type, "container"))
5062                 sub_category = "0001";
5063         else if (!g_strcmp0(type, "server"))
5064                 sub_category = "0002";
5065         else if (!g_strcmp0(type, "laptop"))
5066                 sub_category = "0005";
5067         else if (!g_strcmp0(type, "desktop"))
5068                 sub_category = "0006";
5069         else if (!g_strcmp0(type, "tablet"))
5070                 sub_category = "0009";
5071         else if (!g_strcmp0(type, "watch"))
5072                 category = "00FF";
5073
5074         snprintf(dev_type, 17, "%s%s%s", category, oui, sub_category);
5075 }
5076
5077 static void p2p_support(GSupplicantInterface *interface)
5078 {
5079         char dev_type[17] = {};
5080         const char *hostname;
5081 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5082         /*
5083          * Note: If supplicant interface's driver is wired then skip it,
5084          * because it meanti only for ethernet not Wi-Fi.
5085          */
5086         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5087                 return;
5088 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5089
5090
5091         DBG("");
5092
5093         if (!interface)
5094                 return;
5095
5096         if (!g_supplicant_interface_has_p2p(interface))
5097                 return;
5098
5099         if (connman_technology_driver_register(&p2p_tech_driver) < 0) {
5100                 DBG("Could not register P2P technology driver");
5101                 return;
5102         }
5103
5104         hostname = connman_utsname_get_hostname();
5105         if (!hostname)
5106                 hostname = "ConnMan";
5107
5108         set_device_type(connman_machine_get_type(), dev_type);
5109         g_supplicant_interface_set_p2p_device_config(interface,
5110                                                         hostname, dev_type);
5111         connman_peer_driver_register(&peer_driver);
5112 }
5113
5114 static void scan_started(GSupplicantInterface *interface)
5115 {
5116 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5117         /*
5118          * Note: If supplicant interface's driver is wired then skip it,
5119          * because it meanti only for ethernet not Wi-Fi.
5120          */
5121         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5122                 return;
5123 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5124
5125         DBG("");
5126 }
5127
5128 static void scan_finished(GSupplicantInterface *interface)
5129 {
5130 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5131         /*
5132          * Note: If supplicant interface's driver is wired then skip it,
5133          * because it meanti only for ethernet not Wi-Fi.
5134          */
5135         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5136                 return;
5137 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5138
5139 #if defined TIZEN_EXT
5140         struct wifi_data *wifi;
5141         bool is_associating = false;
5142         static bool is_scanning = true;
5143 #endif
5144
5145         DBG("");
5146
5147 #if defined TIZEN_EXT
5148         wifi = g_supplicant_interface_get_data(interface);
5149         if (wifi && wifi->scan_pending_network) {
5150                 network_connect(wifi->scan_pending_network);
5151                 wifi->scan_pending_network = NULL;
5152         }
5153
5154         //service state - associating
5155         if(!wifi || !wifi->network)
5156                 return;
5157
5158         is_associating = connman_network_get_associating(wifi->network);
5159         if(is_associating && is_scanning){
5160                 is_scanning = false;
5161                 DBG("send scan for connecting");
5162                 throw_wifi_scan(wifi->device, scan_callback);
5163
5164                 return;
5165         }
5166         is_scanning = true;
5167
5168         //go scan
5169
5170 #endif
5171 }
5172
5173 static void ap_create_fail(GSupplicantInterface *interface)
5174 {
5175 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5176         /*
5177          * Note: If supplicant interface's driver is wired then skip it,
5178          * because it meanti only for ethernet not Wi-Fi.
5179          */
5180         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5181                 return;
5182 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5183
5184         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5185         int ret;
5186
5187         if ((wifi->tethering) && (wifi->tethering_param)) {
5188                 DBG("%s create AP fail \n",
5189                                 g_supplicant_interface_get_ifname(wifi->interface));
5190
5191                 connman_inet_remove_from_bridge(wifi->index, wifi->bridge);
5192                 wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
5193                 wifi->tethering = false;
5194
5195                 ret = tech_set_tethering(wifi->tethering_param->technology,
5196                                 wifi->tethering_param->ssid->ssid,
5197                                 wifi->tethering_param->ssid->passphrase,
5198                                 wifi->bridge, true);
5199
5200                 if ((ret == -EOPNOTSUPP) && (wifi_technology)) {
5201                         connman_technology_tethering_notify(wifi_technology,false);
5202                 }
5203
5204                 g_free(wifi->tethering_param->ssid);
5205                 g_free(wifi->tethering_param);
5206                 wifi->tethering_param = NULL;
5207         }
5208 }
5209
5210 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
5211 {
5212         unsigned char strength;
5213
5214         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
5215 #if !defined TIZEN_EXT
5216         if (strength > 100)
5217                 strength = 100;
5218 #endif
5219
5220         return strength;
5221 }
5222
5223 #if defined TIZEN_EXT_WIFI_MESH
5224 static void mesh_peer_added(GSupplicantNetwork *supplicant_network)
5225 {
5226         GSupplicantInterface *interface;
5227         struct wifi_data *wifi;
5228         const char *name, *security;
5229         struct connman_mesh *connman_mesh;
5230         struct wifi_mesh_info *mesh_info;
5231         const unsigned char *bssid;
5232         const char *identifier;
5233         char *address;
5234         uint16_t frequency;
5235         int ret;
5236
5237         interface = g_supplicant_network_get_interface(supplicant_network);
5238         wifi = g_supplicant_interface_get_data(interface);
5239         if (!wifi || !wifi->mesh_interface) {
5240                 DBG("Virtual Mesh interface not created");
5241                 return;
5242         }
5243
5244         bssid = g_supplicant_network_get_bssid(supplicant_network);
5245         address = g_malloc0(19);
5246         snprintf(address, 19, "%02x:%02x:%02x:%02x:%02x:%02x", bssid[0], bssid[1],
5247                                                                  bssid[2], bssid[3], bssid[4], bssid[5]);
5248
5249         identifier = g_supplicant_network_get_identifier(supplicant_network);
5250         name = g_supplicant_network_get_name(supplicant_network);
5251         security = g_supplicant_network_get_security(supplicant_network);
5252         frequency = g_supplicant_network_get_frequency(supplicant_network);
5253
5254         mesh_info = wifi->mesh_info;
5255         connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
5256         if (connman_mesh)
5257                 goto done;
5258
5259         DBG("Mesh Peer name %s identifier %s security %s added", name, identifier,
5260                                         security);
5261         connman_mesh = connman_mesh_create(mesh_info->identifier, identifier);
5262         connman_mesh_set_name(connman_mesh, name);
5263         connman_mesh_set_security(connman_mesh, security);
5264         connman_mesh_set_frequency(connman_mesh, frequency);
5265         connman_mesh_set_address(connman_mesh, address);
5266         connman_mesh_set_index(connman_mesh, mesh_info->index);
5267         connman_mesh_set_strength(connman_mesh,
5268                                                 calculate_strength(supplicant_network));
5269         connman_mesh_set_peer_type(connman_mesh, CONNMAN_MESH_PEER_TYPE_DISCOVERED);
5270
5271         ret = connman_mesh_register(connman_mesh);
5272         if (ret == -EALREADY)
5273                 DBG("Mesh Peer is already registered");
5274
5275 done:
5276         g_free(address);
5277 }
5278
5279 static void mesh_peer_removed(GSupplicantNetwork *supplicant_network)
5280 {
5281         GSupplicantInterface *interface;
5282         struct wifi_data *wifi;
5283         struct connman_mesh *connman_mesh;
5284         struct wifi_mesh_info *mesh_info;
5285         const char *identifier;
5286
5287         interface = g_supplicant_network_get_interface(supplicant_network);
5288         wifi = g_supplicant_interface_get_data(interface);
5289         if (!wifi || !wifi->mesh_interface) {
5290                 DBG("Virtual Mesh interface not created");
5291                 return;
5292         }
5293
5294         identifier = g_supplicant_network_get_identifier(supplicant_network);
5295         if (!identifier) {
5296                 DBG("Failed to get Mesh Peer identifier");
5297                 return;
5298         }
5299
5300         mesh_info = wifi->mesh_info;
5301         connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
5302         if (connman_mesh) {
5303                 /* Do not unregister connected mesh peer */
5304                 if (connman_mesh_peer_is_connected_state(connman_mesh)) {
5305                         DBG("Mesh Peer %s is connected", identifier);
5306                         return;
5307                 }
5308                 DBG("Mesh Peer identifier %s removed", identifier);
5309                 connman_mesh_unregister(connman_mesh);
5310         }
5311 }
5312 #endif
5313
5314
5315 #if defined TIZEN_EXT
5316 static GSList *get_supported_security_list(unsigned int keymgmt,
5317                                         bool owe_transition_mode,
5318                                         GSupplicantNetwork *supplicant_network)
5319 {
5320         GSList *sec_list = NULL;
5321         dbus_bool_t privacy = g_supplicant_network_get_privacy(supplicant_network);
5322         const char *enc_mode = g_supplicant_network_get_enc_mode(supplicant_network);
5323
5324         if (keymgmt &
5325                         (G_SUPPLICANT_KEYMGMT_WPA_EAP |
5326                                         G_SUPPLICANT_KEYMGMT_WPA_EAP_256))
5327                 sec_list = g_slist_prepend (sec_list, "ieee8021x");
5328         else if (keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_EAP)
5329                 sec_list = g_slist_prepend (sec_list, "ft_ieee8021x");
5330
5331         if (sec_list)
5332                 return sec_list;
5333
5334         if (keymgmt &
5335                         (G_SUPPLICANT_KEYMGMT_WPA_PSK |
5336                                         G_SUPPLICANT_KEYMGMT_WPA_PSK_256)) {
5337                 if (!g_strcmp0(enc_mode, "aes"))
5338                         sec_list = g_slist_prepend (sec_list, "rsn");
5339                 else if (!g_strcmp0(enc_mode, "tkip"))
5340                         sec_list = g_slist_prepend (sec_list, "psk");
5341                 else if (!g_strcmp0(enc_mode, "mixed")) {
5342                         sec_list = g_slist_prepend (sec_list, "psk");
5343                         sec_list = g_slist_prepend (sec_list, "rsn");
5344                 }
5345         }
5346
5347         if (keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_PSK)
5348                 sec_list = g_slist_prepend (sec_list, "ft_psk");
5349
5350         if (keymgmt & G_SUPPLICANT_KEYMGMT_SAE)
5351                 sec_list = g_slist_prepend (sec_list, "sae");
5352         if (keymgmt & G_SUPPLICANT_KEYMGMT_FT_SAE)
5353                 sec_list = g_slist_prepend (sec_list, "ft_sae");
5354
5355         if (keymgmt & G_SUPPLICANT_KEYMGMT_OWE || owe_transition_mode)
5356                 sec_list = g_slist_prepend (sec_list, "owe");
5357         if (keymgmt & G_SUPPLICANT_KEYMGMT_DPP)
5358                 sec_list = g_slist_prepend (sec_list, "dpp");
5359
5360         if (sec_list)
5361                 return sec_list;
5362
5363         if (privacy)
5364                 sec_list = g_slist_prepend (sec_list, "wep");
5365         else
5366                 sec_list = g_slist_prepend (sec_list, "none");
5367
5368         return sec_list;
5369 }
5370 #endif
5371
5372 static void network_added(GSupplicantNetwork *supplicant_network)
5373 {
5374         struct connman_network *network;
5375         GSupplicantInterface *interface;
5376         struct wifi_data *wifi;
5377         const char *name, *identifier, *security, *group, *mode;
5378         const unsigned char *ssid;
5379         unsigned int ssid_len;
5380         bool wps;
5381         bool wps_pbc;
5382         bool wps_ready;
5383         bool wps_advertizing;
5384
5385 #if defined TIZEN_EXT
5386         bool owe_transition_mode;
5387         const unsigned char *transition_mode_ssid;
5388         const unsigned char *transition_mode_bssid;
5389         unsigned int transition_mode_ssid_len;
5390         unsigned int keymgmt;
5391         GSList *vsie_list = NULL;
5392         GSList *sec_list = NULL;
5393         const unsigned char *country_code;
5394         ieee80211_modes_e phy_mode;
5395 #endif
5396
5397         mode = g_supplicant_network_get_mode(supplicant_network);
5398         identifier = g_supplicant_network_get_identifier(supplicant_network);
5399 #if defined TIZEN_EXT
5400         if (!simplified_log)
5401 #endif
5402         DBG("%s", identifier);
5403
5404         if (!g_strcmp0(mode, "adhoc"))
5405                 return;
5406
5407 #if defined TIZEN_EXT_WIFI_MESH
5408         if (!g_strcmp0(mode, "mesh")) {
5409                 mesh_peer_added(supplicant_network);
5410                 return;
5411         }
5412 #endif
5413
5414         interface = g_supplicant_network_get_interface(supplicant_network);
5415 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5416         /*
5417          * Note: If supplicant interface's driver is wired then skip it,
5418          * because it meanti only for ethernet not Wi-Fi.
5419          */
5420         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5421                 return;
5422 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5423
5424         wifi = g_supplicant_interface_get_data(interface);
5425         name = g_supplicant_network_get_name(supplicant_network);
5426         security = g_supplicant_network_get_security(supplicant_network);
5427         group = g_supplicant_network_get_identifier(supplicant_network);
5428         wps = g_supplicant_network_get_wps(supplicant_network);
5429         wps_pbc = g_supplicant_network_is_wps_pbc(supplicant_network);
5430         wps_ready = g_supplicant_network_is_wps_active(supplicant_network);
5431         wps_advertizing = g_supplicant_network_is_wps_advertizing(
5432                                                         supplicant_network);
5433
5434         if (!wifi)
5435                 return;
5436
5437         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
5438
5439         network = connman_device_get_network(wifi->device, identifier);
5440
5441         if (!network) {
5442                 network = connman_network_create(identifier,
5443                                                 CONNMAN_NETWORK_TYPE_WIFI);
5444                 if (!network)
5445                         return;
5446
5447                 connman_network_set_index(network, wifi->index);
5448
5449                 if (connman_device_add_network(wifi->device, network) < 0) {
5450                         connman_network_unref(network);
5451                         return;
5452                 }
5453
5454                 wifi->networks = g_slist_prepend(wifi->networks, network);
5455         }
5456
5457         if (name && name[0] != '\0')
5458                 connman_network_set_name(network, name);
5459
5460         connman_network_set_blob(network, "WiFi.SSID",
5461                                                 ssid, ssid_len);
5462 #if defined TIZEN_EXT
5463         vsie_list = (GSList *)g_supplicant_network_get_wifi_vsie(supplicant_network);
5464         if (vsie_list)
5465                 connman_network_set_vsie_list(network, vsie_list);
5466         else
5467                 DBG("vsie_list is NULL");
5468         country_code = g_supplicant_network_get_countrycode(supplicant_network);
5469         connman_network_set_countrycode(network, country_code);
5470         phy_mode = g_supplicant_network_get_phy_mode(supplicant_network);
5471         connman_network_set_phy_mode(network, phy_mode);
5472 #endif
5473         connman_network_set_string(network, "WiFi.Security", security);
5474         connman_network_set_strength(network,
5475                                 calculate_strength(supplicant_network));
5476         connman_network_set_bool(network, "WiFi.WPS", wps);
5477         connman_network_set_bool(network, "WiFi.WPSAdvertising",
5478                                 wps_advertizing);
5479
5480         if (wps) {
5481                 /* Is AP advertizing for WPS association?
5482                  * If so, we decide to use WPS by default */
5483                 if (wps_ready && wps_pbc &&
5484                                                 wps_advertizing)
5485 #if !defined TIZEN_EXT
5486                         connman_network_set_bool(network, "WiFi.UseWPS", true);
5487 #else
5488                         DBG("wps is activating by ap but ignore it.");
5489 #endif
5490         }
5491
5492         connman_network_set_frequency(network,
5493                         g_supplicant_network_get_frequency(supplicant_network));
5494
5495 #if defined TIZEN_EXT
5496         keymgmt = g_supplicant_network_get_keymgmt(supplicant_network);
5497         connman_network_set_bssid(network,
5498                         g_supplicant_network_get_bssid(supplicant_network));
5499         owe_transition_mode = (bool)g_supplicant_network_get_transition_mode(supplicant_network);
5500         connman_network_set_bool(network, "WiFi.TRANSITION_MODE", owe_transition_mode);
5501         if (owe_transition_mode) {
5502                 transition_mode_ssid = (unsigned char *)g_supplicant_network_get_transition_mode_ssid(supplicant_network, &transition_mode_ssid_len);
5503                 connman_network_set_blob(network, "WiFi.TRANSITION_MODE_SSID",
5504                                                         transition_mode_ssid, transition_mode_ssid_len);
5505                 transition_mode_bssid = g_supplicant_network_get_transition_mode_bssid(supplicant_network);
5506                 connman_network_set_transition_mode_bssid(network, transition_mode_bssid);
5507         }
5508
5509         sec_list = get_supported_security_list(keymgmt,
5510                         owe_transition_mode, supplicant_network);
5511
5512         connman_network_set_sec_list(network, sec_list);
5513         connman_network_set_maxrate(network,
5514                         g_supplicant_network_get_maxrate(supplicant_network));
5515         connman_network_set_enc_mode(network,
5516                         g_supplicant_network_get_enc_mode(supplicant_network));
5517         connman_network_set_rsn_mode(network,
5518                         g_supplicant_network_get_rsn_mode(supplicant_network));
5519         connman_network_set_bool(network, "WiFi.PMFRequired",
5520                         (bool)g_supplicant_network_is_pmf_required(supplicant_network));
5521         connman_network_set_keymgmt(network, keymgmt);
5522         connman_network_set_bool(network, "WiFi.HS20AP",
5523                         g_supplicant_network_is_hs20AP(supplicant_network));
5524         connman_network_set_bssid_list(network,
5525                         (GSList *)g_supplicant_network_get_bssid_list(supplicant_network));
5526         connman_network_set_last_connected_bssid(network,
5527                         g_supplicant_network_get_last_connected_bssid(supplicant_network));
5528         connman_network_set_assoc_reject_table(network,
5529                         g_supplicant_network_clone_assoc_reject_table(supplicant_network));
5530 #endif
5531         connman_network_set_available(network, true);
5532         connman_network_set_string(network, "WiFi.Mode", mode);
5533
5534 #if defined TIZEN_EXT
5535         if (group)
5536 #else
5537         if (ssid)
5538 #endif
5539                 connman_network_set_group(network, group);
5540
5541 #if defined TIZEN_EXT
5542         g_supplicant_network_set_last_connected_bssid(supplicant_network,
5543                         connman_network_get_last_connected_bssid(network));
5544 #endif
5545
5546 #if defined TIZEN_EXT
5547         if (wifi_first_scan == true)
5548                 found_with_first_scan = true;
5549 #endif
5550
5551         if (wifi->hidden && ssid) {
5552 #if defined TIZEN_EXT
5553                 if (network_security(wifi->hidden->security) ==
5554                         network_security(security) &&
5555 #else
5556                 if (!g_strcmp0(wifi->hidden->security, security) &&
5557 #endif
5558                                 wifi->hidden->ssid_len == ssid_len &&
5559                                 !memcmp(wifi->hidden->ssid, ssid, ssid_len)) {
5560                         connman_network_connect_hidden(network,
5561                                         wifi->hidden->identity,
5562                                         wifi->hidden->passphrase,
5563                                         wifi->hidden->user_data);
5564                         wifi->hidden->user_data = NULL;
5565                         hidden_free(wifi->hidden);
5566                         wifi->hidden = NULL;
5567                 }
5568         }
5569 }
5570
5571 static void network_removed(GSupplicantNetwork *network)
5572 {
5573         GSupplicantInterface *interface;
5574         struct wifi_data *wifi;
5575         const char *name, *identifier;
5576         struct connman_network *connman_network;
5577
5578 #if defined TIZEN_EXT_WIFI_MESH
5579         const char *mode;
5580         mode = g_supplicant_network_get_mode(network);
5581         if (!g_strcmp0(mode, "mesh")) {
5582                 mesh_peer_removed(network);
5583                 return;
5584         }
5585 #endif
5586
5587         interface = g_supplicant_network_get_interface(network);
5588 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5589         /*
5590          * Note: If supplicant interface's driver is wired then skip it,
5591          * because it meanti only for ethernet not Wi-Fi.
5592          */
5593         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5594                 return;
5595 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5596
5597         wifi = g_supplicant_interface_get_data(interface);
5598         identifier = g_supplicant_network_get_identifier(network);
5599         name = g_supplicant_network_get_name(network);
5600
5601         DBG("name %s", name);
5602
5603         if (!wifi)
5604                 return;
5605
5606         connman_network = connman_device_get_network(wifi->device, identifier);
5607         if (!connman_network)
5608                 return;
5609
5610 #if defined TIZEN_EXT
5611         if (connman_network == wifi->scan_pending_network)
5612                 wifi->scan_pending_network = NULL;
5613
5614         if (connman_network == wifi->pending_network)
5615                 wifi->pending_network = NULL;
5616
5617         if(connman_network_get_connecting(connman_network) == true){
5618                 connman_network_set_connected(connman_network, false);
5619         }
5620 #endif
5621
5622         wifi->networks = g_slist_remove(wifi->networks, connman_network);
5623
5624         connman_device_remove_network(wifi->device, connman_network);
5625         connman_network_unref(connman_network);
5626 }
5627
5628 static void network_changed(GSupplicantNetwork *network, const char *property)
5629 {
5630         GSupplicantInterface *interface;
5631         struct wifi_data *wifi;
5632         const char *name, *identifier;
5633         struct connman_network *connman_network;
5634         bool update_needed;
5635
5636 #if defined TIZEN_EXT
5637         const unsigned char *bssid;
5638         unsigned int maxrate;
5639         uint16_t frequency;
5640         bool wps;
5641         const unsigned char *country_code;
5642         ieee80211_modes_e phy_mode;
5643         GSList *bssid_list;
5644 #endif
5645
5646         interface = g_supplicant_network_get_interface(network);
5647 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5648         /*
5649          * Note: If supplicant interface's driver is wired then skip it,
5650          * because it meanti only for ethernet not Wi-Fi.
5651          */
5652         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5653                 return;
5654 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5655
5656         wifi = g_supplicant_interface_get_data(interface);
5657         identifier = g_supplicant_network_get_identifier(network);
5658         name = g_supplicant_network_get_name(network);
5659
5660 #if defined TIZEN_EXT
5661         if (!simplified_log)
5662                 DBG("name %s property %s", name, property);
5663 #else
5664         DBG("name %s", name);
5665 #endif
5666
5667         if (!wifi)
5668                 return;
5669
5670         connman_network = connman_device_get_network(wifi->device, identifier);
5671         if (!connman_network)
5672                 return;
5673
5674         if (g_str_equal(property, "WPSCapabilities")) {
5675                 bool wps;
5676                 bool wps_pbc;
5677                 bool wps_ready;
5678                 bool wps_advertizing;
5679
5680                 wps = g_supplicant_network_get_wps(network);
5681                 wps_pbc = g_supplicant_network_is_wps_pbc(network);
5682                 wps_ready = g_supplicant_network_is_wps_active(network);
5683                 wps_advertizing =
5684                         g_supplicant_network_is_wps_advertizing(network);
5685
5686                 connman_network_set_bool(connman_network, "WiFi.WPS", wps);
5687                 connman_network_set_bool(connman_network,
5688                                 "WiFi.WPSAdvertising", wps_advertizing);
5689
5690                 if (wps) {
5691                         /*
5692                          * Is AP advertizing for WPS association?
5693                          * If so, we decide to use WPS by default
5694                          */
5695                         if (wps_ready && wps_pbc && wps_advertizing)
5696                                 connman_network_set_bool(connman_network,
5697                                                         "WiFi.UseWPS", true);
5698                 }
5699
5700                 update_needed = true;
5701         } else if (g_str_equal(property, "Signal")) {
5702                 connman_network_set_strength(connman_network,
5703                                         calculate_strength(network));
5704                 update_needed = true;
5705         }
5706 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
5707         else if (g_str_equal(property, "LastConnectedBSSID")) {
5708                 const char *ident, *group;
5709                 char *service_ident;
5710                 bool need_save;
5711
5712                 ident = connman_device_get_ident(wifi->device);
5713                 group = connman_network_get_group(connman_network);
5714                 if (ident && group) {
5715                         service_ident = g_strdup_printf("%s_%s_%s",
5716                                 __connman_network_get_type(connman_network), ident, group);
5717
5718                         need_save = connman_device_set_last_connected_ident(wifi->device, service_ident);
5719                         if (need_save)
5720                                 connman_device_save_last_connected(wifi->device);
5721
5722                         g_free(service_ident);
5723                 }
5724
5725                 connman_network_set_last_connected_bssid(connman_network,
5726                                         g_supplicant_network_get_last_connected_bssid(network));
5727
5728                 update_needed = true;
5729         }
5730 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
5731 #if defined TIZEN_EXT
5732         else if (g_str_equal(property, "UpdateAssocReject")) {
5733                 connman_network_set_assoc_reject_table(connman_network,
5734                                 g_supplicant_network_clone_assoc_reject_table(network));
5735                 update_needed = true;
5736         }
5737 #endif
5738         else
5739                 update_needed = false;
5740
5741         if (update_needed)
5742                 connman_network_update(connman_network);
5743
5744 #if defined TIZEN_EXT
5745         bssid = g_supplicant_network_get_bssid(network);
5746         maxrate = g_supplicant_network_get_maxrate(network);
5747         frequency = g_supplicant_network_get_frequency(network);
5748         wps = g_supplicant_network_get_wps(network);
5749         phy_mode = g_supplicant_network_get_phy_mode(network);
5750
5751         connman_network_set_bssid(connman_network, bssid);
5752         connman_network_set_maxrate(connman_network, maxrate);
5753         connman_network_set_frequency(connman_network, frequency);
5754         connman_network_set_bool(connman_network, "WiFi.WPS", wps);
5755         country_code = g_supplicant_network_get_countrycode(network);
5756         connman_network_set_countrycode(connman_network, country_code);
5757         bssid_list = (GSList *)g_supplicant_network_get_bssid_list(network);
5758         connman_network_set_bssid_list(connman_network, bssid_list);
5759         connman_network_set_phy_mode(connman_network, phy_mode);
5760
5761         if (g_str_equal(property, "CheckMultiBssidConnect") &&
5762                         connman_network_get_associating(connman_network))
5763                 network_connect(connman_network);
5764 #endif
5765 }
5766
5767 static void network_associated(GSupplicantNetwork *network)
5768 {
5769         GSupplicantInterface *interface;
5770         struct wifi_data *wifi;
5771         struct connman_network *connman_network;
5772         const char *identifier;
5773
5774         DBG("");
5775
5776         interface = g_supplicant_network_get_interface(network);
5777         if (!interface)
5778                 return;
5779 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5780         /*
5781          * Note: If supplicant interface's driver is wired then skip it,
5782          * because it meanti only for ethernet not Wi-Fi.
5783          */
5784         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5785                 return;
5786 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5787
5788
5789         wifi = g_supplicant_interface_get_data(interface);
5790         if (!wifi)
5791                 return;
5792
5793         /* P2P networks must not be treated as WiFi networks */
5794         if (wifi->p2p_connecting || wifi->p2p_device)
5795                 return;
5796
5797         identifier = g_supplicant_network_get_identifier(network);
5798
5799         connman_network = connman_device_get_network(wifi->device, identifier);
5800         if (!connman_network)
5801                 return;
5802
5803         if (wifi->network) {
5804                 if (wifi->network == connman_network)
5805                         return;
5806 #if TIZEN_EXT
5807                 unsigned int ssid_len;
5808                 DBG("network1 ssid[%s] , OWE[%d],ssid[%s]",
5809                         (char *)connman_network_get_blob(wifi->network,"WiFi.SSID", &ssid_len),
5810                         connman_network_get_bool(wifi->network,"WiFi.TRANSITION_MODE"),
5811                         (char *)connman_network_get_blob(wifi->network,"WiFi.TRANSITION_MODE_SSID", &ssid_len));
5812
5813                 DBG("network1 ssid[%s], OWE[%d], ssid[%s]",
5814                         (char *)connman_network_get_blob(connman_network,"WiFi.SSID",&ssid_len),
5815                         connman_network_get_bool(connman_network,"WiFi.TRANSITION_MODE"),
5816                         (char *)connman_network_get_blob(connman_network,"WiFi.TRANSITION_MODE_SSID", &ssid_len));
5817                 if (connman_network_check_transition_mode(wifi->network, connman_network)) {//OWE trasition mode check
5818                         DBG("OWE transition mode is TRUE");
5819                         return;
5820                 }
5821 #endif
5822                 /*
5823                  * This should never happen, we got associated with
5824                  * a network different than the one we were expecting.
5825                  */
5826                 DBG("Associated to %p while expecting %p",
5827                                         connman_network, wifi->network);
5828
5829                 connman_network_set_associating(wifi->network, false);
5830         }
5831
5832         DBG("Reconnecting to previous network %p from wpa_s", connman_network);
5833
5834         wifi->network = connman_network_ref(connman_network);
5835         wifi->retries = 0;
5836
5837         /*
5838          * Interface state changes callback (interface_state) is always
5839          * called before network_associated callback thus we need to call
5840          * interface_state again in order to process the new state now that
5841          * we have the network properly set.
5842          */
5843         interface_state(interface);
5844 }
5845
5846 static void sta_authorized(GSupplicantInterface *interface,
5847                                         const char *addr)
5848 {
5849 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5850         /*
5851          * Note: If supplicant interface's driver is wired then skip it,
5852          * because it meanti only for ethernet not Wi-Fi.
5853          */
5854         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5855                 return;
5856 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5857
5858         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5859
5860         DBG("wifi %p station %s authorized", wifi, addr);
5861
5862         if (!wifi || !wifi->tethering)
5863                 return;
5864
5865         __connman_tethering_client_register(addr);
5866 }
5867
5868 static void sta_deauthorized(GSupplicantInterface *interface,
5869                                         const char *addr)
5870 {
5871 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5872         /*
5873          * Note: If supplicant interface's driver is wired then skip it,
5874          * because it meanti only for ethernet not Wi-Fi.
5875          */
5876         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
5877                 return;
5878 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5879
5880         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5881
5882         DBG("wifi %p station %s deauthorized", wifi, addr);
5883
5884         if (!wifi || !wifi->tethering)
5885                 return;
5886
5887         __connman_tethering_client_unregister(addr);
5888 }
5889
5890 static void apply_peer_services(GSupplicantPeer *peer,
5891                                 struct connman_peer *connman_peer)
5892 {
5893         const unsigned char *data;
5894         int length;
5895
5896         DBG("");
5897
5898         connman_peer_reset_services(connman_peer);
5899
5900         data = g_supplicant_peer_get_widi_ies(peer, &length);
5901         if (data) {
5902                 connman_peer_add_service(connman_peer,
5903                         CONNMAN_PEER_SERVICE_WIFI_DISPLAY, data, length);
5904         }
5905 }
5906
5907 static void peer_found(GSupplicantPeer *peer)
5908 {
5909         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
5910         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
5911         struct connman_peer *connman_peer;
5912         const char *identifier, *name;
5913         int ret;
5914
5915 #if defined TIZEN_EXT
5916         if (!wifi)
5917                 return;
5918 #endif
5919         identifier = g_supplicant_peer_get_identifier(peer);
5920         name = g_supplicant_peer_get_name(peer);
5921
5922         DBG("ident: %s", identifier);
5923
5924         connman_peer = connman_peer_get(wifi->device, identifier);
5925         if (connman_peer)
5926                 return;
5927
5928         connman_peer = connman_peer_create(identifier);
5929         connman_peer_set_name(connman_peer, name);
5930         connman_peer_set_device(connman_peer, wifi->device);
5931         apply_peer_services(peer, connman_peer);
5932
5933         ret = connman_peer_register(connman_peer);
5934         if (ret < 0 && ret != -EALREADY)
5935                 connman_peer_unref(connman_peer);
5936         else
5937                 wifi->peers = g_slist_prepend(wifi->peers, connman_peer);
5938 }
5939
5940 static void peer_lost(GSupplicantPeer *peer)
5941 {
5942         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
5943         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
5944         struct connman_peer *connman_peer;
5945         const char *identifier;
5946
5947         if (!wifi)
5948                 return;
5949
5950         identifier = g_supplicant_peer_get_identifier(peer);
5951
5952         DBG("ident: %s", identifier);
5953
5954         connman_peer = connman_peer_get(wifi->device, identifier);
5955         if (connman_peer) {
5956                 if (wifi->p2p_connecting &&
5957                                 wifi->pending_peer == connman_peer) {
5958                         peer_connect_timeout(wifi);
5959                 }
5960                 connman_peer_unregister(connman_peer);
5961                 connman_peer_unref(connman_peer);
5962         }
5963
5964         wifi->peers = g_slist_remove(wifi->peers, connman_peer);
5965 }
5966
5967 static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state)
5968 {
5969         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
5970         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
5971         enum connman_peer_state p_state = CONNMAN_PEER_STATE_UNKNOWN;
5972         struct connman_peer *connman_peer;
5973         const char *identifier;
5974
5975         identifier = g_supplicant_peer_get_identifier(peer);
5976
5977         DBG("ident: %s", identifier);
5978
5979         if (!wifi)
5980                 return;
5981
5982         connman_peer = connman_peer_get(wifi->device, identifier);
5983         if (!connman_peer)
5984                 return;
5985
5986         switch (state) {
5987         case G_SUPPLICANT_PEER_SERVICES_CHANGED:
5988                 apply_peer_services(peer, connman_peer);
5989                 connman_peer_services_changed(connman_peer);
5990                 return;
5991         case G_SUPPLICANT_PEER_GROUP_CHANGED:
5992                 if (!g_supplicant_peer_is_in_a_group(peer))
5993                         p_state = CONNMAN_PEER_STATE_IDLE;
5994                 else
5995                         p_state = CONNMAN_PEER_STATE_CONFIGURATION;
5996                 break;
5997         case G_SUPPLICANT_PEER_GROUP_STARTED:
5998                 break;
5999         case G_SUPPLICANT_PEER_GROUP_FINISHED:
6000                 p_state = CONNMAN_PEER_STATE_IDLE;
6001                 break;
6002         case G_SUPPLICANT_PEER_GROUP_JOINED:
6003                 connman_peer_set_iface_address(connman_peer,
6004                                 g_supplicant_peer_get_iface_address(peer));
6005                 break;
6006         case G_SUPPLICANT_PEER_GROUP_DISCONNECTED:
6007                 p_state = CONNMAN_PEER_STATE_IDLE;
6008                 break;
6009         case G_SUPPLICANT_PEER_GROUP_FAILED:
6010                 if (g_supplicant_peer_has_requested_connection(peer))
6011                         p_state = CONNMAN_PEER_STATE_IDLE;
6012                 else
6013                         p_state = CONNMAN_PEER_STATE_FAILURE;
6014                 break;
6015         }
6016
6017         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION ||
6018                                         p_state == CONNMAN_PEER_STATE_FAILURE) {
6019                 if (wifi->p2p_connecting
6020                                 && connman_peer == wifi->pending_peer)
6021                         peer_cancel_timeout(wifi);
6022                 else
6023                         p_state = CONNMAN_PEER_STATE_UNKNOWN;
6024         }
6025
6026         if (p_state == CONNMAN_PEER_STATE_UNKNOWN)
6027                 return;
6028
6029         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION) {
6030                 GSupplicantInterface *g_iface;
6031                 struct wifi_data *g_wifi;
6032
6033                 g_iface = g_supplicant_peer_get_group_interface(peer);
6034                 if (!g_iface)
6035                         return;
6036
6037                 g_wifi = g_supplicant_interface_get_data(g_iface);
6038                 if (!g_wifi)
6039                         return;
6040
6041                 connman_peer_set_as_master(connman_peer,
6042                                         !g_supplicant_peer_is_client(peer));
6043                 connman_peer_set_sub_device(connman_peer, g_wifi->device);
6044
6045                 /*
6046                  * If wpa_supplicant didn't create a dedicated p2p-group
6047                  * interface then mark this interface as p2p_device to avoid
6048                  * scan and auto-scan are launched on it while P2P is connected.
6049                  */
6050                 if (!g_list_find(p2p_iface_list, g_wifi))
6051                         wifi->p2p_device = true;
6052         }
6053
6054         connman_peer_set_state(connman_peer, p_state);
6055 }
6056
6057 static void peer_request(GSupplicantPeer *peer)
6058 {
6059         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
6060         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
6061         struct connman_peer *connman_peer;
6062         const char *identifier;
6063
6064 #if defined TIZEN_EXT
6065         if (!wifi)
6066                 return;
6067 #endif
6068
6069         identifier = g_supplicant_peer_get_identifier(peer);
6070
6071         DBG("ident: %s", identifier);
6072
6073         connman_peer = connman_peer_get(wifi->device, identifier);
6074         if (!connman_peer)
6075                 return;
6076
6077         connman_peer_request_connection(connman_peer);
6078 }
6079
6080 #if defined TIZEN_EXT
6081 static void system_power_off(void)
6082 {
6083         GList *list;
6084         struct wifi_data *wifi;
6085         struct connman_service *service;
6086         struct connman_ipconfig *ipconfig_ipv4;
6087
6088         if (connman_setting_get_bool("WiFiDHCPRelease") == true) {
6089                 for (list = iface_list; list; list = list->next) {
6090                         wifi = list->data;
6091
6092                         if (wifi->network != NULL) {
6093                                 service = connman_service_lookup_from_network(wifi->network);
6094                                 ipconfig_ipv4 = __connman_service_get_ip4config(service);
6095                                 __connman_dhcp_stop(ipconfig_ipv4);
6096                         }
6097                 }
6098         }
6099 }
6100
6101 static void network_merged(GSupplicantNetwork *network)
6102 {
6103         GSupplicantInterface *interface;
6104         GSupplicantState state;
6105         struct wifi_data *wifi;
6106         const char *identifier;
6107         struct connman_network *connman_network;
6108         bool ishs20AP = 0;
6109         char *temp = NULL;
6110
6111         interface = g_supplicant_network_get_interface(network);
6112         if (!interface)
6113                 return;
6114
6115 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
6116         /*
6117          * Note: If supplicant interface's driver is wired then skip it,
6118          * because it meanti only for ethernet not Wi-Fi.
6119          */
6120         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
6121                 return;
6122 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
6123
6124         state = g_supplicant_interface_get_state(interface);
6125         if (state < G_SUPPLICANT_STATE_AUTHENTICATING)
6126                 return;
6127
6128         wifi = g_supplicant_interface_get_data(interface);
6129         if (!wifi)
6130                 return;
6131
6132         identifier = g_supplicant_network_get_identifier(network);
6133
6134         connman_network = connman_device_get_network(wifi->device, identifier);
6135         if (!connman_network)
6136                 return;
6137
6138         DBG("merged identifier %s", identifier);
6139
6140         if (wifi->connected == FALSE) {
6141                 switch (state) {
6142                 case G_SUPPLICANT_STATE_AUTHENTICATING:
6143                 case G_SUPPLICANT_STATE_ASSOCIATING:
6144                 case G_SUPPLICANT_STATE_ASSOCIATED:
6145                 case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
6146                 case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
6147                         connman_network_set_associating(connman_network, TRUE);
6148                         break;
6149                 case G_SUPPLICANT_STATE_COMPLETED:
6150                         connman_network_set_connected(connman_network, TRUE);
6151                         break;
6152                 default:
6153                         DBG("Not handled the state : %d", state);
6154                         break;
6155                 }
6156         }
6157
6158         ishs20AP = g_supplicant_network_is_hs20AP(network);
6159
6160         if (ishs20AP &&
6161                 g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) {
6162                 temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1);
6163                 connman_network_set_string(connman_network, "WiFi.EAP",
6164                                 temp);
6165                 connman_network_set_string(connman_network, "WiFi.Identity",
6166                                 g_supplicant_network_get_identity(network));
6167                 connman_network_set_string(connman_network, "WiFi.Phase2",
6168                                 g_supplicant_network_get_phase2(network));
6169
6170                 g_free(temp);
6171         }
6172
6173         wifi->network = connman_network;
6174 }
6175
6176 static void assoc_failed(void *user_data)
6177 {
6178         struct connman_network *network = user_data;
6179         connman_network_set_associating(network, false);
6180 }
6181
6182 static void scan_done(GSupplicantInterface *interface)
6183 {
6184 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
6185         /*
6186          * Note: If supplicant interface's driver is wired then skip it,
6187          * because it meanti only for ethernet not Wi-Fi.
6188          */
6189         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
6190                 return;
6191 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
6192
6193         GList *list;
6194         int scan_type = CONNMAN_SCAN_TYPE_WPA_SUPPLICANT;
6195         struct wifi_data *wifi;
6196         bool scanning;
6197
6198         for (list = iface_list; list; list = list->next) {
6199                 wifi = list->data;
6200
6201                 if (interface == wifi->interface) {
6202                         scanning = connman_device_get_scanning(wifi->device,
6203                                         CONNMAN_SERVICE_TYPE_WIFI);
6204                         if (!scanning)
6205                                 __connman_technology_notify_scan_done(
6206                                                 connman_device_get_string(wifi->device, "Interface"), scan_type);
6207                         break;
6208                 }
6209         }
6210 }
6211 #endif
6212
6213 static void debug(const char *str)
6214 {
6215 #if defined TIZEN_EXT
6216         if (connman_setting_get_bool("ConnmanSupplicantDebug"))
6217 #else
6218         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
6219 #endif
6220                 connman_debug("%s", str);
6221 }
6222
6223 static void disconnect_reasoncode(GSupplicantInterface *interface,
6224                                 int reasoncode)
6225 {
6226 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
6227         /*
6228          * Note: If supplicant interface's driver is wired then skip it,
6229          * because it meanti only for ethernet not Wi-Fi.
6230          */
6231         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
6232                 return;
6233 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
6234
6235         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
6236
6237         if (wifi != NULL) {
6238                 wifi->disconnect_code = reasoncode;
6239         }
6240 }
6241
6242 static void assoc_status_code(GSupplicantInterface *interface, int status_code)
6243 {
6244 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
6245         /*
6246          * Note: If supplicant interface's driver is wired then skip it,
6247          * because it meanti only for ethernet not Wi-Fi.
6248          */
6249         if (!g_strcmp0("wired", g_supplicant_interface_get_driver(interface)))
6250                 return;
6251 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
6252
6253         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
6254
6255         if (wifi != NULL) {
6256                 wifi->assoc_code = status_code;
6257         }
6258 }
6259
6260 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
6261 static GSupplicantCallbacks callbacks = {
6262 #else /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
6263 static const GSupplicantCallbacks callbacks = {
6264 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
6265         .system_ready           = system_ready,
6266         .system_killed          = system_killed,
6267         .interface_added        = interface_added,
6268         .interface_state        = interface_state,
6269         .interface_removed      = interface_removed,
6270         .p2p_support            = p2p_support,
6271         .scan_started           = scan_started,
6272         .scan_finished          = scan_finished,
6273         .ap_create_fail         = ap_create_fail,
6274         .network_added          = network_added,
6275         .network_removed        = network_removed,
6276         .network_changed        = network_changed,
6277         .network_associated     = network_associated,
6278         .sta_authorized         = sta_authorized,
6279         .sta_deauthorized       = sta_deauthorized,
6280         .peer_found             = peer_found,
6281         .peer_lost              = peer_lost,
6282         .peer_changed           = peer_changed,
6283         .peer_request           = peer_request,
6284 #if defined TIZEN_EXT
6285         .system_power_off       = system_power_off,
6286         .network_merged         = network_merged,
6287         .assoc_failed           = assoc_failed,
6288         .scan_done              = scan_done,
6289 #endif
6290         .debug                  = debug,
6291         .disconnect_reasoncode  = disconnect_reasoncode,
6292         .assoc_status_code      = assoc_status_code,
6293 #if defined TIZEN_EXT_WIFI_MESH
6294         .mesh_support           = mesh_support,
6295         .mesh_group_started = mesh_group_started,
6296         .mesh_group_removed = mesh_group_removed,
6297         .mesh_peer_connected = mesh_peer_connected,
6298         .mesh_peer_disconnected = mesh_peer_disconnected,
6299 #endif
6300 };
6301
6302
6303 static int tech_probe(struct connman_technology *technology)
6304 {
6305         wifi_technology = technology;
6306
6307         return 0;
6308 }
6309
6310 static void tech_remove(struct connman_technology *technology)
6311 {
6312         wifi_technology = NULL;
6313 }
6314
6315 static GSupplicantSSID *ssid_ap_init(const char *ssid, const char *passphrase)
6316 {
6317         GSupplicantSSID *ap;
6318
6319         ap = g_try_malloc0(sizeof(GSupplicantSSID));
6320         if (!ap)
6321                 return NULL;
6322
6323         ap->mode = G_SUPPLICANT_MODE_MASTER;
6324 #if defined TIZEN_EXT
6325         ap->ssid = (void *) ssid;
6326 #else
6327         ap->ssid = ssid;
6328 #endif
6329         ap->ssid_len = strlen(ssid);
6330         ap->scan_ssid = 0;
6331         ap->freq = 2412;
6332
6333         if (!passphrase || strlen(passphrase) == 0) {
6334                 ap->security = G_SUPPLICANT_SECURITY_NONE;
6335                 ap->passphrase = NULL;
6336         } else {
6337                ap->security = G_SUPPLICANT_SECURITY_PSK;
6338                ap->protocol = G_SUPPLICANT_PROTO_RSN;
6339                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
6340                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
6341                ap->passphrase = passphrase;
6342         }
6343
6344         return ap;
6345 }
6346
6347 static void ap_start_callback(int result, GSupplicantInterface *interface,
6348                                                         void *user_data)
6349 {
6350         struct wifi_tethering_info *info = user_data;
6351
6352         DBG("result %d index %d bridge %s",
6353                 result, info->wifi->index, info->wifi->bridge);
6354
6355         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
6356                 connman_inet_remove_from_bridge(info->wifi->index,
6357                                                         info->wifi->bridge);
6358
6359                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
6360                         connman_technology_tethering_notify(info->technology, false);
6361                         g_free(info->wifi->tethering_param->ssid);
6362                         g_free(info->wifi->tethering_param);
6363                         info->wifi->tethering_param = NULL;
6364                 }
6365         }
6366
6367         g_free(info->ifname);
6368         g_free(info);
6369 }
6370
6371 static void ap_create_callback(int result,
6372                                 GSupplicantInterface *interface,
6373                                         void *user_data)
6374 {
6375         struct wifi_tethering_info *info = user_data;
6376
6377         DBG("result %d ifname %s", result,
6378                                 g_supplicant_interface_get_ifname(interface));
6379
6380         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
6381                 connman_inet_remove_from_bridge(info->wifi->index,
6382                                                         info->wifi->bridge);
6383
6384                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
6385                         connman_technology_tethering_notify(info->technology, false);
6386                         g_free(info->wifi->tethering_param->ssid);
6387                         g_free(info->wifi->tethering_param);
6388                         info->wifi->tethering_param = NULL;
6389
6390                 }
6391
6392                 g_free(info->ifname);
6393                 g_free(info->ssid);
6394                 g_free(info);
6395                 return;
6396         }
6397
6398         info->wifi->interface = interface;
6399         g_supplicant_interface_set_data(interface, info->wifi);
6400
6401         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
6402                 connman_error("Failed to set interface ap_scan property");
6403
6404         g_supplicant_interface_connect(interface, info->ssid,
6405                                                 ap_start_callback, info);
6406 }
6407
6408 static void sta_remove_callback(int result,
6409                                 GSupplicantInterface *interface,
6410                                         void *user_data)
6411 {
6412         struct wifi_tethering_info *info = user_data;
6413         const char *driver = connman_setting_get_string("wifi");
6414
6415         DBG("ifname %s result %d ", info->ifname, result);
6416
6417         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
6418                 info->wifi->tethering = false;
6419                 connman_technology_tethering_notify(info->technology, false);
6420
6421                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
6422                         g_free(info->wifi->tethering_param->ssid);
6423                         g_free(info->wifi->tethering_param);
6424                         info->wifi->tethering_param = NULL;
6425                 }
6426
6427                 g_free(info->ifname);
6428                 g_free(info->ssid);
6429                 g_free(info);
6430                 return;
6431         }
6432
6433         info->wifi->interface = NULL;
6434
6435         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
6436 #ifdef TIZEN_EXT
6437                         0, 0, 60,
6438 #endif /* TIZEN_EXT */
6439                                                 ap_create_callback,
6440                                                         info);
6441 }
6442
6443 static int enable_wifi_tethering(struct connman_technology *technology,
6444                                 const char *bridge, const char *identifier,
6445                                 const char *passphrase, bool available)
6446 {
6447         GList *list;
6448         GSupplicantInterface *interface;
6449         struct wifi_data *wifi;
6450         struct wifi_tethering_info *info;
6451         const char *ifname;
6452         unsigned int mode;
6453         int err, berr = 0;
6454
6455         for (list = iface_list; list; list = list->next) {
6456                 wifi = list->data;
6457
6458                 DBG("wifi %p network %p pending_network %p", wifi,
6459                         wifi->network, wifi->pending_network);
6460
6461                 interface = wifi->interface;
6462
6463                 if (!interface)
6464                         continue;
6465
6466                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
6467                 if (!ifname)
6468                         continue;
6469
6470                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED) {
6471                         DBG("%s does not support AP mode (detected)", ifname);
6472                         continue;
6473                 }
6474
6475                 mode = g_supplicant_interface_get_mode(interface);
6476                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
6477                         wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
6478                         DBG("%s does not support AP mode (capability)", ifname);
6479                         continue;
6480                 }
6481
6482                 if (wifi->network && available)
6483                         continue;
6484
6485                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
6486                 if (!info)
6487                         return -ENOMEM;
6488
6489                 wifi->tethering_param = g_try_malloc0(sizeof(struct wifi_tethering_info));
6490                 if (!wifi->tethering_param) {
6491                         g_free(info);
6492                         return -ENOMEM;
6493                 }
6494
6495                 info->wifi = wifi;
6496                 info->technology = technology;
6497                 info->wifi->bridge = bridge;
6498                 info->ssid = ssid_ap_init(identifier, passphrase);
6499                 if (!info->ssid)
6500                         goto failed;
6501
6502                 info->ifname = g_strdup(ifname);
6503
6504                 wifi->tethering_param->technology = technology;
6505                 wifi->tethering_param->ssid = ssid_ap_init(identifier, passphrase);
6506                 if (!wifi->tethering_param->ssid)
6507                         goto failed;
6508
6509                 info->wifi->tethering = true;
6510                 info->wifi->ap_supported = WIFI_AP_SUPPORTED;
6511
6512                 berr = connman_technology_tethering_notify(technology, true);
6513                 if (berr < 0)
6514                         goto failed;
6515
6516                 err = g_supplicant_interface_remove(interface,
6517                                                 sta_remove_callback,
6518                                                         info);
6519                 if (err >= 0) {
6520                         DBG("tethering wifi %p ifname %s", wifi, ifname);
6521                         return 0;
6522                 }
6523
6524         failed:
6525                 g_free(info->ifname);
6526                 g_free(info->ssid);
6527                 g_free(info);
6528                 g_free(wifi->tethering_param);
6529                 wifi->tethering_param = NULL;
6530
6531                 /*
6532                  * Remove bridge if it was correctly created but remove
6533                  * operation failed. Instead, if bridge creation failed then
6534                  * break out and do not try again on another interface,
6535                  * bridge set-up does not depend on it.
6536                  */
6537                 if (berr == 0)
6538                         connman_technology_tethering_notify(technology, false);
6539                 else
6540                         break;
6541         }
6542
6543         return -EOPNOTSUPP;
6544 }
6545
6546 static int tech_set_tethering(struct connman_technology *technology,
6547                                 const char *identifier, const char *passphrase,
6548                                 const char *bridge, bool enabled)
6549 {
6550         GList *list;
6551         struct wifi_data *wifi;
6552         int err;
6553
6554         DBG("");
6555
6556         if (!enabled) {
6557                 for (list = iface_list; list; list = list->next) {
6558                         wifi = list->data;
6559
6560                         if (wifi->tethering) {
6561                                 wifi->tethering = false;
6562
6563                                 connman_inet_remove_from_bridge(wifi->index,
6564                                                                         bridge);
6565                                 wifi->bridged = false;
6566                         }
6567                 }
6568
6569                 connman_technology_tethering_notify(technology, false);
6570
6571                 return 0;
6572         }
6573
6574         DBG("trying tethering for available devices");
6575         err = enable_wifi_tethering(technology, bridge, identifier, passphrase,
6576                                 true);
6577
6578         if (err < 0) {
6579                 DBG("trying tethering for any device");
6580                 err = enable_wifi_tethering(technology, bridge, identifier,
6581                                         passphrase, false);
6582         }
6583
6584         return err;
6585 }
6586
6587 static void regdom_callback(int result, const char *alpha2, void *user_data)
6588 {
6589         DBG("");
6590
6591         if (!wifi_technology)
6592                 return;
6593
6594         if (result != 0)
6595                 alpha2 = NULL;
6596
6597         connman_technology_regdom_notify(wifi_technology, alpha2);
6598 }
6599
6600 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
6601 {
6602         return g_supplicant_set_country(alpha2, regdom_callback, NULL);
6603 }
6604
6605 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
6606 static void supp_ins_init(void)
6607 {
6608         const char *string;
6609         GSupplicantINSPreferredFreq preferred_freq;
6610
6611         string = connman_setting_get_string("INSPreferredFreqBSSID");
6612         if (g_strcmp0(string, "5GHz") == 0)
6613                 preferred_freq = G_SUPPLICANT_INS_PREFERRED_FREQ_5GHZ;
6614         else if (g_strcmp0(string, "2.4GHz") == 0)
6615                 preferred_freq = G_SUPPLICANT_INS_PREFERRED_FREQ_24GHZ;
6616         else
6617                 preferred_freq = G_SUPPLICANT_INS_PREFERRED_FREQ_UNKNOWN;
6618
6619         g_supplicant_set_ins_settings(preferred_freq,
6620                 connman_setting_get_bool("INSLastConnectedBSSID"),
6621                 connman_setting_get_bool("INSAssocReject"),
6622                 connman_setting_get_bool("INSSignalBSSID"),
6623                 connman_setting_get_uint("INSPreferredFreqBSSIDScore"),
6624                 connman_setting_get_uint("INSLastConnectedBSSIDScore"),
6625                 connman_setting_get_uint("INSAssocRejectScore"),
6626                 connman_setting_get_int("INSSignalLevel3_5GHz"),
6627                 connman_setting_get_int("INSSignalLevel3_24GHz")
6628         );
6629 }
6630 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
6631
6632 static struct connman_technology_driver tech_driver = {
6633         .name           = "wifi",
6634         .type           = CONNMAN_SERVICE_TYPE_WIFI,
6635         .probe          = tech_probe,
6636         .remove         = tech_remove,
6637         .set_tethering  = tech_set_tethering,
6638         .set_regdom     = tech_set_regdom,
6639 };
6640
6641 static int wifi_init(void)
6642 {
6643         int err;
6644
6645         err = connman_network_driver_register(&network_driver);
6646         if (err < 0)
6647                 return err;
6648
6649         err = g_supplicant_register(&callbacks);
6650         if (err < 0) {
6651                 connman_network_driver_unregister(&network_driver);
6652                 return err;
6653         }
6654
6655         err = connman_technology_driver_register(&tech_driver);
6656         if (err < 0) {
6657                 g_supplicant_unregister(&callbacks);
6658                 connman_network_driver_unregister(&network_driver);
6659                 return err;
6660         }
6661
6662 #if defined TIZEN_EXT
6663         failed_bssids = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
6664 #endif
6665
6666 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
6667         supp_ins_init();
6668 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
6669         return 0;
6670 }
6671
6672 static void wifi_exit(void)
6673 {
6674         DBG();
6675
6676         connman_technology_driver_unregister(&tech_driver);
6677
6678         g_supplicant_unregister(&callbacks);
6679
6680         connman_network_driver_unregister(&network_driver);
6681
6682 #if defined TIZEN_EXT
6683         g_hash_table_unref(failed_bssids);
6684 #endif
6685 }
6686
6687 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
6688                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)