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