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