Fix to handle scan events initiated by wpa_supplicant
[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 defined TIZEN_EXT
2273         if (!autoscan)
2274                 return FALSE;
2275 #endif
2276
2277         if (autoscan->interval <= 0) {
2278                 interval = autoscan->base;
2279                 goto set_interval;
2280         } else
2281                 interval = autoscan->interval * autoscan->base;
2282
2283 #if defined TIZEN_EXT
2284         if (autoscan->interval >= autoscan->limit)
2285 #else
2286         if (interval > autoscan->limit)
2287 #endif
2288                 interval = autoscan->limit;
2289
2290         throw_wifi_scan(wifi->device, scan_callback_hidden);
2291
2292         /*
2293          * In case BackgroundScanning is disabled, interval will reach the
2294          * limit exactly after the very first passive scanning. It allows
2295          * to ensure at most one passive scan is performed in such cases.
2296          */
2297         if (!connman_setting_get_bool("BackgroundScanning") &&
2298                                         interval == autoscan->limit) {
2299                 g_source_remove(autoscan->timeout);
2300                 autoscan->timeout = 0;
2301
2302                 connman_device_unref(device);
2303
2304                 return FALSE;
2305         }
2306
2307 set_interval:
2308         DBG("interval %d", interval);
2309
2310         autoscan->interval = interval;
2311
2312         autoscan->timeout = g_timeout_add_seconds(interval,
2313                                                 autoscan_timeout, device);
2314
2315         return FALSE;
2316 }
2317
2318 static void start_autoscan(struct connman_device *device)
2319 {
2320         struct wifi_data *wifi = connman_device_get_data(device);
2321         struct autoscan_params *autoscan;
2322
2323         DBG("");
2324
2325         if (!wifi)
2326                 return;
2327
2328         if (wifi->p2p_device)
2329                 return;
2330
2331         if (wifi->connected)
2332                 return;
2333
2334         autoscan = wifi->autoscan;
2335         if (!autoscan)
2336                 return;
2337
2338         if (autoscan->timeout > 0 || autoscan->interval > 0)
2339                 return;
2340
2341         connman_device_ref(device);
2342
2343         autoscan_timeout(device);
2344 }
2345
2346 static struct autoscan_params *parse_autoscan_params(const char *params)
2347 {
2348         struct autoscan_params *autoscan;
2349         char **list_params;
2350         int limit;
2351         int base;
2352
2353         DBG("");
2354
2355         list_params = g_strsplit(params, ":", 0);
2356         if (list_params == 0)
2357                 return NULL;
2358
2359         if (!g_strcmp0(list_params[0], "exponential") &&
2360                                 g_strv_length(list_params) == 3) {
2361                 base = atoi(list_params[1]);
2362                 limit = atoi(list_params[2]);
2363         } else if (!g_strcmp0(list_params[0], "single") &&
2364                                 g_strv_length(list_params) == 2)
2365                 base = limit = atoi(list_params[1]);
2366         else {
2367                 g_strfreev(list_params);
2368                 return NULL;
2369         }
2370
2371         DBG("Setup %s autoscanning", list_params[0]);
2372
2373         g_strfreev(list_params);
2374
2375         autoscan = g_try_malloc0(sizeof(struct autoscan_params));
2376         if (!autoscan) {
2377                 DBG("Could not allocate memory for autoscan");
2378                 return NULL;
2379         }
2380
2381         DBG("base %d - limit %d", base, limit);
2382         autoscan->base = base;
2383         autoscan->limit = limit;
2384
2385         return autoscan;
2386 }
2387
2388 static void setup_autoscan(struct wifi_data *wifi)
2389 {
2390         /*
2391          * If BackgroundScanning is enabled, setup exponential
2392          * autoscanning if it has not been previously done.
2393          */
2394         if (connman_setting_get_bool("BackgroundScanning")) {
2395                 wifi->autoscan = parse_autoscan_params(AUTOSCAN_EXPONENTIAL);
2396                 return;
2397         }
2398
2399         /*
2400          * On the contrary, if BackgroundScanning is disabled, update autoscan
2401          * parameters based on the type of scanning that is being performed.
2402          */
2403         if (wifi->autoscan) {
2404                 g_free(wifi->autoscan);
2405                 wifi->autoscan = NULL;
2406         }
2407
2408         switch (wifi->scanning_type) {
2409         case WIFI_SCANNING_PASSIVE:
2410                 /* Do not setup autoscan. */
2411                 break;
2412         case WIFI_SCANNING_ACTIVE:
2413                 /* Setup one single passive scan after active. */
2414                 wifi->autoscan = parse_autoscan_params(AUTOSCAN_SINGLE);
2415                 break;
2416         case WIFI_SCANNING_UNKNOWN:
2417                 /* Setup autoscan in this case but we should never fall here. */
2418                 wifi->autoscan = parse_autoscan_params(AUTOSCAN_SINGLE);
2419                 break;
2420         }
2421 }
2422
2423 static void finalize_interface_creation(struct wifi_data *wifi)
2424 {
2425         DBG("interface is ready wifi %p tethering %d", wifi, wifi->tethering);
2426
2427         if (!wifi->device) {
2428                 connman_error("WiFi device not set");
2429                 return;
2430         }
2431
2432         connman_device_set_powered(wifi->device, true);
2433
2434         if (wifi->p2p_device)
2435                 return;
2436
2437         if (!wifi->autoscan)
2438                 setup_autoscan(wifi);
2439
2440         start_autoscan(wifi->device);
2441 }
2442
2443 static void interface_create_callback(int result,
2444                                         GSupplicantInterface *interface,
2445                                                         void *user_data)
2446 {
2447         struct wifi_data *wifi = user_data;
2448
2449         DBG("result %d ifname %s, wifi %p", result,
2450                                 g_supplicant_interface_get_ifname(interface),
2451                                 wifi);
2452
2453         if (result < 0 || !wifi)
2454                 return;
2455
2456         wifi->interface = interface;
2457         g_supplicant_interface_set_data(interface, wifi);
2458
2459         if (g_supplicant_interface_get_ready(interface)) {
2460                 wifi->interface_ready = true;
2461                 finalize_interface_creation(wifi);
2462         }
2463 }
2464
2465 static int wifi_enable(struct connman_device *device)
2466 {
2467         struct wifi_data *wifi = connman_device_get_data(device);
2468         int index;
2469         char *interface;
2470         const char *driver = connman_option_get_string("wifi");
2471         int ret;
2472
2473         DBG("device %p %p", device, wifi);
2474
2475         index = connman_device_get_index(device);
2476         if (!wifi || index < 0)
2477                 return -ENODEV;
2478
2479         if (is_p2p_connecting())
2480                 return -EINPROGRESS;
2481
2482         interface = connman_inet_ifname(index);
2483         ret = g_supplicant_interface_create(interface, driver, NULL,
2484                                                 interface_create_callback,
2485                                                         wifi);
2486         g_free(interface);
2487
2488         if (ret < 0)
2489                 return ret;
2490
2491         return -EINPROGRESS;
2492 }
2493
2494 static int wifi_disable(struct connman_device *device)
2495 {
2496         struct wifi_data *wifi = connman_device_get_data(device);
2497         int ret;
2498
2499         DBG("device %p wifi %p", device, wifi);
2500
2501         if (!wifi)
2502                 return -ENODEV;
2503
2504         wifi->connected = false;
2505         wifi->disconnecting = false;
2506
2507         if (wifi->pending_network)
2508                 wifi->pending_network = NULL;
2509
2510 #if !defined TIZEN_EXT
2511         stop_autoscan(device);
2512 #endif
2513
2514         if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_P2P)) {
2515                 g_source_remove(wifi->p2p_find_timeout);
2516                 wifi->p2p_find_timeout = 0;
2517                 connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_P2P, false);
2518                 connman_device_unref(wifi->device);
2519         }
2520
2521 #if defined TIZEN_EXT
2522         if (wifi->automaxspeed_timeout != 0) {
2523                 g_source_remove(wifi->automaxspeed_timeout);
2524                 wifi->automaxspeed_timeout = 0;
2525         }
2526 #endif
2527
2528         /* In case of a user scan, device is still referenced */
2529         if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI)) {
2530                 connman_device_set_scanning(device,
2531                                 CONNMAN_SERVICE_TYPE_WIFI, false);
2532                 connman_device_unref(wifi->device);
2533         }
2534
2535 #if defined TIZEN_EXT
2536         stop_autoscan(device);
2537 #endif
2538
2539         remove_networks(device, wifi);
2540         remove_peers(wifi);
2541
2542 #if defined TIZEN_EXT
2543         wifi->scan_pending_network = NULL;
2544
2545         if (is_wifi_notifier_registered == true) {
2546                 connman_notifier_unregister(&notifier);
2547                 is_wifi_notifier_registered = false;
2548         }
2549 #endif
2550
2551         ret = g_supplicant_interface_remove(wifi->interface, NULL, NULL);
2552         if (ret < 0)
2553                 return ret;
2554
2555         return -EINPROGRESS;
2556 }
2557
2558 static int get_latest_connections(int max_ssids,
2559                                 GSupplicantScanParams *scan_data)
2560 {
2561         GSequenceIter *iter;
2562         GSequence *latest_list;
2563         struct last_connected *entry;
2564         GKeyFile *keyfile;
2565         GTimeVal modified;
2566         gchar **services;
2567         gchar *str;
2568         char *ssid;
2569         int i, freq;
2570         int num_ssids = 0;
2571
2572         latest_list = g_sequence_new(free_entry);
2573         if (!latest_list)
2574                 return -ENOMEM;
2575
2576         services = connman_storage_get_services();
2577         for (i = 0; services && services[i]; i++) {
2578                 if (strncmp(services[i], "wifi_", 5) != 0)
2579                         continue;
2580
2581                 keyfile = connman_storage_load_service(services[i]);
2582                 if (!keyfile)
2583                         continue;
2584
2585                 str = g_key_file_get_string(keyfile,
2586                                         services[i], "Favorite", NULL);
2587                 if (!str || g_strcmp0(str, "true")) {
2588                         g_free(str);
2589                         g_key_file_free(keyfile);
2590                         continue;
2591                 }
2592                 g_free(str);
2593
2594                 str = g_key_file_get_string(keyfile,
2595                                         services[i], "AutoConnect", NULL);
2596                 if (!str || g_strcmp0(str, "true")) {
2597                         g_free(str);
2598                         g_key_file_free(keyfile);
2599                         continue;
2600                 }
2601                 g_free(str);
2602
2603                 str = g_key_file_get_string(keyfile,
2604                                         services[i], "Modified", NULL);
2605                 if (!str) {
2606                         g_key_file_free(keyfile);
2607                         continue;
2608                 }
2609                 g_time_val_from_iso8601(str, &modified);
2610                 g_free(str);
2611
2612                 ssid = g_key_file_get_string(keyfile,
2613                                         services[i], "SSID", NULL);
2614
2615                 freq = g_key_file_get_integer(keyfile, services[i],
2616                                         "Frequency", NULL);
2617                 if (freq) {
2618                         entry = g_try_new(struct last_connected, 1);
2619                         if (!entry) {
2620                                 g_sequence_free(latest_list);
2621                                 g_key_file_free(keyfile);
2622                                 g_free(ssid);
2623                                 return -ENOMEM;
2624                         }
2625
2626                         entry->ssid = ssid;
2627                         entry->modified = modified;
2628                         entry->freq = freq;
2629
2630                         g_sequence_insert_sorted(latest_list, entry,
2631                                                 sort_entry, NULL);
2632                         num_ssids++;
2633                 } else
2634                         g_free(ssid);
2635
2636                 g_key_file_free(keyfile);
2637         }
2638
2639         g_strfreev(services);
2640
2641         num_ssids = num_ssids > max_ssids ? max_ssids : num_ssids;
2642
2643         iter = g_sequence_get_begin_iter(latest_list);
2644
2645         for (i = 0; i < num_ssids; i++) {
2646                 entry = g_sequence_get(iter);
2647
2648                 DBG("ssid %s freq %d modified %lu", entry->ssid, entry->freq,
2649                                                 entry->modified.tv_sec);
2650
2651                 add_scan_param(entry->ssid, NULL, 0, entry->freq, scan_data,
2652                                                 max_ssids, entry->ssid);
2653
2654                 iter = g_sequence_iter_next(iter);
2655         }
2656
2657         g_sequence_free(latest_list);
2658         return num_ssids;
2659 }
2660
2661 static void wifi_update_scanner_type(struct wifi_data *wifi,
2662                                         enum wifi_scanning_type new_type)
2663 {
2664         DBG("");
2665
2666         if (!wifi || wifi->scanning_type == new_type)
2667                 return;
2668
2669         wifi->scanning_type = new_type;
2670
2671         setup_autoscan(wifi);
2672 }
2673
2674 static int wifi_scan_simple(struct connman_device *device)
2675 {
2676         struct wifi_data *wifi = connman_device_get_data(device);
2677
2678         reset_autoscan(device);
2679
2680         /* Distinguish between devices performing passive and active scanning */
2681         if (wifi)
2682                 wifi_update_scanner_type(wifi, WIFI_SCANNING_PASSIVE);
2683
2684         return throw_wifi_scan(device, scan_callback_hidden);
2685 }
2686
2687 static gboolean p2p_find_stop(gpointer data)
2688 {
2689         struct connman_device *device = data;
2690         struct wifi_data *wifi = connman_device_get_data(device);
2691
2692         DBG("");
2693
2694         if (wifi) {
2695                 wifi->p2p_find_timeout = 0;
2696
2697                 g_supplicant_interface_p2p_stop_find(wifi->interface);
2698         }
2699
2700         connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_P2P, false);
2701
2702         connman_device_unref(device);
2703         start_autoscan(device);
2704
2705         return FALSE;
2706 }
2707
2708 static void p2p_find_callback(int result, GSupplicantInterface *interface,
2709                                                         void *user_data)
2710 {
2711         struct connman_device *device = user_data;
2712         struct wifi_data *wifi = connman_device_get_data(device);
2713
2714         DBG("result %d wifi %p", result, wifi);
2715
2716         if (!wifi)
2717                 goto error;
2718
2719         if (wifi->p2p_find_timeout) {
2720                 g_source_remove(wifi->p2p_find_timeout);
2721                 wifi->p2p_find_timeout = 0;
2722         }
2723
2724         if (result)
2725                 goto error;
2726
2727         wifi->p2p_find_timeout = g_timeout_add_seconds(P2P_FIND_TIMEOUT,
2728                                                         p2p_find_stop, device);
2729         if (!wifi->p2p_find_timeout)
2730                 goto error;
2731
2732         return;
2733 error:
2734         p2p_find_stop(device);
2735 }
2736
2737 static int p2p_find(struct connman_device *device)
2738 {
2739         struct wifi_data *wifi;
2740         int ret;
2741
2742         DBG("");
2743
2744         if (!p2p_technology)
2745                 return -ENOTSUP;
2746
2747         wifi = connman_device_get_data(device);
2748
2749         if (g_supplicant_interface_is_p2p_finding(wifi->interface))
2750                 return -EALREADY;
2751
2752         reset_autoscan(device);
2753         connman_device_ref(device);
2754
2755         ret = g_supplicant_interface_p2p_find(wifi->interface,
2756                                                 p2p_find_callback, device);
2757         if (ret) {
2758                 connman_device_unref(device);
2759                 start_autoscan(device);
2760         } else {
2761                 connman_device_set_scanning(device,
2762                                 CONNMAN_SERVICE_TYPE_P2P, true);
2763         }
2764
2765         return ret;
2766 }
2767
2768 #if defined TIZEN_EXT
2769 static void specific_scan_callback(int result, GSupplicantInterface *interface,
2770                                                 void *user_data)
2771 {
2772         struct connman_device *device = user_data;
2773         struct wifi_data *wifi = connman_device_get_data(device);
2774         bool scanning;
2775
2776         DBG("result %d wifi %p", result, wifi);
2777
2778         if (wifi && wifi->scan_params) {
2779                 g_supplicant_free_scan_params(wifi->scan_params);
2780                 wifi->scan_params = NULL;
2781         }
2782
2783         scanning = connman_device_get_scanning(device,
2784                                                CONNMAN_SERVICE_TYPE_WIFI);
2785         if (scanning) {
2786                 connman_device_set_scanning(device,
2787                                 CONNMAN_SERVICE_TYPE_WIFI, false);
2788                 connman_device_unref(device);
2789         }
2790 }
2791
2792 static int wifi_specific_scan(enum connman_service_type type,
2793                         struct connman_device *device, int scan_type,
2794                         GSList *specific_scan_list, void *user_data)
2795 {
2796         GSList *list = NULL;
2797         char *ssid = NULL;
2798         struct wifi_data *wifi = connman_device_get_data(device);
2799         GSupplicantScanParams *scan_params = NULL;
2800         struct scan_ssid *scan_ssid = NULL;
2801         bool scanning;
2802         int ret;
2803         int freq;
2804         int count = 0;
2805
2806         if (!wifi)
2807                 return -ENODEV;
2808
2809         if (wifi->p2p_device)
2810                 return 0;
2811
2812         if (type == CONNMAN_SERVICE_TYPE_P2P)
2813                 return p2p_find(device);
2814
2815         if (wifi->tethering)
2816                 return 0;
2817
2818         scanning =
2819                 connman_device_get_scanning(device,
2820                                             CONNMAN_SERVICE_TYPE_WIFI);
2821         if (scanning)
2822                 return -EALREADY;
2823
2824         DBG("scan_type: %d", scan_type);
2825         if (scan_type == CONNMAN_MULTI_SCAN_SSID) { /* ssid based scan */
2826                 scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
2827                 if (!scan_params) {
2828                         DBG("Failed to allocate memory.");
2829                         return -ENOMEM;
2830                 }
2831
2832                 for (list = specific_scan_list; list; list = list->next) {
2833                         ssid = (char *)list->data;
2834                         int ssid_len = strlen(ssid);
2835
2836                         scan_ssid = g_try_new0(struct scan_ssid, 1);
2837                         if (!scan_ssid) {
2838                                 DBG("Failed to allocate memory.");
2839                                 g_supplicant_free_scan_params(scan_params);
2840                                 return -ENOMEM;
2841                         }
2842
2843                         memcpy(scan_ssid->ssid, ssid, (ssid_len + 1));
2844                         /* DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); */
2845                         scan_ssid->ssid_len = ssid_len;
2846                         scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid);
2847                         count++;
2848                 }
2849                 scan_params->num_ssids = count;
2850
2851         } else if (scan_type == CONNMAN_MULTI_SCAN_FREQ) { /* frequency based scan */
2852
2853                 scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
2854                 if (!scan_params) {
2855                         DBG("Failed to allocate memory.");
2856                         return -ENOMEM;
2857                 }
2858
2859                 guint num_freqs = g_slist_length(specific_scan_list);
2860                 DBG("num_freqs: %d", num_freqs);
2861
2862                 scan_params->freqs = g_try_new0(uint16_t, num_freqs);
2863                 if (!scan_params->freqs) {
2864                         DBG("Failed to allocate memory.");
2865                         g_free(scan_params);
2866                         return -ENOMEM;
2867                 }
2868
2869                 count = 0;
2870                 for (list = specific_scan_list; list; list = list->next) {
2871                         freq = (int)list->data;
2872
2873                         scan_params->freqs[count] = freq;
2874                         DBG("scan_params->freqs[%d]: %d", count, scan_params->freqs[count]);
2875                         count++;
2876                 }
2877                 scan_params->num_freqs = count;
2878
2879         } else if (scan_type == CONNMAN_MULTI_SCAN_SSID_FREQ) { /* SSID & Frequency mixed scan */
2880                 int freq_count, ap_count;
2881                 scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
2882                 if (!scan_params) {
2883                         DBG("Failed to allocate memory.");
2884                         return -ENOMEM;
2885                 }
2886
2887                 guint size = g_slist_length(specific_scan_list);
2888
2889                 scan_params->freqs = g_try_new0(uint16_t, size/2);
2890                 if (!scan_params->freqs) {
2891                         DBG("Failed to allocate memory.");
2892                         g_free(scan_params);
2893                         return -ENOMEM;
2894                 }
2895
2896                 ap_count = freq_count = 0;
2897                 for (list = specific_scan_list; list; list = list->next) {
2898                         if (((connman_multi_scan_ap_s *)list->data)->flag == true) { /** ssid */
2899                                 ssid = ((connman_multi_scan_ap_s *)list->data)->str;
2900                                 int ssid_len = strlen(ssid);
2901
2902                                 scan_ssid = g_try_new0(struct scan_ssid, 1);
2903                                 if (!scan_ssid) {
2904                                         DBG("Failed to allocate memory.");
2905                                         g_supplicant_free_scan_params(scan_params);
2906                                         return -ENOMEM;
2907                                 }
2908
2909                                 memcpy(scan_ssid->ssid, ssid, (ssid_len + 1));
2910                                 /* DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); */
2911                                 scan_ssid->ssid_len = ssid_len;
2912                                 scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid);
2913                                 ap_count++;
2914
2915                         } else { /* freq */
2916                                 freq = atoi(((connman_multi_scan_ap_s *)list->data)->str);
2917                                 scan_params->freqs[freq_count] = freq;
2918                                 DBG("scan_params->freqs[%d]: %d", freq_count, scan_params->freqs[freq_count]);
2919                                 freq_count++;
2920                         }
2921                 }
2922                 scan_params->num_ssids = ap_count;
2923                 scan_params->num_freqs = freq_count;
2924         } else {
2925                 DBG("Invalid scan");
2926                 return -EINVAL;
2927         }
2928
2929         reset_autoscan(device);
2930         connman_device_ref(device);
2931
2932         ret = g_supplicant_interface_scan(wifi->interface, scan_params,
2933                                                 specific_scan_callback, device);
2934
2935         if (ret == 0) {
2936                 connman_device_set_scanning(device,
2937                                 CONNMAN_SERVICE_TYPE_WIFI, true);
2938         } else {
2939                 g_supplicant_free_scan_params(scan_params);
2940                 connman_device_unref(device);
2941         }
2942
2943         return ret;
2944 }
2945 #endif
2946
2947 #if defined TIZEN_EXT_WIFI_MESH
2948 static void mesh_scan_callback(int result, GSupplicantInterface *interface,
2949                                                 void *user_data)
2950 {
2951         struct connman_device *device = user_data;
2952         struct wifi_data *wifi = connman_device_get_data(device);
2953         bool scanning;
2954
2955         DBG("result %d wifi %p", result, wifi);
2956
2957         scanning = connman_device_get_scanning(device,
2958                                                CONNMAN_SERVICE_TYPE_MESH);
2959         if (scanning)
2960                 connman_device_set_scanning(device,
2961                                 CONNMAN_SERVICE_TYPE_MESH, false);
2962
2963         if (scanning)
2964                 connman_device_unref(device);
2965 }
2966
2967 static int mesh_scan(struct connman_device *device)
2968 {
2969         struct wifi_data *wifi;
2970         struct wifi_mesh_info *mesh_info;
2971         int ret;
2972
2973         DBG("");
2974
2975         wifi = connman_device_get_data(device);
2976
2977         if (!wifi->mesh_interface)
2978                 return -ENOTSUP;
2979
2980         mesh_info = wifi->mesh_info;
2981         reset_autoscan(device);
2982         connman_device_ref(device);
2983
2984         ret = g_supplicant_interface_scan(mesh_info->interface, NULL,
2985                                                 mesh_scan_callback, device);
2986         if (ret)
2987                 connman_device_unref(device);
2988         else
2989                 connman_device_set_scanning(device,
2990                                 CONNMAN_SERVICE_TYPE_MESH, true);
2991
2992         return ret;
2993 }
2994
2995 static void abort_scan_callback(int result, GSupplicantInterface *interface,
2996                                                 void *user_data)
2997 {
2998         struct connman_device *device = user_data;
2999         struct wifi_data *wifi = connman_device_get_data(device);
3000
3001         DBG("result %d wifi %p", result, wifi);
3002
3003         __connman_technology_notify_abort_scan(CONNMAN_SERVICE_TYPE_MESH, result);
3004 }
3005
3006 static int mesh_abort_scan(enum connman_service_type type,
3007                                                 struct connman_device *device)
3008 {
3009         struct wifi_data *wifi = connman_device_get_data(device);
3010         struct wifi_mesh_info *mesh_info;
3011         bool scanning;
3012         int ret;
3013
3014         if (!wifi || !wifi->mesh_interface)
3015                 return -ENODEV;
3016
3017         if (type != CONNMAN_SERVICE_TYPE_MESH)
3018                 return -EINVAL;
3019
3020         mesh_info = wifi->mesh_info;
3021
3022         scanning = connman_device_get_scanning(device,
3023                                                CONNMAN_SERVICE_TYPE_MESH);
3024         if (!scanning)
3025                 return -EEXIST;
3026
3027         ret = g_supplicant_interface_abort_scan(mesh_info->interface,
3028                                                 abort_scan_callback, device);
3029
3030         return ret;
3031 }
3032
3033 static int mesh_specific_scan(enum connman_service_type type,
3034                               struct connman_device *device, const char *ssid,
3035                               unsigned int freq, void *user_data)
3036 {
3037         struct wifi_data *wifi = connman_device_get_data(device);
3038         GSupplicantScanParams *scan_params = NULL;
3039         struct wifi_mesh_info *mesh_info;
3040         struct scan_ssid *scan_ssid;
3041         bool scanning;
3042         int ret;
3043
3044         if (!wifi || !wifi->mesh_interface)
3045                 return -ENODEV;
3046
3047         if (type != CONNMAN_SERVICE_TYPE_MESH)
3048                 return -EINVAL;
3049
3050         if (wifi->p2p_device)
3051                 return 0;
3052
3053         mesh_info = wifi->mesh_info;
3054
3055         scanning = connman_device_get_scanning(device,
3056                                                CONNMAN_SERVICE_TYPE_MESH);
3057         if (scanning)
3058                 return -EALREADY;
3059
3060         scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
3061         if (!scan_params)
3062                 return -ENOMEM;
3063
3064         scan_ssid = g_try_new(struct scan_ssid, 1);
3065         if (!scan_ssid) {
3066                 g_free(scan_params);
3067                 return -ENOMEM;
3068         }
3069
3070         scan_ssid->ssid_len = strlen(ssid);
3071         memcpy(scan_ssid->ssid, ssid, scan_ssid->ssid_len);
3072         scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid);
3073         scan_params->num_ssids = 1;
3074
3075         scan_params->freqs = g_try_new(uint16_t, 1);
3076         if (!scan_params->freqs) {
3077                 g_slist_free_full(scan_params->ssids, g_free);
3078                 g_free(scan_params);
3079                 return -ENOMEM;
3080         }
3081
3082         scan_params->freqs[0] = freq;
3083         scan_params->num_freqs = 1;
3084
3085         reset_autoscan(device);
3086         connman_device_ref(device);
3087
3088         ret = g_supplicant_interface_scan(mesh_info->interface, scan_params,
3089                                                 mesh_scan_callback, device);
3090
3091         if (ret == 0) {
3092                 connman_device_set_scanning(device,
3093                                 CONNMAN_SERVICE_TYPE_MESH, true);
3094         } else {
3095                 g_supplicant_free_scan_params(scan_params);
3096                 connman_device_unref(device);
3097         }
3098
3099         return ret;
3100 }
3101 #endif
3102
3103 /*
3104  * Note that the hidden scan is only used when connecting to this specific
3105  * hidden AP first time. It is not used when system autoconnects to hidden AP.
3106  */
3107 static int wifi_scan(struct connman_device *device,
3108                         struct connman_device_scan_params *params)
3109 {
3110         struct wifi_data *wifi = connman_device_get_data(device);
3111         GSupplicantScanParams *scan_params = NULL;
3112         struct scan_ssid *scan_ssid;
3113         struct hidden_params *hidden;
3114         int ret;
3115         int driver_max_ssids = 0;
3116         bool do_hidden;
3117         bool scanning;
3118
3119         if (!wifi)
3120                 return -ENODEV;
3121
3122         if (wifi->p2p_device)
3123                 return -EBUSY;
3124
3125         if (wifi->tethering)
3126                 return -EBUSY;
3127
3128         if (params->type == CONNMAN_SERVICE_TYPE_P2P)
3129                 return p2p_find(device);
3130
3131 #if defined TIZEN_EXT_WIFI_MESH
3132         if (params->type == CONNMAN_SERVICE_TYPE_MESH)
3133                 return mesh_scan(device);
3134 #endif
3135
3136         DBG("device %p wifi %p hidden ssid %s", device, wifi->interface,
3137                 params->ssid);
3138
3139         scanning = connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI);
3140
3141         if (!params->ssid || params->ssid_len == 0 || params->ssid_len > 32) {
3142                 if (scanning)
3143                         return -EALREADY;
3144
3145                 driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
3146                                                         wifi->interface);
3147                 DBG("max ssids %d", driver_max_ssids);
3148                 if (driver_max_ssids == 0)
3149                         return wifi_scan_simple(device);
3150
3151                 do_hidden = false;
3152         } else {
3153                 if (scanning && wifi->hidden && wifi->postpone_hidden)
3154                         return -EALREADY;
3155
3156                 do_hidden = true;
3157         }
3158
3159         scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
3160         if (!scan_params)
3161                 return -ENOMEM;
3162
3163         if (do_hidden) {
3164                 scan_ssid = g_try_new(struct scan_ssid, 1);
3165                 if (!scan_ssid) {
3166                         g_free(scan_params);
3167                         return -ENOMEM;
3168                 }
3169
3170                 memcpy(scan_ssid->ssid, params->ssid, params->ssid_len);
3171                 scan_ssid->ssid_len = params->ssid_len;
3172                 scan_params->ssids = g_slist_prepend(scan_params->ssids,
3173                                                                 scan_ssid);
3174                 scan_params->num_ssids = 1;
3175
3176                 hidden = g_try_new0(struct hidden_params, 1);
3177                 if (!hidden) {
3178                         g_supplicant_free_scan_params(scan_params);
3179                         return -ENOMEM;
3180                 }
3181
3182                 if (wifi->hidden) {
3183                         hidden_free(wifi->hidden);
3184                         wifi->hidden = NULL;
3185                 }
3186
3187                 memcpy(hidden->ssid, params->ssid, params->ssid_len);
3188                 hidden->ssid_len = params->ssid_len;
3189                 hidden->identity = g_strdup(params->identity);
3190                 hidden->passphrase = g_strdup(params->passphrase);
3191                 hidden->security = g_strdup(params->security);
3192                 hidden->user_data = params->user_data;
3193                 wifi->hidden = hidden;
3194
3195                 if (scanning) {
3196                         /* Let's keep this active scan for later,
3197                          * when current scan will be over. */
3198                         wifi->postpone_hidden = TRUE;
3199                         hidden->scan_params = scan_params;
3200
3201                         return 0;
3202                 }
3203         } else if (wifi->connected) {
3204                 g_supplicant_free_scan_params(scan_params);
3205                 return wifi_scan_simple(device);
3206         } else if (!params->force_full_scan) {
3207                 ret = get_latest_connections(driver_max_ssids, scan_params);
3208                 if (ret <= 0) {
3209                         g_supplicant_free_scan_params(scan_params);
3210                         return wifi_scan_simple(device);
3211                 }
3212         }
3213
3214         /* Distinguish between devices performing passive and active scanning */
3215         wifi_update_scanner_type(wifi, WIFI_SCANNING_ACTIVE);
3216
3217         connman_device_ref(device);
3218
3219         reset_autoscan(device);
3220
3221         ret = g_supplicant_interface_scan(wifi->interface, scan_params,
3222                                                 scan_callback, device);
3223         if (ret == 0) {
3224                 connman_device_set_scanning(device,
3225                                 CONNMAN_SERVICE_TYPE_WIFI, true);
3226 #if defined TIZEN_EXT
3227                 /*To allow the Full Scan after ssid based scan, set the flag here
3228                   It is required because Tizen does not use the ConnMan specific
3229                   backgroung Scan feature.Tizen has added the BG Scan feature in
3230                   net-config. To sync with up ConnMan, we need to issue the Full Scan
3231                   after SSID specific scan.*/
3232                 wifi->allow_full_scan = TRUE;
3233 #endif
3234         } else {
3235                 g_supplicant_free_scan_params(scan_params);
3236                 connman_device_unref(device);
3237
3238                 if (do_hidden) {
3239                         hidden_free(wifi->hidden);
3240                         wifi->hidden = NULL;
3241                 }
3242         }
3243
3244         return ret;
3245 }
3246
3247 static void wifi_stop_scan(enum connman_service_type type,
3248                         struct connman_device *device)
3249 {
3250         struct wifi_data *wifi = connman_device_get_data(device);
3251
3252         DBG("device %p wifi %p", device, wifi);
3253
3254         if (!wifi)
3255                 return;
3256
3257         if (type == CONNMAN_SERVICE_TYPE_P2P) {
3258                 if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_P2P)) {
3259                         g_source_remove(wifi->p2p_find_timeout);
3260                         p2p_find_stop(device);
3261                 }
3262         }
3263 }
3264
3265 static void wifi_regdom_callback(int result,
3266                                         const char *alpha2,
3267                                                 void *user_data)
3268 {
3269         struct connman_device *device = user_data;
3270
3271         connman_device_regdom_notify(device, result, alpha2);
3272
3273         connman_device_unref(device);
3274 }
3275
3276 static int wifi_set_regdom(struct connman_device *device, const char *alpha2)
3277 {
3278         struct wifi_data *wifi = connman_device_get_data(device);
3279         int ret;
3280
3281         if (!wifi)
3282                 return -EINVAL;
3283
3284         connman_device_ref(device);
3285
3286         ret = g_supplicant_interface_set_country(wifi->interface,
3287                                                 wifi_regdom_callback,
3288                                                         alpha2, device);
3289         if (ret != 0)
3290                 connman_device_unref(device);
3291
3292         return ret;
3293 }
3294
3295 static struct connman_device_driver wifi_ng_driver = {
3296         .name           = "wifi",
3297         .type           = CONNMAN_DEVICE_TYPE_WIFI,
3298         .priority       = CONNMAN_DEVICE_PRIORITY_LOW,
3299         .probe          = wifi_probe,
3300         .remove         = wifi_remove,
3301         .enable         = wifi_enable,
3302         .disable        = wifi_disable,
3303         .scan           = wifi_scan,
3304         .stop_scan      = wifi_stop_scan,
3305         .set_regdom     = wifi_set_regdom,
3306 #if defined TIZEN_EXT
3307         .specific_scan  = wifi_specific_scan,
3308 #endif
3309 #if defined TIZEN_EXT_WIFI_MESH
3310         .abort_scan     = mesh_abort_scan,
3311         .mesh_specific_scan     = mesh_specific_scan,
3312 #endif
3313 };
3314
3315 static void system_ready(void)
3316 {
3317         DBG("");
3318
3319         if (connman_device_driver_register(&wifi_ng_driver) < 0)
3320                 connman_error("Failed to register WiFi driver");
3321 }
3322
3323 static void system_killed(void)
3324 {
3325         DBG("");
3326
3327         connman_device_driver_unregister(&wifi_ng_driver);
3328 }
3329
3330 static int network_probe(struct connman_network *network)
3331 {
3332         DBG("network %p", network);
3333
3334         return 0;
3335 }
3336
3337 static void network_remove(struct connman_network *network)
3338 {
3339         struct connman_device *device = connman_network_get_device(network);
3340         struct wifi_data *wifi;
3341
3342         DBG("network %p", network);
3343
3344         wifi = connman_device_get_data(device);
3345         if (!wifi)
3346                 return;
3347
3348         if (wifi->network != network)
3349                 return;
3350
3351         wifi->network = NULL;
3352
3353 #if defined TIZEN_EXT
3354         wifi->disconnecting = false;
3355
3356         if (wifi->pending_network == network)
3357                 wifi->pending_network = NULL;
3358
3359         if (wifi->scan_pending_network == network)
3360                 wifi->scan_pending_network = NULL;
3361 #endif
3362 }
3363
3364 static void connect_callback(int result, GSupplicantInterface *interface,
3365                                                         void *user_data)
3366 {
3367 #if defined TIZEN_EXT
3368         GList *list;
3369         struct wifi_data *wifi;
3370 #endif
3371         struct connman_network *network = user_data;
3372
3373         DBG("network %p result %d", network, result);
3374
3375 #if defined TIZEN_EXT
3376         set_connman_bssid(RESET_BSSID, NULL);
3377
3378         for (list = iface_list; list; list = list->next) {
3379                 wifi = list->data;
3380
3381                 if (wifi && wifi->network == network)
3382                         goto found;
3383         }
3384
3385         /* wifi_data may be invalid because wifi is already disabled */
3386         return;
3387
3388 found:
3389 #endif
3390         if (result == -ENOKEY) {
3391                 connman_network_set_error(network,
3392                                         CONNMAN_NETWORK_ERROR_INVALID_KEY);
3393         } else if (result < 0) {
3394                 connman_network_set_error(network,
3395                                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
3396         }
3397
3398         connman_network_unref(network);
3399 }
3400
3401 static GSupplicantSecurity network_security(const char *security)
3402 {
3403         if (g_str_equal(security, "none"))
3404                 return G_SUPPLICANT_SECURITY_NONE;
3405         else if (g_str_equal(security, "wep"))
3406                 return G_SUPPLICANT_SECURITY_WEP;
3407         else if (g_str_equal(security, "psk"))
3408                 return G_SUPPLICANT_SECURITY_PSK;
3409         else if (g_str_equal(security, "wpa"))
3410                 return G_SUPPLICANT_SECURITY_PSK;
3411         else if (g_str_equal(security, "rsn"))
3412                 return G_SUPPLICANT_SECURITY_PSK;
3413         else if (g_str_equal(security, "ieee8021x"))
3414                 return G_SUPPLICANT_SECURITY_IEEE8021X;
3415 #if defined TIZEN_EXT
3416         else if (g_str_equal(security, "ft_psk") == TRUE)
3417                 return G_SUPPLICANT_SECURITY_FT_PSK;
3418         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
3419                 return G_SUPPLICANT_SECURITY_FT_IEEE8021X;
3420         else if (g_str_equal(security, "sae"))
3421                 return G_SUPPLICANT_SECURITY_SAE;
3422         else if (g_str_equal(security, "owe"))
3423                 return G_SUPPLICANT_SECURITY_OWE;
3424         else if (g_str_equal(security, "dpp"))
3425                 return G_SUPPLICANT_SECURITY_DPP;
3426 #endif
3427
3428         return G_SUPPLICANT_SECURITY_UNKNOWN;
3429 }
3430
3431 #if defined TIZEN_EXT
3432 static GSupplicantEapKeymgmt network_eap_keymgmt(const char *security)
3433 {
3434         if (security == NULL)
3435                 return G_SUPPLICANT_EAP_KEYMGMT_NONE;
3436
3437         if (g_str_equal(security, "FT") == TRUE)
3438                 return G_SUPPLICANT_EAP_KEYMGMT_FT;
3439         else if (g_str_equal(security, "CCKM") == TRUE)
3440                 return G_SUPPLICANT_EAP_KEYMGMT_CCKM;
3441
3442         return G_SUPPLICANT_EAP_KEYMGMT_NONE;
3443 }
3444 #endif
3445
3446 static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
3447 {
3448         const char *security;
3449 #if defined TIZEN_EXT
3450         const void *ssid_data;
3451 #endif
3452
3453         memset(ssid, 0, sizeof(*ssid));
3454         ssid->mode = G_SUPPLICANT_MODE_INFRA;
3455 #if defined TIZEN_EXT
3456         ssid_data = connman_network_get_blob(network, "WiFi.SSID",
3457                                                 &ssid->ssid_len);
3458         ssid->ssid = g_try_malloc0(ssid->ssid_len);
3459
3460         if (!ssid->ssid)
3461                 ssid->ssid_len = 0;
3462         else
3463                 memcpy(ssid->ssid, ssid_data, ssid->ssid_len);
3464 #else
3465         ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
3466                                                 &ssid->ssid_len);
3467 #endif
3468         ssid->scan_ssid = 1;
3469         security = connman_network_get_string(network, "WiFi.Security");
3470         ssid->security = network_security(security);
3471 #if defined TIZEN_EXT
3472         ssid->ieee80211w = 1;
3473 #endif
3474         ssid->passphrase = connman_network_get_string(network,
3475                                                 "WiFi.Passphrase");
3476
3477         ssid->eap = connman_network_get_string(network, "WiFi.EAP");
3478
3479         /*
3480          * If our private key password is unset,
3481          * we use the supplied passphrase. That is needed
3482          * for PEAP where 2 passphrases (identity and client
3483          * cert may have to be provided.
3484          */
3485         if (!connman_network_get_string(network, "WiFi.PrivateKeyPassphrase"))
3486                 connman_network_set_string(network,
3487                                                 "WiFi.PrivateKeyPassphrase",
3488                                                 ssid->passphrase);
3489         /* We must have an identity for both PEAP and TLS */
3490         ssid->identity = connman_network_get_string(network, "WiFi.Identity");
3491
3492         /* Use agent provided identity as a fallback */
3493         if (!ssid->identity || strlen(ssid->identity) == 0)
3494                 ssid->identity = connman_network_get_string(network,
3495                                                         "WiFi.AgentIdentity");
3496
3497         ssid->anonymous_identity = connman_network_get_string(network,
3498                                                 "WiFi.AnonymousIdentity");
3499         ssid->ca_cert_path = connman_network_get_string(network,
3500                                                         "WiFi.CACertFile");
3501         ssid->subject_match = connman_network_get_string(network,
3502                                                         "WiFi.SubjectMatch");
3503         ssid->altsubject_match = connman_network_get_string(network,
3504                                                         "WiFi.AltSubjectMatch");
3505         ssid->domain_suffix_match = connman_network_get_string(network,
3506                                                         "WiFi.DomainSuffixMatch");
3507         ssid->domain_match = connman_network_get_string(network,
3508                                                         "WiFi.DomainMatch");
3509         ssid->client_cert_path = connman_network_get_string(network,
3510                                                         "WiFi.ClientCertFile");
3511         ssid->private_key_path = connman_network_get_string(network,
3512                                                         "WiFi.PrivateKeyFile");
3513         ssid->private_key_passphrase = connman_network_get_string(network,
3514                                                 "WiFi.PrivateKeyPassphrase");
3515         ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
3516
3517         ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS");
3518         ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS");
3519 #if defined TIZEN_EXT
3520         ssid->connector = connman_network_get_string(network,
3521                                                         "WiFi.Connector");
3522         ssid->c_sign_key = connman_network_get_string(network,
3523                                                         "WiFi.CSignKey");
3524         ssid->net_access_key = connman_network_get_string(network,
3525                                                 "WiFi.NetAccessKey");
3526 #endif
3527
3528 #if defined TIZEN_EXT
3529         if (set_connman_bssid(CHECK_BSSID, NULL) == 6) {
3530                 ssid->bssid_for_connect_len = 6;
3531                 set_connman_bssid(GET_BSSID, (char *)ssid->bssid_for_connect);
3532                 DBG("BSSID : %02x:%02x:%02x:%02x:%02x:%02x",
3533                         ssid->bssid_for_connect[0], ssid->bssid_for_connect[1],
3534                         ssid->bssid_for_connect[2], ssid->bssid_for_connect[3],
3535                         ssid->bssid_for_connect[4], ssid->bssid_for_connect[5]);
3536         } else {
3537                 ssid->freq = connman_network_get_frequency(network);
3538         }
3539
3540         GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network);
3541         if (bssid_list && g_slist_length(bssid_list) > 1) {
3542
3543                 /* If there are more than one bssid,
3544                  * the user-specified bssid is tried only once at the beginning.
3545                  * After that, the bssids in the list are tried in order.
3546                  */
3547                 if (set_connman_bssid(CHECK_BSSID, NULL) == 6) {
3548                         set_connman_bssid(RESET_BSSID, NULL);
3549                         goto done;
3550                 }
3551
3552                 GSList *list;
3553                 char buff[MAC_ADDRESS_LENGTH];
3554                 for (list = bssid_list; list; list = list->next) {
3555                         struct connman_bssids * bssids = (struct connman_bssids *)list->data;
3556
3557                         g_snprintf(buff, MAC_ADDRESS_LENGTH, "%02x:%02x:%02x:%02x:%02x:%02x",
3558                                         bssids->bssid[0], bssids->bssid[1], bssids->bssid[2],
3559                                         bssids->bssid[3], bssids->bssid[4], bssids->bssid[5]);
3560                         buff[MAC_ADDRESS_LENGTH - 1] = '\0';
3561
3562                         gchar *curr_bssid = g_strdup((const gchar *)buff);
3563
3564                         if (g_hash_table_contains(failed_bssids, curr_bssid)) {
3565                                 DBG("bssid match, try next bssid");
3566                                 g_free(curr_bssid);
3567                                 continue;
3568                         } else {
3569                                 g_hash_table_add(failed_bssids, curr_bssid);
3570
3571                                 memcpy(buff_bssid, bssids->bssid, WIFI_BSSID_LEN_MAX);
3572                                 ssid->bssid = buff_bssid;
3573                                 ssid->freq = (unsigned int)bssids->frequency;
3574                                 break;
3575                         }
3576                 }
3577
3578                 if (!list) {
3579                         ssid->bssid = connman_network_get_bssid(network);
3580                         g_hash_table_remove_all(failed_bssids);
3581                 }
3582         } else
3583                 ssid->bssid = connman_network_get_bssid(network);
3584
3585 done:
3586         ssid->eap_keymgmt = network_eap_keymgmt(
3587                         connman_network_get_string(network, "WiFi.KeymgmtType"));
3588         ssid->phase1 = connman_network_get_string(network, "WiFi.Phase1");
3589
3590         if(g_strcmp0(ssid->eap, "fast") == 0)
3591                 ssid->pac_file = g_strdup(WIFI_EAP_FAST_PAC_FILE);
3592 #endif
3593
3594         if (connman_setting_get_bool("BackgroundScanning"))
3595                 ssid->bgscan = BGSCAN_DEFAULT;
3596 }
3597
3598 static int network_connect(struct connman_network *network)
3599 {
3600         struct connman_device *device = connman_network_get_device(network);
3601         struct wifi_data *wifi;
3602         GSupplicantInterface *interface;
3603         GSupplicantSSID *ssid;
3604
3605         DBG("network %p", network);
3606
3607         if (!device)
3608                 return -ENODEV;
3609
3610         wifi = connman_device_get_data(device);
3611         if (!wifi)
3612                 return -ENODEV;
3613
3614         ssid = g_try_malloc0(sizeof(GSupplicantSSID));
3615         if (!ssid)
3616                 return -ENOMEM;
3617
3618         interface = wifi->interface;
3619
3620         ssid_init(ssid, network);
3621
3622         if (wifi->disconnecting) {
3623                 wifi->pending_network = network;
3624 #if defined TIZEN_EXT
3625                 g_free(ssid->ssid);
3626 #endif
3627                 g_free(ssid);
3628         } else {
3629                 wifi->network = connman_network_ref(network);
3630                 wifi->retries = 0;
3631 #if defined TIZEN_EXT
3632                 wifi->scan_pending_network = NULL;
3633 #endif
3634
3635                 return g_supplicant_interface_connect(interface, ssid,
3636                                                 connect_callback, network);
3637         }
3638
3639         return -EINPROGRESS;
3640 }
3641
3642 static void disconnect_callback(int result, GSupplicantInterface *interface,
3643                                                                 void *user_data)
3644 {
3645 #if defined TIZEN_EXT
3646         GList *list;
3647         struct wifi_data *wifi;
3648         struct connman_network *network = user_data;
3649
3650         DBG("network %p result %d", network, result);
3651
3652         for (list = iface_list; list; list = list->next) {
3653                 wifi = list->data;
3654
3655                 if (wifi->network == NULL && wifi->disconnecting == true)
3656                         wifi->disconnecting = false;
3657
3658                 if (wifi->network == network)
3659                         goto found;
3660         }
3661
3662         /* wifi_data may be invalid because wifi is already disabled */
3663         return;
3664
3665 found:
3666 #else
3667         struct wifi_data *wifi = user_data;
3668 #endif
3669
3670         DBG("result %d supplicant interface %p wifi %p",
3671                         result, interface, wifi);
3672
3673         if (result == -ECONNABORTED) {
3674                 DBG("wifi interface no longer available");
3675                 return;
3676         }
3677
3678         if (wifi->network != wifi->pending_network)
3679                 connman_network_set_connected(wifi->network, false);
3680         wifi->network = NULL;
3681
3682         wifi->disconnecting = false;
3683         wifi->connected = false;
3684
3685         if (wifi->pending_network) {
3686                 network_connect(wifi->pending_network);
3687                 wifi->pending_network = NULL;
3688         }
3689
3690         start_autoscan(wifi->device);
3691 }
3692
3693 static int network_disconnect(struct connman_network *network)
3694 {
3695         struct connman_device *device = connman_network_get_device(network);
3696         struct wifi_data *wifi;
3697         int err;
3698 #if defined TIZEN_EXT
3699         struct connman_service *service;
3700 #endif
3701
3702         DBG("network %p", network);
3703
3704         wifi = connman_device_get_data(device);
3705         if (!wifi || !wifi->interface)
3706                 return -ENODEV;
3707
3708 #if defined TIZEN_EXT
3709         if (connman_network_get_associating(network) == true) {
3710                 connman_network_clear_associating(network);
3711                 connman_network_set_bool(network, "WiFi.UseWPS", false);
3712         } else {
3713                 service = connman_service_lookup_from_network(network);
3714
3715                 if (service != NULL &&
3716                         (__connman_service_is_connected_state(service,
3717                                         CONNMAN_IPCONFIG_TYPE_IPV4) == false &&
3718                         __connman_service_is_connected_state(service,
3719                                         CONNMAN_IPCONFIG_TYPE_IPV6) == false) &&
3720                         (connman_service_get_favorite(service) == false))
3721                                         __connman_service_set_passphrase(service, NULL);
3722         }
3723
3724         if (wifi->pending_network == network)
3725                 wifi->pending_network = NULL;
3726
3727         if (wifi->scan_pending_network == network)
3728                 wifi->scan_pending_network = NULL;
3729
3730 #endif
3731         connman_network_set_associating(network, false);
3732
3733         if (wifi->disconnecting)
3734                 return -EALREADY;
3735
3736         wifi->disconnecting = true;
3737
3738 #if defined TIZEN_EXT
3739         err = g_supplicant_interface_disconnect(wifi->interface,
3740                                                 disconnect_callback, network);
3741 #else
3742         err = g_supplicant_interface_disconnect(wifi->interface,
3743                                                 disconnect_callback, wifi);
3744 #endif
3745
3746         if (err < 0)
3747                 wifi->disconnecting = false;
3748
3749         return err;
3750 }
3751
3752 #if defined TIZEN_EXT
3753 static void set_connection_mode(struct connman_network *network,
3754                 int linkspeed)
3755 {
3756         ieee80211_modes_e phy_mode;
3757         connection_mode_e conn_mode;
3758
3759         phy_mode = connman_network_get_phy_mode(network);
3760         switch (phy_mode) {
3761         case IEEE80211_MODE_B:
3762                 if (linkspeed > 0 && linkspeed <= 11)
3763                         conn_mode = CONNECTION_MODE_IEEE80211B;
3764                 else
3765                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3766
3767                 break;
3768         case IEEE80211_MODE_BG:
3769                 if (linkspeed > 0 && linkspeed <= 11)
3770                         conn_mode = CONNECTION_MODE_IEEE80211B;
3771                 else if (linkspeed > 11 && linkspeed <= 54)
3772                         conn_mode = CONNECTION_MODE_IEEE80211G;
3773                 else
3774                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3775
3776                 break;
3777         case IEEE80211_MODE_BGN:
3778                 if (linkspeed > 0 && linkspeed <= 11)
3779                         conn_mode = CONNECTION_MODE_IEEE80211B;
3780                 else if (linkspeed > 11 && linkspeed <= 54)
3781                         conn_mode = CONNECTION_MODE_IEEE80211G;
3782                 else if (linkspeed > 54 && linkspeed <= 450)
3783                         conn_mode = CONNECTION_MODE_IEEE80211N;
3784                 else
3785                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3786
3787                 break;
3788         case IEEE80211_MODE_A:
3789                 if (linkspeed > 0 && linkspeed <= 54)
3790                         conn_mode = CONNECTION_MODE_IEEE80211A;
3791                 else
3792                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3793
3794                 break;
3795         case IEEE80211_MODE_AN:
3796                 if (linkspeed > 0 && linkspeed <= 54)
3797                         conn_mode = CONNECTION_MODE_IEEE80211A;
3798                 else if (linkspeed > 54 && linkspeed <= 450)
3799                         conn_mode = CONNECTION_MODE_IEEE80211N;
3800                 else
3801                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3802
3803                 break;
3804         case IEEE80211_MODE_ANAC:
3805                 if (linkspeed > 0 && linkspeed <= 54)
3806                         conn_mode = CONNECTION_MODE_IEEE80211A;
3807                 else if (linkspeed > 54 && linkspeed <= 450)
3808                         conn_mode = CONNECTION_MODE_IEEE80211N;
3809                 else if (linkspeed > 450 && linkspeed <= 1300)
3810                         conn_mode = CONNECTION_MODE_IEEE80211AC;
3811                 else
3812                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3813
3814                 break;
3815         default:
3816                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3817                 break;
3818         }
3819
3820         DBG("connection mode(%d)", conn_mode);
3821         connman_network_set_connection_mode(network, conn_mode);
3822 }
3823
3824 static void signalpoll_callback(int result, int maxspeed, int strength,
3825                                 void *user_data)
3826 {
3827         struct connman_network *network = user_data;
3828
3829         if (result != 0) {
3830                 DBG("Failed to get maxspeed from signalpoll !");
3831                 return;
3832         }
3833
3834         strength += 120;
3835         if (strength > 100)
3836                 strength = 100;
3837
3838         DBG("maxspeed = %d, strength = %d", maxspeed, strength);
3839         if (network) {
3840                 connman_network_set_strength(network, (uint8_t)strength);
3841                 connman_network_set_maxspeed(network, maxspeed);
3842                 set_connection_mode(network, maxspeed);
3843         }
3844 }
3845
3846 static int network_signalpoll(struct wifi_data *wifi)
3847 {
3848         GSupplicantInterface *interface;
3849         struct connman_network *network;
3850
3851         if (!wifi || !wifi->network)
3852                 return -ENODEV;
3853
3854         interface = wifi->interface;
3855         network = wifi->network;
3856
3857         DBG("network %p", network);
3858
3859         return g_supplicant_interface_signalpoll(interface, signalpoll_callback, network);
3860 }
3861
3862 static gboolean autosignalpoll_timeout(gpointer data)
3863 {
3864         struct wifi_data *wifi = data;
3865
3866         if (!wifi || !wifi->automaxspeed_timeout) {
3867                 DBG("automaxspeed_timeout is found to be zero. i.e. currently in disconnected state. !!");
3868                 return FALSE;
3869         }
3870
3871         int ret = network_signalpoll(wifi);
3872         if (ret < 0) {
3873                 DBG("Fail to get max speed !!");
3874                 wifi->automaxspeed_timeout = 0;
3875                 return FALSE;
3876         }
3877
3878         return TRUE;
3879 }
3880 #endif
3881
3882 static struct connman_network_driver network_driver = {
3883         .name           = "wifi",
3884         .type           = CONNMAN_NETWORK_TYPE_WIFI,
3885         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
3886         .probe          = network_probe,
3887         .remove         = network_remove,
3888         .connect        = network_connect,
3889         .disconnect     = network_disconnect,
3890 };
3891
3892 static void interface_added(GSupplicantInterface *interface)
3893 {
3894         const char *ifname = g_supplicant_interface_get_ifname(interface);
3895         const char *driver = g_supplicant_interface_get_driver(interface);
3896 #if defined TIZEN_EXT
3897         bool is_5_0_ghz_supported = g_supplicant_interface_get_is_5_0_ghz_supported(interface);
3898 #endif
3899
3900         struct wifi_data *wifi;
3901
3902         wifi = g_supplicant_interface_get_data(interface);
3903         if (!wifi) {
3904                 wifi = get_pending_wifi_data(ifname);
3905                 if (!wifi)
3906                         return;
3907
3908                 wifi->interface = interface;
3909                 g_supplicant_interface_set_data(interface, wifi);
3910                 p2p_iface_list = g_list_append(p2p_iface_list, wifi);
3911                 wifi->p2p_device = true;
3912         }
3913
3914         DBG("ifname %s driver %s wifi %p tethering %d",
3915                         ifname, driver, wifi, wifi->tethering);
3916
3917         if (!wifi->device) {
3918                 connman_error("WiFi device not set");
3919                 return;
3920         }
3921
3922         connman_device_set_powered(wifi->device, true);
3923 #if defined TIZEN_EXT
3924         connman_techonology_wifi_set_5ghz_supported(wifi_technology, is_5_0_ghz_supported);
3925         /* Max number of SSIDs supported by wlan chipset that can be scanned */
3926         int max_scan_ssids = g_supplicant_interface_get_max_scan_ssids(interface);
3927         connman_techonology_set_max_scan_ssids(wifi_technology, max_scan_ssids);
3928 #endif
3929 }
3930
3931 static bool is_idle(struct wifi_data *wifi)
3932 {
3933         DBG("state %d", wifi->state);
3934
3935         switch (wifi->state) {
3936         case G_SUPPLICANT_STATE_UNKNOWN:
3937         case G_SUPPLICANT_STATE_DISABLED:
3938         case G_SUPPLICANT_STATE_DISCONNECTED:
3939         case G_SUPPLICANT_STATE_INACTIVE:
3940         case G_SUPPLICANT_STATE_SCANNING:
3941                 return true;
3942
3943         case G_SUPPLICANT_STATE_AUTHENTICATING:
3944         case G_SUPPLICANT_STATE_ASSOCIATING:
3945         case G_SUPPLICANT_STATE_ASSOCIATED:
3946         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3947         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3948         case G_SUPPLICANT_STATE_COMPLETED:
3949                 return false;
3950         }
3951
3952         return false;
3953 }
3954
3955 static bool is_idle_wps(GSupplicantInterface *interface,
3956                                                 struct wifi_data *wifi)
3957 {
3958         /* First, let's check if WPS processing did not went wrong */
3959         if (g_supplicant_interface_get_wps_state(interface) ==
3960                 G_SUPPLICANT_WPS_STATE_FAIL)
3961                 return false;
3962
3963         /* Unlike normal connection, being associated while processing wps
3964          * actually means that we are idling. */
3965         switch (wifi->state) {
3966         case G_SUPPLICANT_STATE_UNKNOWN:
3967         case G_SUPPLICANT_STATE_DISABLED:
3968         case G_SUPPLICANT_STATE_DISCONNECTED:
3969         case G_SUPPLICANT_STATE_INACTIVE:
3970         case G_SUPPLICANT_STATE_SCANNING:
3971         case G_SUPPLICANT_STATE_ASSOCIATED:
3972                 return true;
3973         case G_SUPPLICANT_STATE_AUTHENTICATING:
3974         case G_SUPPLICANT_STATE_ASSOCIATING:
3975         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3976         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3977         case G_SUPPLICANT_STATE_COMPLETED:
3978                 return false;
3979         }
3980
3981         return false;
3982 }
3983
3984 static bool handle_wps_completion(GSupplicantInterface *interface,
3985                                         struct connman_network *network,
3986                                         struct connman_device *device,
3987                                         struct wifi_data *wifi)
3988 {
3989         bool wps;
3990
3991         wps = connman_network_get_bool(network, "WiFi.UseWPS");
3992         if (wps) {
3993                 const unsigned char *ssid, *wps_ssid;
3994                 unsigned int ssid_len, wps_ssid_len;
3995                 const char *wps_key;
3996
3997                 /* Checking if we got associated with requested
3998                  * network */
3999                 ssid = connman_network_get_blob(network, "WiFi.SSID",
4000                                                 &ssid_len);
4001
4002                 wps_ssid = g_supplicant_interface_get_wps_ssid(
4003                         interface, &wps_ssid_len);
4004
4005                 if (!wps_ssid || wps_ssid_len != ssid_len ||
4006                                 memcmp(ssid, wps_ssid, ssid_len) != 0) {
4007                         connman_network_set_associating(network, false);
4008 #if defined TIZEN_EXT
4009                         g_supplicant_interface_disconnect(wifi->interface,
4010                                                 disconnect_callback, wifi->network);
4011
4012                         connman_network_set_bool(network, "WiFi.UseWPS", false);
4013                         connman_network_set_string(network, "WiFi.PinWPS", NULL);
4014 #else
4015                         g_supplicant_interface_disconnect(wifi->interface,
4016                                                 disconnect_callback, wifi);
4017 #endif
4018                         return false;
4019                 }
4020
4021                 wps_key = g_supplicant_interface_get_wps_key(interface);
4022 #if defined TIZEN_EXT
4023                 /* Check the passphrase and encrypt it
4024                  */
4025                  int ret;
4026                  gchar *passphrase = g_strdup(wps_key);
4027
4028                  connman_network_set_string(network, "WiFi.PinWPS", NULL);
4029
4030                  if (check_passphrase_ext(network, passphrase) < 0) {
4031                          DBG("[WPS] Invalid passphrase");
4032                          g_free(passphrase);
4033                          return true;
4034                  }
4035
4036                  ret = send_encryption_request(passphrase, network);
4037
4038                  g_free(passphrase);
4039
4040                  if (!ret)
4041                          DBG("[WPS] Encryption request succeeded");
4042                  else
4043                          DBG("[WPS] Encryption request failed %d", ret);
4044
4045 #else
4046                 connman_network_set_string(network, "WiFi.Passphrase",
4047                                         wps_key);
4048
4049                 connman_network_set_string(network, "WiFi.PinWPS", NULL);
4050 #endif
4051         }
4052
4053         return true;
4054 }
4055
4056 static bool handle_assoc_status_code(GSupplicantInterface *interface,
4057                                      struct wifi_data *wifi)
4058 {
4059         if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING &&
4060 #if defined TIZEN_EXT
4061                         wifi->assoc_code > 0 &&
4062 #else
4063                         wifi->assoc_code == ASSOC_STATUS_NO_CLIENT &&
4064 #endif
4065                         wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) {
4066                 wifi->load_shaping_retries ++;
4067                 return TRUE;
4068         }
4069         wifi->load_shaping_retries = 0;
4070         return FALSE;
4071 }
4072
4073 static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
4074                                         struct connman_network *network,
4075                                         struct wifi_data *wifi)
4076 {
4077 #if defined TIZEN_EXT
4078         const char *security;
4079         struct connman_service *service;
4080
4081         if (wifi->connected)
4082                 return false;
4083
4084         security = connman_network_get_string(network, "WiFi.Security");
4085
4086         if (security && g_str_equal(security, "ieee8021x") == true &&
4087                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
4088                 wifi->retries = 0;
4089                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
4090
4091                 return false;
4092         }
4093
4094         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
4095                 return false;
4096 #else
4097         struct connman_service *service;
4098
4099         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
4100                 return false;
4101
4102         if (wifi->connected)
4103                 return false;
4104 #endif
4105
4106         service = connman_service_lookup_from_network(network);
4107         if (!service)
4108                 return false;
4109
4110         wifi->retries++;
4111
4112         if (connman_service_get_favorite(service)) {
4113                 if (wifi->retries < FAVORITE_MAXIMUM_RETRIES)
4114                         return true;
4115         }
4116
4117         wifi->retries = 0;
4118         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
4119
4120         return false;
4121 }
4122
4123 #if defined TIZEN_EXT
4124 static bool handle_wifi_assoc_retry(struct connman_network *network,
4125                                         struct wifi_data *wifi)
4126 {
4127         const char *security;
4128
4129         if (!wifi->network || wifi->connected || wifi->disconnecting ||
4130                         connman_network_get_connecting(network) != true) {
4131                 wifi->assoc_retry_count = 0;
4132                 return false;
4133         }
4134
4135         if (wifi->state != G_SUPPLICANT_STATE_ASSOCIATING &&
4136                         wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) {
4137                 wifi->assoc_retry_count = 0;
4138                 return false;
4139         }
4140
4141         security = connman_network_get_string(network, "WiFi.Security");
4142         if (security && g_str_equal(security, "ieee8021x") == true &&
4143                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
4144                 wifi->assoc_retry_count = 0;
4145                 return false;
4146         }
4147
4148         if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) {
4149                 wifi->assoc_retry_count = 0;
4150
4151                 /* Honestly it's not an invalid-key error,
4152                  * however QA team recommends that the invalid-key error
4153                  * might be better to display for user experience.
4154                  */
4155                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
4156
4157                 return false;
4158         }
4159
4160         return true;
4161 }
4162 #endif
4163
4164 static void interface_state(GSupplicantInterface *interface)
4165 {
4166         struct connman_network *network;
4167         struct connman_device *device;
4168         struct wifi_data *wifi;
4169         GSupplicantState state = g_supplicant_interface_get_state(interface);
4170         bool wps;
4171         bool old_connected;
4172
4173         wifi = g_supplicant_interface_get_data(interface);
4174
4175         DBG("wifi %p interface state %d", wifi, state);
4176
4177         if (!wifi)
4178                 return;
4179
4180         device = wifi->device;
4181         if (!device)
4182                 return;
4183
4184         if (state == G_SUPPLICANT_STATE_COMPLETED) {
4185                 if (wifi->tethering_param) {
4186                         g_free(wifi->tethering_param->ssid);
4187                         g_free(wifi->tethering_param);
4188                         wifi->tethering_param = NULL;
4189                 }
4190
4191                 if (wifi->tethering)
4192                         stop_autoscan(device);
4193         }
4194
4195         if (g_supplicant_interface_get_ready(interface) &&
4196                                         !wifi->interface_ready) {
4197                 wifi->interface_ready = true;
4198                 finalize_interface_creation(wifi);
4199         }
4200
4201         network = wifi->network;
4202         if (!network)
4203                 return;
4204
4205         switch (state) {
4206         case G_SUPPLICANT_STATE_SCANNING:
4207                 if (wifi->connected)
4208                         connman_network_set_connected(network, false);
4209
4210                 break;
4211
4212         case G_SUPPLICANT_STATE_AUTHENTICATING:
4213         case G_SUPPLICANT_STATE_ASSOCIATING:
4214 #if defined TIZEN_EXT
4215                 reset_autoscan(device);
4216 #else
4217                 stop_autoscan(device);
4218 #endif
4219
4220                 if (!wifi->connected)
4221                         connman_network_set_associating(network, true);
4222
4223                 break;
4224
4225         case G_SUPPLICANT_STATE_COMPLETED:
4226 #if defined TIZEN_EXT
4227                 /* though it should be already reset: */
4228                 reset_autoscan(device);
4229
4230                 wifi->assoc_retry_count = 0;
4231
4232                 wifi->scan_pending_network = NULL;
4233
4234                 /* should be cleared scanning flag */
4235                 bool scanning = connman_device_get_scanning(device,
4236                                                CONNMAN_SERVICE_TYPE_WIFI);
4237                 if (scanning){
4238                         connman_device_set_scanning(device,
4239                                 CONNMAN_SERVICE_TYPE_WIFI, false);
4240                         connman_device_unref(device);
4241                 }
4242
4243                 if (!wifi->automaxspeed_timeout) {
4244                         DBG("Going to start signalpoll timer!!");
4245                         int ret = network_signalpoll(wifi);
4246                         if (ret < 0)
4247                                 DBG("Fail to get max speed !!");
4248                         else
4249                                 wifi->automaxspeed_timeout = g_timeout_add_seconds(10, autosignalpoll_timeout, wifi);
4250                 }
4251
4252                 g_hash_table_remove_all(failed_bssids);
4253 #else
4254                 /* though it should be already stopped: */
4255                 stop_autoscan(device);
4256 #endif
4257
4258                 if (!handle_wps_completion(interface, network, device, wifi))
4259                         break;
4260
4261                 connman_network_set_connected(network, true);
4262
4263                 wifi->disconnect_code = 0;
4264                 wifi->assoc_code = 0;
4265                 wifi->load_shaping_retries = 0;
4266                 break;
4267
4268         case G_SUPPLICANT_STATE_DISCONNECTED:
4269 #if defined TIZEN_EXT
4270                 connman_network_set_strength(network, 0);
4271                 connman_network_set_maxspeed(network, 0);
4272
4273                 if (wifi->automaxspeed_timeout != 0) {
4274                         g_source_remove(wifi->automaxspeed_timeout);
4275                         wifi->automaxspeed_timeout = 0;
4276                         DBG("Remove signalpoll timer!!");
4277                 }
4278 #endif
4279                 /*
4280                  * If we're in one of the idle modes, we have
4281                  * not started association yet and thus setting
4282                  * those ones to FALSE could cancel an association
4283                  * in progress.
4284                  */
4285                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
4286                 if (wps)
4287                         if (is_idle_wps(interface, wifi))
4288                                 break;
4289
4290                 if (is_idle(wifi))
4291                         break;
4292
4293 #if defined TIZEN_EXT
4294                 if (handle_assoc_status_code(interface, wifi)) {
4295                         GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network);
4296                         guint bssid_length = 0;
4297
4298                         if (bssid_list)
4299                                 bssid_length = g_slist_length(bssid_list);
4300
4301                         if (bssid_length > 1 && bssid_length > g_hash_table_size(failed_bssids)) {
4302                                 network_connect(network);
4303                                 break;
4304                         }
4305
4306                         wifi->load_shaping_retries = 0;
4307                 }
4308
4309                 g_hash_table_remove_all(failed_bssids);
4310 #else
4311                 if (handle_assoc_status_code(interface, wifi))
4312                         break;
4313 #endif
4314
4315                 /* If previous state was 4way-handshake, then
4316                  * it's either: psk was incorrect and thus we retry
4317                  * or if we reach the maximum retries we declare the
4318                  * psk as wrong */
4319                 if (handle_4way_handshake_failure(interface,
4320                                                 network, wifi))
4321                         break;
4322
4323                 /* See table 8-36 Reason codes in IEEE Std 802.11 */
4324                 switch (wifi->disconnect_code) {
4325                 case 1: /* Unspecified reason */
4326                         /* Let's assume it's because we got blocked */
4327
4328                 case 6: /* Class 2 frame received from nonauthenticated STA */
4329                         connman_network_set_error(network,
4330                                                 CONNMAN_NETWORK_ERROR_BLOCKED);
4331                         break;
4332
4333                 default:
4334                         break;
4335                 }
4336
4337 #if defined TIZEN_EXT
4338                 /* Some of Wi-Fi networks are not comply Wi-Fi specification.
4339                  * Retry association until its retry count is expired */
4340                 if (handle_wifi_assoc_retry(network, wifi) == true) {
4341                         throw_wifi_scan(wifi->device, scan_callback);
4342                         wifi->scan_pending_network = wifi->network;
4343                         break;
4344                 }
4345
4346                 if(wifi->disconnect_code > 0){
4347                         DBG("Set disconnect reason code(%d)", wifi->disconnect_code);
4348                         connman_network_set_disconnect_reason(network, wifi->disconnect_code);
4349                 }
4350 #endif
4351
4352                 if (network != wifi->pending_network) {
4353                         connman_network_set_connected(network, false);
4354                         connman_network_set_associating(network, false);
4355                 }
4356                 wifi->disconnecting = false;
4357
4358                 start_autoscan(device);
4359
4360                 break;
4361
4362         case G_SUPPLICANT_STATE_INACTIVE:
4363 #if defined TIZEN_EXT
4364                 if (handle_wps_completion(interface, network, device, wifi) == false)
4365                         break;
4366 #endif
4367                 connman_network_set_associating(network, false);
4368                 start_autoscan(device);
4369
4370                 break;
4371
4372         case G_SUPPLICANT_STATE_UNKNOWN:
4373         case G_SUPPLICANT_STATE_DISABLED:
4374         case G_SUPPLICANT_STATE_ASSOCIATED:
4375         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4376         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4377                 break;
4378         }
4379
4380         old_connected = wifi->connected;
4381         wifi->state = state;
4382
4383         /* Saving wpa_s state policy:
4384          * If connected and if the state changes are roaming related:
4385          * --> We stay connected
4386          * If completed
4387          * --> We are connected
4388          * All other case:
4389          * --> We are not connected
4390          * */
4391         switch (state) {
4392         case G_SUPPLICANT_STATE_AUTHENTICATING:
4393         case G_SUPPLICANT_STATE_ASSOCIATING:
4394         case G_SUPPLICANT_STATE_ASSOCIATED:
4395         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4396         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4397                 if (wifi->connected)
4398                         connman_warn("Probably roaming right now!"
4399                                                 " Staying connected...");
4400                 break;
4401         case G_SUPPLICANT_STATE_SCANNING:
4402                 wifi->connected = false;
4403
4404                 if (old_connected)
4405                         start_autoscan(device);
4406                 break;
4407         case G_SUPPLICANT_STATE_COMPLETED:
4408                 wifi->connected = true;
4409                 break;
4410         default:
4411                 wifi->connected = false;
4412                 break;
4413         }
4414
4415         DBG("DONE");
4416 }
4417
4418 static void interface_removed(GSupplicantInterface *interface)
4419 {
4420         const char *ifname = g_supplicant_interface_get_ifname(interface);
4421         struct wifi_data *wifi;
4422
4423         DBG("ifname %s", ifname);
4424
4425         wifi = g_supplicant_interface_get_data(interface);
4426
4427 #if defined TIZEN_EXT_WIFI_MESH
4428         if (wifi && wifi->mesh_interface) {
4429                 DBG("Notify mesh interface remove");
4430                 connman_mesh_notify_interface_remove(true);
4431                 struct wifi_mesh_info *mesh_info = wifi->mesh_info;
4432                 g_free(mesh_info->parent_ifname);
4433                 g_free(mesh_info->ifname);
4434                 g_free(mesh_info->identifier);
4435                 g_free(mesh_info);
4436                 wifi->mesh_interface = false;
4437                 wifi->mesh_info = NULL;
4438                 return;
4439         }
4440 #endif
4441
4442         if (wifi)
4443                 wifi->interface = NULL;
4444
4445         if (wifi && wifi->tethering)
4446                 return;
4447
4448         if (!wifi || !wifi->device) {
4449                 DBG("wifi interface already removed");
4450                 return;
4451         }
4452
4453         connman_device_set_powered(wifi->device, false);
4454
4455         check_p2p_technology();
4456 #if defined TIZEN_EXT_WIFI_MESH
4457         check_mesh_technology();
4458 #endif
4459 }
4460
4461 static void set_device_type(const char *type, char dev_type[17])
4462 {
4463         const char *oui = "0050F204";
4464         const char *category = "0001";
4465         const char *sub_category = "0000";
4466
4467         if (!g_strcmp0(type, "handset")) {
4468                 category = "000A";
4469                 sub_category = "0005";
4470         } else if (!g_strcmp0(type, "vm") || !g_strcmp0(type, "container"))
4471                 sub_category = "0001";
4472         else if (!g_strcmp0(type, "server"))
4473                 sub_category = "0002";
4474         else if (!g_strcmp0(type, "laptop"))
4475                 sub_category = "0005";
4476         else if (!g_strcmp0(type, "desktop"))
4477                 sub_category = "0006";
4478         else if (!g_strcmp0(type, "tablet"))
4479                 sub_category = "0009";
4480         else if (!g_strcmp0(type, "watch"))
4481                 category = "00FF";
4482
4483         snprintf(dev_type, 17, "%s%s%s", category, oui, sub_category);
4484 }
4485
4486 static void p2p_support(GSupplicantInterface *interface)
4487 {
4488         char dev_type[17] = {};
4489         const char *hostname;
4490
4491         DBG("");
4492
4493         if (!interface)
4494                 return;
4495
4496         if (!g_supplicant_interface_has_p2p(interface))
4497                 return;
4498
4499         if (connman_technology_driver_register(&p2p_tech_driver) < 0) {
4500                 DBG("Could not register P2P technology driver");
4501                 return;
4502         }
4503
4504         hostname = connman_utsname_get_hostname();
4505         if (!hostname)
4506                 hostname = "ConnMan";
4507
4508         set_device_type(connman_machine_get_type(), dev_type);
4509         g_supplicant_interface_set_p2p_device_config(interface,
4510                                                         hostname, dev_type);
4511         connman_peer_driver_register(&peer_driver);
4512 }
4513
4514 static void scan_started(GSupplicantInterface *interface)
4515 {
4516         DBG("");
4517 }
4518
4519 static void scan_finished(GSupplicantInterface *interface)
4520 {
4521 #if defined TIZEN_EXT
4522         struct wifi_data *wifi;
4523         bool is_associating = false;
4524         static bool is_scanning = true;
4525 #endif
4526
4527         DBG("");
4528
4529 #if defined TIZEN_EXT
4530         wifi = g_supplicant_interface_get_data(interface);
4531         if (wifi && wifi->scan_pending_network) {
4532                 network_connect(wifi->scan_pending_network);
4533                 wifi->scan_pending_network = NULL;
4534         }
4535
4536         //service state - associating
4537         if(!wifi || !wifi->network)
4538                 return;
4539
4540         is_associating = connman_network_get_associating(wifi->network);
4541         if(is_associating && is_scanning){
4542                 is_scanning = false;
4543                 DBG("send scan for connecting");
4544                 throw_wifi_scan(wifi->device, scan_callback);
4545
4546                 return;
4547         }
4548         is_scanning = true;
4549
4550         //go scan
4551
4552 #endif
4553 }
4554
4555 static void ap_create_fail(GSupplicantInterface *interface)
4556 {
4557         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
4558         int ret;
4559
4560         if ((wifi->tethering) && (wifi->tethering_param)) {
4561                 DBG("%s create AP fail \n",
4562                                 g_supplicant_interface_get_ifname(wifi->interface));
4563
4564                 connman_inet_remove_from_bridge(wifi->index, wifi->bridge);
4565                 wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
4566                 wifi->tethering = false;
4567
4568                 ret = tech_set_tethering(wifi->tethering_param->technology,
4569                                 wifi->tethering_param->ssid->ssid,
4570                                 wifi->tethering_param->ssid->passphrase,
4571                                 wifi->bridge, true);
4572
4573                 if ((ret == -EOPNOTSUPP) && (wifi_technology)) {
4574                         connman_technology_tethering_notify(wifi_technology,false);
4575                 }
4576
4577                 g_free(wifi->tethering_param->ssid);
4578                 g_free(wifi->tethering_param);
4579                 wifi->tethering_param = NULL;
4580         }
4581 }
4582
4583 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
4584 {
4585         unsigned char strength;
4586
4587         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
4588 #if !defined TIZEN_EXT
4589         if (strength > 100)
4590                 strength = 100;
4591 #endif
4592
4593         return strength;
4594 }
4595
4596 #if defined TIZEN_EXT_WIFI_MESH
4597 static void mesh_peer_added(GSupplicantNetwork *supplicant_network)
4598 {
4599         GSupplicantInterface *interface;
4600         struct wifi_data *wifi;
4601         const char *name, *security;
4602         struct connman_mesh *connman_mesh;
4603         struct wifi_mesh_info *mesh_info;
4604         const unsigned char *bssid;
4605         const char *identifier;
4606         char *address;
4607         uint16_t frequency;
4608         int ret;
4609
4610         interface = g_supplicant_network_get_interface(supplicant_network);
4611         wifi = g_supplicant_interface_get_data(interface);
4612         if (!wifi || !wifi->mesh_interface) {
4613                 DBG("Virtual Mesh interface not created");
4614                 return;
4615         }
4616
4617         bssid = g_supplicant_network_get_bssid(supplicant_network);
4618         address = g_malloc0(19);
4619         snprintf(address, 19, "%02x:%02x:%02x:%02x:%02x:%02x", bssid[0], bssid[1],
4620                                                                  bssid[2], bssid[3], bssid[4], bssid[5]);
4621
4622         identifier = g_supplicant_network_get_identifier(supplicant_network);
4623         name = g_supplicant_network_get_name(supplicant_network);
4624         security = g_supplicant_network_get_security(supplicant_network);
4625         frequency = g_supplicant_network_get_frequency(supplicant_network);
4626
4627         mesh_info = wifi->mesh_info;
4628         connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
4629         if (connman_mesh)
4630                 goto done;
4631
4632         DBG("Mesh Peer name %s identifier %s security %s added", name, identifier,
4633                                         security);
4634         connman_mesh = connman_mesh_create(mesh_info->identifier, identifier);
4635         connman_mesh_set_name(connman_mesh, name);
4636         connman_mesh_set_security(connman_mesh, security);
4637         connman_mesh_set_frequency(connman_mesh, frequency);
4638         connman_mesh_set_address(connman_mesh, address);
4639         connman_mesh_set_index(connman_mesh, mesh_info->index);
4640         connman_mesh_set_strength(connman_mesh,
4641                                                 calculate_strength(supplicant_network));
4642         connman_mesh_set_peer_type(connman_mesh, CONNMAN_MESH_PEER_TYPE_DISCOVERED);
4643
4644         ret = connman_mesh_register(connman_mesh);
4645         if (ret == -EALREADY)
4646                 DBG("Mesh Peer is already registered");
4647
4648 done:
4649         g_free(address);
4650 }
4651
4652 static void mesh_peer_removed(GSupplicantNetwork *supplicant_network)
4653 {
4654         GSupplicantInterface *interface;
4655         struct wifi_data *wifi;
4656         struct connman_mesh *connman_mesh;
4657         struct wifi_mesh_info *mesh_info;
4658         const char *identifier;
4659
4660         interface = g_supplicant_network_get_interface(supplicant_network);
4661         wifi = g_supplicant_interface_get_data(interface);
4662         if (!wifi || !wifi->mesh_interface) {
4663                 DBG("Virtual Mesh interface not created");
4664                 return;
4665         }
4666
4667         identifier = g_supplicant_network_get_identifier(supplicant_network);
4668         if (!identifier) {
4669                 DBG("Failed to get Mesh Peer identifier");
4670                 return;
4671         }
4672
4673         mesh_info = wifi->mesh_info;
4674         connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
4675         if (connman_mesh) {
4676                 /* Do not unregister connected mesh peer */
4677                 if (connman_mesh_peer_is_connected_state(connman_mesh)) {
4678                         DBG("Mesh Peer %s is connected", identifier);
4679                         return;
4680                 }
4681                 DBG("Mesh Peer identifier %s removed", identifier);
4682                 connman_mesh_unregister(connman_mesh);
4683         }
4684 }
4685 #endif
4686
4687 static void network_added(GSupplicantNetwork *supplicant_network)
4688 {
4689         struct connman_network *network;
4690         GSupplicantInterface *interface;
4691         struct wifi_data *wifi;
4692         const char *name, *identifier, *security, *group, *mode;
4693         const unsigned char *ssid;
4694         unsigned int ssid_len;
4695         bool wps;
4696         bool wps_pbc;
4697         bool wps_ready;
4698         bool wps_advertizing;
4699
4700 #if defined TIZEN_EXT
4701         GSList *vsie_list = NULL;
4702         const unsigned char *country_code;
4703         ieee80211_modes_e phy_mode;
4704 #endif
4705
4706         mode = g_supplicant_network_get_mode(supplicant_network);
4707         identifier = g_supplicant_network_get_identifier(supplicant_network);
4708
4709         DBG("%s", identifier);
4710
4711         if (!g_strcmp0(mode, "adhoc"))
4712                 return;
4713
4714 #if defined TIZEN_EXT_WIFI_MESH
4715         if (!g_strcmp0(mode, "mesh")) {
4716                 mesh_peer_added(supplicant_network);
4717                 return;
4718         }
4719 #endif
4720
4721         interface = g_supplicant_network_get_interface(supplicant_network);
4722         wifi = g_supplicant_interface_get_data(interface);
4723         name = g_supplicant_network_get_name(supplicant_network);
4724         security = g_supplicant_network_get_security(supplicant_network);
4725         group = g_supplicant_network_get_identifier(supplicant_network);
4726         wps = g_supplicant_network_get_wps(supplicant_network);
4727         wps_pbc = g_supplicant_network_is_wps_pbc(supplicant_network);
4728         wps_ready = g_supplicant_network_is_wps_active(supplicant_network);
4729         wps_advertizing = g_supplicant_network_is_wps_advertizing(
4730                                                         supplicant_network);
4731
4732         if (!wifi)
4733                 return;
4734
4735         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
4736
4737         network = connman_device_get_network(wifi->device, identifier);
4738
4739         if (!network) {
4740                 network = connman_network_create(identifier,
4741                                                 CONNMAN_NETWORK_TYPE_WIFI);
4742                 if (!network)
4743                         return;
4744
4745                 connman_network_set_index(network, wifi->index);
4746
4747                 if (connman_device_add_network(wifi->device, network) < 0) {
4748                         connman_network_unref(network);
4749                         return;
4750                 }
4751
4752                 wifi->networks = g_slist_prepend(wifi->networks, network);
4753         }
4754
4755         if (name && name[0] != '\0')
4756                 connman_network_set_name(network, name);
4757
4758         connman_network_set_blob(network, "WiFi.SSID",
4759                                                 ssid, ssid_len);
4760 #if defined TIZEN_EXT
4761         vsie_list = (GSList *)g_supplicant_network_get_wifi_vsie(supplicant_network);
4762         if (vsie_list)
4763                 connman_network_set_vsie_list(network, vsie_list);
4764         else
4765                 DBG("vsie_list is NULL");
4766         country_code = g_supplicant_network_get_countrycode(supplicant_network);
4767         connman_network_set_countrycode(network, country_code);
4768         phy_mode = g_supplicant_network_get_phy_mode(supplicant_network);
4769         connman_network_set_phy_mode(network, phy_mode);
4770 #endif
4771         connman_network_set_string(network, "WiFi.Security", security);
4772         connman_network_set_strength(network,
4773                                 calculate_strength(supplicant_network));
4774         connman_network_set_bool(network, "WiFi.WPS", wps);
4775         connman_network_set_bool(network, "WiFi.WPSAdvertising",
4776                                 wps_advertizing);
4777
4778         if (wps) {
4779                 /* Is AP advertizing for WPS association?
4780                  * If so, we decide to use WPS by default */
4781                 if (wps_ready && wps_pbc &&
4782                                                 wps_advertizing)
4783 #if !defined TIZEN_EXT
4784                         connman_network_set_bool(network, "WiFi.UseWPS", true);
4785 #else
4786                         DBG("wps is activating by ap but ignore it.");
4787 #endif
4788         }
4789
4790         connman_network_set_frequency(network,
4791                         g_supplicant_network_get_frequency(supplicant_network));
4792
4793 #if defined TIZEN_EXT
4794         connman_network_set_bssid(network,
4795                         g_supplicant_network_get_bssid(supplicant_network));
4796         connman_network_set_maxrate(network,
4797                         g_supplicant_network_get_maxrate(supplicant_network));
4798         connman_network_set_enc_mode(network,
4799                         g_supplicant_network_get_enc_mode(supplicant_network));
4800         connman_network_set_rsn_mode(network,
4801                         g_supplicant_network_get_rsn_mode(supplicant_network));
4802         connman_network_set_keymgmt(network,
4803                         g_supplicant_network_get_keymgmt(supplicant_network));
4804         connman_network_set_bool(network, "WiFi.HS20AP",
4805                         g_supplicant_network_is_hs20AP(supplicant_network));
4806         connman_network_set_bssid_list(network,
4807                         (GSList *)g_supplicant_network_get_bssid_list(supplicant_network));
4808 #endif
4809         connman_network_set_available(network, true);
4810         connman_network_set_string(network, "WiFi.Mode", mode);
4811
4812 #if defined TIZEN_EXT
4813         if (group)
4814 #else
4815         if (ssid)
4816 #endif
4817                 connman_network_set_group(network, group);
4818
4819 #if defined TIZEN_EXT
4820         if (wifi_first_scan == true)
4821                 found_with_first_scan = true;
4822 #endif
4823
4824         if (wifi->hidden && ssid) {
4825 #if defined TIZEN_EXT
4826                 if (network_security(wifi->hidden->security) ==
4827                         network_security(security) &&
4828 #else
4829                 if (!g_strcmp0(wifi->hidden->security, security) &&
4830 #endif
4831                                 wifi->hidden->ssid_len == ssid_len &&
4832                                 !memcmp(wifi->hidden->ssid, ssid, ssid_len)) {
4833                         connman_network_connect_hidden(network,
4834                                         wifi->hidden->identity,
4835                                         wifi->hidden->passphrase,
4836                                         wifi->hidden->user_data);
4837                         wifi->hidden->user_data = NULL;
4838                         hidden_free(wifi->hidden);
4839                         wifi->hidden = NULL;
4840                 }
4841         }
4842 }
4843
4844 static void network_removed(GSupplicantNetwork *network)
4845 {
4846         GSupplicantInterface *interface;
4847         struct wifi_data *wifi;
4848         const char *name, *identifier;
4849         struct connman_network *connman_network;
4850
4851 #if defined TIZEN_EXT_WIFI_MESH
4852         const char *mode;
4853         mode = g_supplicant_network_get_mode(network);
4854         if (!g_strcmp0(mode, "mesh")) {
4855                 mesh_peer_removed(network);
4856                 return;
4857         }
4858 #endif
4859
4860         interface = g_supplicant_network_get_interface(network);
4861         wifi = g_supplicant_interface_get_data(interface);
4862         identifier = g_supplicant_network_get_identifier(network);
4863         name = g_supplicant_network_get_name(network);
4864
4865         DBG("name %s", name);
4866
4867         if (!wifi)
4868                 return;
4869
4870         connman_network = connman_device_get_network(wifi->device, identifier);
4871         if (!connman_network)
4872                 return;
4873
4874 #if defined TIZEN_EXT
4875         if (connman_network == wifi->scan_pending_network)
4876                 wifi->scan_pending_network = NULL;
4877
4878         if (connman_network == wifi->pending_network)
4879                 wifi->pending_network = NULL;
4880
4881         if(connman_network_get_connecting(connman_network) == true){
4882                 connman_network_set_connected(connman_network, false);
4883         }
4884 #endif
4885
4886         wifi->networks = g_slist_remove(wifi->networks, connman_network);
4887
4888         connman_device_remove_network(wifi->device, connman_network);
4889         connman_network_unref(connman_network);
4890 }
4891
4892 static void network_changed(GSupplicantNetwork *network, const char *property)
4893 {
4894         GSupplicantInterface *interface;
4895         struct wifi_data *wifi;
4896         const char *name, *identifier;
4897         struct connman_network *connman_network;
4898         bool update_needed;
4899
4900 #if defined TIZEN_EXT
4901         const unsigned char *bssid;
4902         unsigned int maxrate;
4903         uint16_t frequency;
4904         bool wps;
4905         const unsigned char *country_code;
4906         ieee80211_modes_e phy_mode;
4907         GSList *bssid_list;
4908 #endif
4909
4910         interface = g_supplicant_network_get_interface(network);
4911         wifi = g_supplicant_interface_get_data(interface);
4912         identifier = g_supplicant_network_get_identifier(network);
4913         name = g_supplicant_network_get_name(network);
4914
4915         DBG("name %s", name);
4916
4917         if (!wifi)
4918                 return;
4919
4920         connman_network = connman_device_get_network(wifi->device, identifier);
4921         if (!connman_network)
4922                 return;
4923
4924         if (g_str_equal(property, "WPSCapabilities")) {
4925                 bool wps;
4926                 bool wps_pbc;
4927                 bool wps_ready;
4928                 bool wps_advertizing;
4929
4930                 wps = g_supplicant_network_get_wps(network);
4931                 wps_pbc = g_supplicant_network_is_wps_pbc(network);
4932                 wps_ready = g_supplicant_network_is_wps_active(network);
4933                 wps_advertizing =
4934                         g_supplicant_network_is_wps_advertizing(network);
4935
4936                 connman_network_set_bool(connman_network, "WiFi.WPS", wps);
4937                 connman_network_set_bool(connman_network,
4938                                 "WiFi.WPSAdvertising", wps_advertizing);
4939
4940                 if (wps) {
4941                         /*
4942                          * Is AP advertizing for WPS association?
4943                          * If so, we decide to use WPS by default
4944                          */
4945                         if (wps_ready && wps_pbc && wps_advertizing)
4946                                 connman_network_set_bool(connman_network,
4947                                                         "WiFi.UseWPS", true);
4948                 }
4949
4950                 update_needed = true;
4951         } else if (g_str_equal(property, "Signal")) {
4952                 connman_network_set_strength(connman_network,
4953                                         calculate_strength(network));
4954                 update_needed = true;
4955         } else
4956                 update_needed = false;
4957
4958         if (update_needed)
4959                 connman_network_update(connman_network);
4960
4961 #if defined TIZEN_EXT
4962         bssid = g_supplicant_network_get_bssid(network);
4963         maxrate = g_supplicant_network_get_maxrate(network);
4964         frequency = g_supplicant_network_get_frequency(network);
4965         wps = g_supplicant_network_get_wps(network);
4966         phy_mode = g_supplicant_network_get_phy_mode(network);
4967
4968         connman_network_set_bssid(connman_network, bssid);
4969         connman_network_set_maxrate(connman_network, maxrate);
4970         connman_network_set_frequency(connman_network, frequency);
4971         connman_network_set_bool(connman_network, "WiFi.WPS", wps);
4972         country_code = g_supplicant_network_get_countrycode(network);
4973         connman_network_set_countrycode(connman_network, country_code);
4974         bssid_list = (GSList *)g_supplicant_network_get_bssid_list(network);
4975         connman_network_set_bssid_list(connman_network, bssid_list);
4976         connman_network_set_phy_mode(connman_network, phy_mode);
4977
4978         if (g_str_equal(property, "CheckMultiBssidConnect") &&
4979                         connman_network_get_associating(connman_network))
4980                 network_connect(connman_network);
4981 #endif
4982 }
4983
4984 static void network_associated(GSupplicantNetwork *network)
4985 {
4986         GSupplicantInterface *interface;
4987         struct wifi_data *wifi;
4988         struct connman_network *connman_network;
4989         const char *identifier;
4990
4991         DBG("");
4992
4993         interface = g_supplicant_network_get_interface(network);
4994         if (!interface)
4995                 return;
4996
4997         wifi = g_supplicant_interface_get_data(interface);
4998         if (!wifi)
4999                 return;
5000
5001         /* P2P networks must not be treated as WiFi networks */
5002         if (wifi->p2p_connecting || wifi->p2p_device)
5003                 return;
5004
5005         identifier = g_supplicant_network_get_identifier(network);
5006
5007         connman_network = connman_device_get_network(wifi->device, identifier);
5008         if (!connman_network)
5009                 return;
5010
5011         if (wifi->network) {
5012                 if (wifi->network == connman_network)
5013                         return;
5014
5015                 /*
5016                  * This should never happen, we got associated with
5017                  * a network different than the one we were expecting.
5018                  */
5019                 DBG("Associated to %p while expecting %p",
5020                                         connman_network, wifi->network);
5021
5022                 connman_network_set_associating(wifi->network, false);
5023         }
5024
5025         DBG("Reconnecting to previous network %p from wpa_s", connman_network);
5026
5027         wifi->network = connman_network_ref(connman_network);
5028         wifi->retries = 0;
5029
5030         /*
5031          * Interface state changes callback (interface_state) is always
5032          * called before network_associated callback thus we need to call
5033          * interface_state again in order to process the new state now that
5034          * we have the network properly set.
5035          */
5036         interface_state(interface);
5037 }
5038
5039 static void sta_authorized(GSupplicantInterface *interface,
5040                                         const char *addr)
5041 {
5042         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5043
5044         DBG("wifi %p station %s authorized", wifi, addr);
5045
5046         if (!wifi || !wifi->tethering)
5047                 return;
5048
5049         __connman_tethering_client_register(addr);
5050 }
5051
5052 static void sta_deauthorized(GSupplicantInterface *interface,
5053                                         const char *addr)
5054 {
5055         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5056
5057         DBG("wifi %p station %s deauthorized", wifi, addr);
5058
5059         if (!wifi || !wifi->tethering)
5060                 return;
5061
5062         __connman_tethering_client_unregister(addr);
5063 }
5064
5065 static void apply_peer_services(GSupplicantPeer *peer,
5066                                 struct connman_peer *connman_peer)
5067 {
5068         const unsigned char *data;
5069         int length;
5070
5071         DBG("");
5072
5073         connman_peer_reset_services(connman_peer);
5074
5075         data = g_supplicant_peer_get_widi_ies(peer, &length);
5076         if (data) {
5077                 connman_peer_add_service(connman_peer,
5078                         CONNMAN_PEER_SERVICE_WIFI_DISPLAY, data, length);
5079         }
5080 }
5081
5082 static void peer_found(GSupplicantPeer *peer)
5083 {
5084         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
5085         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
5086         struct connman_peer *connman_peer;
5087         const char *identifier, *name;
5088         int ret;
5089
5090 #if defined TIZEN_EXT
5091         if (!wifi)
5092                 return;
5093 #endif
5094         identifier = g_supplicant_peer_get_identifier(peer);
5095         name = g_supplicant_peer_get_name(peer);
5096
5097         DBG("ident: %s", identifier);
5098
5099         connman_peer = connman_peer_get(wifi->device, identifier);
5100         if (connman_peer)
5101                 return;
5102
5103         connman_peer = connman_peer_create(identifier);
5104         connman_peer_set_name(connman_peer, name);
5105         connman_peer_set_device(connman_peer, wifi->device);
5106         apply_peer_services(peer, connman_peer);
5107
5108         ret = connman_peer_register(connman_peer);
5109         if (ret < 0 && ret != -EALREADY)
5110                 connman_peer_unref(connman_peer);
5111         else
5112                 wifi->peers = g_slist_prepend(wifi->peers, connman_peer);
5113 }
5114
5115 static void peer_lost(GSupplicantPeer *peer)
5116 {
5117         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
5118         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
5119         struct connman_peer *connman_peer;
5120         const char *identifier;
5121
5122         if (!wifi)
5123                 return;
5124
5125         identifier = g_supplicant_peer_get_identifier(peer);
5126
5127         DBG("ident: %s", identifier);
5128
5129         connman_peer = connman_peer_get(wifi->device, identifier);
5130         if (connman_peer) {
5131                 if (wifi->p2p_connecting &&
5132                                 wifi->pending_peer == connman_peer) {
5133                         peer_connect_timeout(wifi);
5134                 }
5135                 connman_peer_unregister(connman_peer);
5136                 connman_peer_unref(connman_peer);
5137         }
5138
5139         wifi->peers = g_slist_remove(wifi->peers, connman_peer);
5140 }
5141
5142 static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state)
5143 {
5144         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
5145         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
5146         enum connman_peer_state p_state = CONNMAN_PEER_STATE_UNKNOWN;
5147         struct connman_peer *connman_peer;
5148         const char *identifier;
5149
5150         identifier = g_supplicant_peer_get_identifier(peer);
5151
5152         DBG("ident: %s", identifier);
5153
5154         if (!wifi)
5155                 return;
5156
5157         connman_peer = connman_peer_get(wifi->device, identifier);
5158         if (!connman_peer)
5159                 return;
5160
5161         switch (state) {
5162         case G_SUPPLICANT_PEER_SERVICES_CHANGED:
5163                 apply_peer_services(peer, connman_peer);
5164                 connman_peer_services_changed(connman_peer);
5165                 return;
5166         case G_SUPPLICANT_PEER_GROUP_CHANGED:
5167                 if (!g_supplicant_peer_is_in_a_group(peer))
5168                         p_state = CONNMAN_PEER_STATE_IDLE;
5169                 else
5170                         p_state = CONNMAN_PEER_STATE_CONFIGURATION;
5171                 break;
5172         case G_SUPPLICANT_PEER_GROUP_STARTED:
5173                 break;
5174         case G_SUPPLICANT_PEER_GROUP_FINISHED:
5175                 p_state = CONNMAN_PEER_STATE_IDLE;
5176                 break;
5177         case G_SUPPLICANT_PEER_GROUP_JOINED:
5178                 connman_peer_set_iface_address(connman_peer,
5179                                 g_supplicant_peer_get_iface_address(peer));
5180                 break;
5181         case G_SUPPLICANT_PEER_GROUP_DISCONNECTED:
5182                 p_state = CONNMAN_PEER_STATE_IDLE;
5183                 break;
5184         case G_SUPPLICANT_PEER_GROUP_FAILED:
5185                 if (g_supplicant_peer_has_requested_connection(peer))
5186                         p_state = CONNMAN_PEER_STATE_IDLE;
5187                 else
5188                         p_state = CONNMAN_PEER_STATE_FAILURE;
5189                 break;
5190         }
5191
5192         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION ||
5193                                         p_state == CONNMAN_PEER_STATE_FAILURE) {
5194                 if (wifi->p2p_connecting
5195                                 && connman_peer == wifi->pending_peer)
5196                         peer_cancel_timeout(wifi);
5197                 else
5198                         p_state = CONNMAN_PEER_STATE_UNKNOWN;
5199         }
5200
5201         if (p_state == CONNMAN_PEER_STATE_UNKNOWN)
5202                 return;
5203
5204         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION) {
5205                 GSupplicantInterface *g_iface;
5206                 struct wifi_data *g_wifi;
5207
5208                 g_iface = g_supplicant_peer_get_group_interface(peer);
5209                 if (!g_iface)
5210                         return;
5211
5212                 g_wifi = g_supplicant_interface_get_data(g_iface);
5213                 if (!g_wifi)
5214                         return;
5215
5216                 connman_peer_set_as_master(connman_peer,
5217                                         !g_supplicant_peer_is_client(peer));
5218                 connman_peer_set_sub_device(connman_peer, g_wifi->device);
5219
5220                 /*
5221                  * If wpa_supplicant didn't create a dedicated p2p-group
5222                  * interface then mark this interface as p2p_device to avoid
5223                  * scan and auto-scan are launched on it while P2P is connected.
5224                  */
5225                 if (!g_list_find(p2p_iface_list, g_wifi))
5226                         wifi->p2p_device = true;
5227         }
5228
5229         connman_peer_set_state(connman_peer, p_state);
5230 }
5231
5232 static void peer_request(GSupplicantPeer *peer)
5233 {
5234         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
5235         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
5236         struct connman_peer *connman_peer;
5237         const char *identifier;
5238
5239 #if defined TIZEN_EXT
5240         if (!wifi)
5241                 return;
5242 #endif
5243
5244         identifier = g_supplicant_peer_get_identifier(peer);
5245
5246         DBG("ident: %s", identifier);
5247
5248         connman_peer = connman_peer_get(wifi->device, identifier);
5249         if (!connman_peer)
5250                 return;
5251
5252         connman_peer_request_connection(connman_peer);
5253 }
5254
5255 #if defined TIZEN_EXT
5256 static void system_power_off(void)
5257 {
5258         GList *list;
5259         struct wifi_data *wifi;
5260         struct connman_service *service;
5261         struct connman_ipconfig *ipconfig_ipv4;
5262
5263         if (connman_setting_get_bool("WiFiDHCPRelease") == true) {
5264                 for (list = iface_list; list; list = list->next) {
5265                         wifi = list->data;
5266
5267                         if (wifi->network != NULL) {
5268                                 service = connman_service_lookup_from_network(wifi->network);
5269                                 ipconfig_ipv4 = __connman_service_get_ip4config(service);
5270                                 __connman_dhcp_stop(ipconfig_ipv4);
5271                         }
5272                 }
5273         }
5274 }
5275
5276 static void network_merged(GSupplicantNetwork *network)
5277 {
5278         GSupplicantInterface *interface;
5279         GSupplicantState state;
5280         struct wifi_data *wifi;
5281         const char *identifier;
5282         struct connman_network *connman_network;
5283         bool ishs20AP = 0;
5284         char *temp = NULL;
5285
5286         interface = g_supplicant_network_get_interface(network);
5287         if (!interface)
5288                 return;
5289
5290         state = g_supplicant_interface_get_state(interface);
5291         if (state < G_SUPPLICANT_STATE_AUTHENTICATING)
5292                 return;
5293
5294         wifi = g_supplicant_interface_get_data(interface);
5295         if (!wifi)
5296                 return;
5297
5298         identifier = g_supplicant_network_get_identifier(network);
5299
5300         connman_network = connman_device_get_network(wifi->device, identifier);
5301         if (!connman_network)
5302                 return;
5303
5304         DBG("merged identifier %s", identifier);
5305
5306         if (wifi->connected == FALSE) {
5307                 switch (state) {
5308                 case G_SUPPLICANT_STATE_AUTHENTICATING:
5309                 case G_SUPPLICANT_STATE_ASSOCIATING:
5310                 case G_SUPPLICANT_STATE_ASSOCIATED:
5311                 case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
5312                 case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
5313                         connman_network_set_associating(connman_network, TRUE);
5314                         break;
5315                 case G_SUPPLICANT_STATE_COMPLETED:
5316                         connman_network_set_connected(connman_network, TRUE);
5317                         break;
5318                 default:
5319                         DBG("Not handled the state : %d", state);
5320                         break;
5321                 }
5322         }
5323
5324         ishs20AP = g_supplicant_network_is_hs20AP(network);
5325
5326         if (ishs20AP &&
5327                 g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) {
5328                 temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1);
5329                 connman_network_set_string(connman_network, "WiFi.EAP",
5330                                 temp);
5331                 connman_network_set_string(connman_network, "WiFi.Identity",
5332                                 g_supplicant_network_get_identity(network));
5333                 connman_network_set_string(connman_network, "WiFi.Phase2",
5334                                 g_supplicant_network_get_phase2(network));
5335
5336                 g_free(temp);
5337         }
5338
5339         wifi->network = connman_network;
5340 }
5341
5342 static void assoc_failed(void *user_data)
5343 {
5344         struct connman_network *network = user_data;
5345         connman_network_set_associating(network, false);
5346 }
5347
5348 static void scan_done(GSupplicantInterface *interface)
5349 {
5350         GList *list;
5351         int scan_type = CONNMAN_SCAN_TYPE_WPA_SUPPLICANT;
5352         struct wifi_data *wifi;
5353         bool scanning;
5354
5355         for (list = iface_list; list; list = list->next) {
5356                 wifi = list->data;
5357
5358                 if (interface == wifi->interface) {
5359                         scanning = connman_device_get_scanning(wifi->device,
5360                                         CONNMAN_SERVICE_TYPE_WIFI);
5361                         if (!scanning)
5362                                 __connman_technology_notify_scan_done(scan_type);
5363                         break;
5364                 }
5365         }
5366 }
5367 #endif
5368
5369 static void debug(const char *str)
5370 {
5371         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
5372                 connman_debug("%s", str);
5373 }
5374
5375 static void disconnect_reasoncode(GSupplicantInterface *interface,
5376                                 int reasoncode)
5377 {
5378         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5379
5380         if (wifi != NULL) {
5381                 wifi->disconnect_code = reasoncode;
5382         }
5383 }
5384
5385 static void assoc_status_code(GSupplicantInterface *interface, int status_code)
5386 {
5387         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5388
5389         if (wifi != NULL) {
5390                 wifi->assoc_code = status_code;
5391         }
5392 }
5393
5394 static const GSupplicantCallbacks callbacks = {
5395         .system_ready           = system_ready,
5396         .system_killed          = system_killed,
5397         .interface_added        = interface_added,
5398         .interface_state        = interface_state,
5399         .interface_removed      = interface_removed,
5400         .p2p_support            = p2p_support,
5401         .scan_started           = scan_started,
5402         .scan_finished          = scan_finished,
5403         .ap_create_fail         = ap_create_fail,
5404         .network_added          = network_added,
5405         .network_removed        = network_removed,
5406         .network_changed        = network_changed,
5407         .network_associated     = network_associated,
5408         .sta_authorized         = sta_authorized,
5409         .sta_deauthorized       = sta_deauthorized,
5410         .peer_found             = peer_found,
5411         .peer_lost              = peer_lost,
5412         .peer_changed           = peer_changed,
5413         .peer_request           = peer_request,
5414 #if defined TIZEN_EXT
5415         .system_power_off       = system_power_off,
5416         .network_merged         = network_merged,
5417         .assoc_failed           = assoc_failed,
5418         .scan_done              = scan_done,
5419 #endif
5420         .debug                  = debug,
5421         .disconnect_reasoncode  = disconnect_reasoncode,
5422         .assoc_status_code      = assoc_status_code,
5423 #if defined TIZEN_EXT_WIFI_MESH
5424         .mesh_support           = mesh_support,
5425         .mesh_group_started = mesh_group_started,
5426         .mesh_group_removed = mesh_group_removed,
5427         .mesh_peer_connected = mesh_peer_connected,
5428         .mesh_peer_disconnected = mesh_peer_disconnected,
5429 #endif
5430 };
5431
5432
5433 static int tech_probe(struct connman_technology *technology)
5434 {
5435         wifi_technology = technology;
5436
5437         return 0;
5438 }
5439
5440 static void tech_remove(struct connman_technology *technology)
5441 {
5442         wifi_technology = NULL;
5443 }
5444
5445 static GSupplicantSSID *ssid_ap_init(const char *ssid, const char *passphrase)
5446 {
5447         GSupplicantSSID *ap;
5448
5449         ap = g_try_malloc0(sizeof(GSupplicantSSID));
5450         if (!ap)
5451                 return NULL;
5452
5453         ap->mode = G_SUPPLICANT_MODE_MASTER;
5454 #if defined TIZEN_EXT
5455         ap->ssid = (void *) ssid;
5456 #else
5457         ap->ssid = ssid;
5458 #endif
5459         ap->ssid_len = strlen(ssid);
5460         ap->scan_ssid = 0;
5461         ap->freq = 2412;
5462
5463         if (!passphrase || strlen(passphrase) == 0) {
5464                 ap->security = G_SUPPLICANT_SECURITY_NONE;
5465                 ap->passphrase = NULL;
5466         } else {
5467                ap->security = G_SUPPLICANT_SECURITY_PSK;
5468                ap->protocol = G_SUPPLICANT_PROTO_RSN;
5469                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
5470                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
5471                ap->passphrase = passphrase;
5472         }
5473
5474         return ap;
5475 }
5476
5477 static void ap_start_callback(int result, GSupplicantInterface *interface,
5478                                                         void *user_data)
5479 {
5480         struct wifi_tethering_info *info = user_data;
5481
5482         DBG("result %d index %d bridge %s",
5483                 result, info->wifi->index, info->wifi->bridge);
5484
5485         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
5486                 connman_inet_remove_from_bridge(info->wifi->index,
5487                                                         info->wifi->bridge);
5488
5489                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
5490                         connman_technology_tethering_notify(info->technology, false);
5491                         g_free(info->wifi->tethering_param->ssid);
5492                         g_free(info->wifi->tethering_param);
5493                         info->wifi->tethering_param = NULL;
5494                 }
5495         }
5496
5497         g_free(info->ifname);
5498         g_free(info);
5499 }
5500
5501 static void ap_create_callback(int result,
5502                                 GSupplicantInterface *interface,
5503                                         void *user_data)
5504 {
5505         struct wifi_tethering_info *info = user_data;
5506
5507         DBG("result %d ifname %s", result,
5508                                 g_supplicant_interface_get_ifname(interface));
5509
5510         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
5511                 connman_inet_remove_from_bridge(info->wifi->index,
5512                                                         info->wifi->bridge);
5513
5514                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
5515                         connman_technology_tethering_notify(info->technology, false);
5516                         g_free(info->wifi->tethering_param->ssid);
5517                         g_free(info->wifi->tethering_param);
5518                         info->wifi->tethering_param = NULL;
5519
5520                 }
5521
5522                 g_free(info->ifname);
5523                 g_free(info->ssid);
5524                 g_free(info);
5525                 return;
5526         }
5527
5528         info->wifi->interface = interface;
5529         g_supplicant_interface_set_data(interface, info->wifi);
5530
5531         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
5532                 connman_error("Failed to set interface ap_scan property");
5533
5534         g_supplicant_interface_connect(interface, info->ssid,
5535                                                 ap_start_callback, info);
5536 }
5537
5538 static void sta_remove_callback(int result,
5539                                 GSupplicantInterface *interface,
5540                                         void *user_data)
5541 {
5542         struct wifi_tethering_info *info = user_data;
5543         const char *driver = connman_option_get_string("wifi");
5544
5545         DBG("ifname %s result %d ", info->ifname, result);
5546
5547         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
5548                 info->wifi->tethering = false;
5549                 connman_technology_tethering_notify(info->technology, false);
5550
5551                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
5552                         g_free(info->wifi->tethering_param->ssid);
5553                         g_free(info->wifi->tethering_param);
5554                         info->wifi->tethering_param = NULL;
5555                 }
5556
5557                 g_free(info->ifname);
5558                 g_free(info->ssid);
5559                 g_free(info);
5560                 return;
5561         }
5562
5563         info->wifi->interface = NULL;
5564
5565         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
5566                                                 ap_create_callback,
5567                                                         info);
5568 }
5569
5570 static int enable_wifi_tethering(struct connman_technology *technology,
5571                                 const char *bridge, const char *identifier,
5572                                 const char *passphrase, bool available)
5573 {
5574         GList *list;
5575         GSupplicantInterface *interface;
5576         struct wifi_data *wifi;
5577         struct wifi_tethering_info *info;
5578         const char *ifname;
5579         unsigned int mode;
5580         int err, berr = 0;
5581
5582         for (list = iface_list; list; list = list->next) {
5583                 wifi = list->data;
5584
5585                 DBG("wifi %p network %p pending_network %p", wifi,
5586                         wifi->network, wifi->pending_network);
5587
5588                 interface = wifi->interface;
5589
5590                 if (!interface)
5591                         continue;
5592
5593                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
5594                 if (!ifname)
5595                         continue;
5596
5597                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED) {
5598                         DBG("%s does not support AP mode (detected)", ifname);
5599                         continue;
5600                 }
5601
5602                 mode = g_supplicant_interface_get_mode(interface);
5603                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
5604                         wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
5605                         DBG("%s does not support AP mode (capability)", ifname);
5606                         continue;
5607                 }
5608
5609                 if (wifi->network && available)
5610                         continue;
5611
5612                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
5613                 if (!info)
5614                         return -ENOMEM;
5615
5616                 wifi->tethering_param = g_try_malloc0(sizeof(struct wifi_tethering_info));
5617                 if (!wifi->tethering_param) {
5618                         g_free(info);
5619                         return -ENOMEM;
5620                 }
5621
5622                 info->wifi = wifi;
5623                 info->technology = technology;
5624                 info->wifi->bridge = bridge;
5625                 info->ssid = ssid_ap_init(identifier, passphrase);
5626                 if (!info->ssid)
5627                         goto failed;
5628
5629                 info->ifname = g_strdup(ifname);
5630
5631                 wifi->tethering_param->technology = technology;
5632                 wifi->tethering_param->ssid = ssid_ap_init(identifier, passphrase);
5633                 if (!wifi->tethering_param->ssid)
5634                         goto failed;
5635
5636                 info->wifi->tethering = true;
5637                 info->wifi->ap_supported = WIFI_AP_SUPPORTED;
5638
5639                 berr = connman_technology_tethering_notify(technology, true);
5640                 if (berr < 0)
5641                         goto failed;
5642
5643                 err = g_supplicant_interface_remove(interface,
5644                                                 sta_remove_callback,
5645                                                         info);
5646                 if (err >= 0) {
5647                         DBG("tethering wifi %p ifname %s", wifi, ifname);
5648                         return 0;
5649                 }
5650
5651         failed:
5652                 g_free(info->ifname);
5653                 g_free(info->ssid);
5654                 g_free(info);
5655                 g_free(wifi->tethering_param);
5656                 wifi->tethering_param = NULL;
5657
5658                 /*
5659                  * Remove bridge if it was correctly created but remove
5660                  * operation failed. Instead, if bridge creation failed then
5661                  * break out and do not try again on another interface,
5662                  * bridge set-up does not depend on it.
5663                  */
5664                 if (berr == 0)
5665                         connman_technology_tethering_notify(technology, false);
5666                 else
5667                         break;
5668         }
5669
5670         return -EOPNOTSUPP;
5671 }
5672
5673 static int tech_set_tethering(struct connman_technology *technology,
5674                                 const char *identifier, const char *passphrase,
5675                                 const char *bridge, bool enabled)
5676 {
5677         GList *list;
5678         struct wifi_data *wifi;
5679         int err;
5680
5681         DBG("");
5682
5683         if (!enabled) {
5684                 for (list = iface_list; list; list = list->next) {
5685                         wifi = list->data;
5686
5687                         if (wifi->tethering) {
5688                                 wifi->tethering = false;
5689
5690                                 connman_inet_remove_from_bridge(wifi->index,
5691                                                                         bridge);
5692                                 wifi->bridged = false;
5693                         }
5694                 }
5695
5696                 connman_technology_tethering_notify(technology, false);
5697
5698                 return 0;
5699         }
5700
5701         DBG("trying tethering for available devices");
5702         err = enable_wifi_tethering(technology, bridge, identifier, passphrase,
5703                                 true);
5704
5705         if (err < 0) {
5706                 DBG("trying tethering for any device");
5707                 err = enable_wifi_tethering(technology, bridge, identifier,
5708                                         passphrase, false);
5709         }
5710
5711         return err;
5712 }
5713
5714 static void regdom_callback(int result, const char *alpha2, void *user_data)
5715 {
5716         DBG("");
5717
5718         if (!wifi_technology)
5719                 return;
5720
5721         if (result != 0)
5722                 alpha2 = NULL;
5723
5724         connman_technology_regdom_notify(wifi_technology, alpha2);
5725 }
5726
5727 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
5728 {
5729         return g_supplicant_set_country(alpha2, regdom_callback, NULL);
5730 }
5731
5732 static struct connman_technology_driver tech_driver = {
5733         .name           = "wifi",
5734         .type           = CONNMAN_SERVICE_TYPE_WIFI,
5735         .probe          = tech_probe,
5736         .remove         = tech_remove,
5737         .set_tethering  = tech_set_tethering,
5738         .set_regdom     = tech_set_regdom,
5739 };
5740
5741 static int wifi_init(void)
5742 {
5743         int err;
5744
5745         err = connman_network_driver_register(&network_driver);
5746         if (err < 0)
5747                 return err;
5748
5749         err = g_supplicant_register(&callbacks);
5750         if (err < 0) {
5751                 connman_network_driver_unregister(&network_driver);
5752                 return err;
5753         }
5754
5755         err = connman_technology_driver_register(&tech_driver);
5756         if (err < 0) {
5757                 g_supplicant_unregister(&callbacks);
5758                 connman_network_driver_unregister(&network_driver);
5759                 return err;
5760         }
5761
5762 #if defined TIZEN_EXT
5763         failed_bssids = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
5764 #endif
5765         return 0;
5766 }
5767
5768 static void wifi_exit(void)
5769 {
5770         DBG();
5771
5772         connman_technology_driver_unregister(&tech_driver);
5773
5774         g_supplicant_unregister(&callbacks);
5775
5776         connman_network_driver_unregister(&network_driver);
5777
5778 #if defined TIZEN_EXT
5779         g_hash_table_unref(failed_bssids);
5780 #endif
5781 }
5782
5783 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
5784                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)