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