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