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