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