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