Merge "Add OWE security mode support" into tizen
[platform/upstream/connman.git] / plugins / wifi.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2014  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <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, void *user_data)
3623 {
3624         struct connman_network *network = user_data;
3625
3626         if (result != 0) {
3627                 DBG("Failed to get maxspeed from signalpoll !");
3628                 return;
3629         }
3630
3631         DBG("maxspeed = %d", maxspeed);
3632         if (network) {
3633                 connman_network_set_maxspeed(network, maxspeed);
3634                 set_connection_mode(network, maxspeed);
3635         }
3636 }
3637
3638 static int network_signalpoll(struct wifi_data *wifi)
3639 {
3640         GSupplicantInterface *interface;
3641         struct connman_network *network;
3642
3643         if (!wifi || !wifi->network)
3644                 return -ENODEV;
3645
3646         interface = wifi->interface;
3647         network = wifi->network;
3648
3649         DBG("network %p", network);
3650
3651         return g_supplicant_interface_signalpoll(interface, signalpoll_callback, network);
3652 }
3653
3654 static gboolean autosignalpoll_timeout(gpointer data)
3655 {
3656         struct wifi_data *wifi = data;
3657
3658         if (!wifi || !wifi->automaxspeed_timeout) {
3659                 DBG("automaxspeed_timeout is found to be zero. i.e. currently in disconnected state. !!");
3660                 return FALSE;
3661         }
3662
3663         int ret = network_signalpoll(wifi);
3664         if (ret < 0) {
3665                 DBG("Fail to get max speed !!");
3666                 wifi->automaxspeed_timeout = 0;
3667                 return FALSE;
3668         }
3669
3670         return TRUE;
3671 }
3672 #endif
3673
3674 static struct connman_network_driver network_driver = {
3675         .name           = "wifi",
3676         .type           = CONNMAN_NETWORK_TYPE_WIFI,
3677         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
3678         .probe          = network_probe,
3679         .remove         = network_remove,
3680         .connect        = network_connect,
3681         .disconnect     = network_disconnect,
3682 };
3683
3684 static void interface_added(GSupplicantInterface *interface)
3685 {
3686         const char *ifname = g_supplicant_interface_get_ifname(interface);
3687         const char *driver = g_supplicant_interface_get_driver(interface);
3688 #if defined TIZEN_EXT
3689         bool is_5_0_ghz_supported = g_supplicant_interface_get_is_5_0_ghz_supported(interface);
3690 #endif
3691
3692         struct wifi_data *wifi;
3693
3694         wifi = g_supplicant_interface_get_data(interface);
3695         if (!wifi) {
3696                 wifi = get_pending_wifi_data(ifname);
3697                 if (!wifi)
3698                         return;
3699
3700                 wifi->interface = interface;
3701                 g_supplicant_interface_set_data(interface, wifi);
3702                 p2p_iface_list = g_list_append(p2p_iface_list, wifi);
3703                 wifi->p2p_device = true;
3704         }
3705
3706         DBG("ifname %s driver %s wifi %p tethering %d",
3707                         ifname, driver, wifi, wifi->tethering);
3708
3709         if (!wifi->device) {
3710                 connman_error("WiFi device not set");
3711                 return;
3712         }
3713
3714         connman_device_set_powered(wifi->device, true);
3715 #if defined TIZEN_EXT
3716         connman_techonology_wifi_set_5ghz_supported(wifi_technology, is_5_0_ghz_supported);
3717         /* Max number of SSIDs supported by wlan chipset that can be scanned */
3718         int max_scan_ssids = g_supplicant_interface_get_max_scan_ssids(interface);
3719         connman_techonology_set_max_scan_ssids(wifi_technology, max_scan_ssids);
3720 #endif
3721 }
3722
3723 static bool is_idle(struct wifi_data *wifi)
3724 {
3725         DBG("state %d", wifi->state);
3726
3727         switch (wifi->state) {
3728         case G_SUPPLICANT_STATE_UNKNOWN:
3729         case G_SUPPLICANT_STATE_DISABLED:
3730         case G_SUPPLICANT_STATE_DISCONNECTED:
3731         case G_SUPPLICANT_STATE_INACTIVE:
3732         case G_SUPPLICANT_STATE_SCANNING:
3733                 return true;
3734
3735         case G_SUPPLICANT_STATE_AUTHENTICATING:
3736         case G_SUPPLICANT_STATE_ASSOCIATING:
3737         case G_SUPPLICANT_STATE_ASSOCIATED:
3738         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3739         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3740         case G_SUPPLICANT_STATE_COMPLETED:
3741                 return false;
3742         }
3743
3744         return false;
3745 }
3746
3747 static bool is_idle_wps(GSupplicantInterface *interface,
3748                                                 struct wifi_data *wifi)
3749 {
3750         /* First, let's check if WPS processing did not went wrong */
3751         if (g_supplicant_interface_get_wps_state(interface) ==
3752                 G_SUPPLICANT_WPS_STATE_FAIL)
3753                 return false;
3754
3755         /* Unlike normal connection, being associated while processing wps
3756          * actually means that we are idling. */
3757         switch (wifi->state) {
3758         case G_SUPPLICANT_STATE_UNKNOWN:
3759         case G_SUPPLICANT_STATE_DISABLED:
3760         case G_SUPPLICANT_STATE_DISCONNECTED:
3761         case G_SUPPLICANT_STATE_INACTIVE:
3762         case G_SUPPLICANT_STATE_SCANNING:
3763         case G_SUPPLICANT_STATE_ASSOCIATED:
3764                 return true;
3765         case G_SUPPLICANT_STATE_AUTHENTICATING:
3766         case G_SUPPLICANT_STATE_ASSOCIATING:
3767         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3768         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3769         case G_SUPPLICANT_STATE_COMPLETED:
3770                 return false;
3771         }
3772
3773         return false;
3774 }
3775
3776 static bool handle_wps_completion(GSupplicantInterface *interface,
3777                                         struct connman_network *network,
3778                                         struct connman_device *device,
3779                                         struct wifi_data *wifi)
3780 {
3781         bool wps;
3782
3783         wps = connman_network_get_bool(network, "WiFi.UseWPS");
3784         if (wps) {
3785                 const unsigned char *ssid, *wps_ssid;
3786                 unsigned int ssid_len, wps_ssid_len;
3787                 const char *wps_key;
3788
3789                 /* Checking if we got associated with requested
3790                  * network */
3791                 ssid = connman_network_get_blob(network, "WiFi.SSID",
3792                                                 &ssid_len);
3793
3794                 wps_ssid = g_supplicant_interface_get_wps_ssid(
3795                         interface, &wps_ssid_len);
3796
3797                 if (!wps_ssid || wps_ssid_len != ssid_len ||
3798                                 memcmp(ssid, wps_ssid, ssid_len) != 0) {
3799                         connman_network_set_associating(network, false);
3800 #if defined TIZEN_EXT
3801                         g_supplicant_interface_disconnect(wifi->interface,
3802                                                 disconnect_callback, wifi->network);
3803
3804                         connman_network_set_bool(network, "WiFi.UseWPS", false);
3805                         connman_network_set_string(network, "WiFi.PinWPS", NULL);
3806 #else
3807                         g_supplicant_interface_disconnect(wifi->interface,
3808                                                 disconnect_callback, wifi);
3809 #endif
3810                         return false;
3811                 }
3812
3813                 wps_key = g_supplicant_interface_get_wps_key(interface);
3814 #if defined TIZEN_EXT
3815                 /* Check the passphrase and encrypt it
3816                  */
3817                  int ret;
3818                  gchar *passphrase = g_strdup(wps_key);
3819
3820                  connman_network_set_string(network, "WiFi.PinWPS", NULL);
3821
3822                  if (check_passphrase_ext(network, passphrase) < 0) {
3823                          DBG("[WPS] Invalid passphrase");
3824                          g_free(passphrase);
3825                          return true;
3826                  }
3827
3828                  ret = send_encryption_request(passphrase, network);
3829
3830                  g_free(passphrase);
3831
3832                  if (!ret)
3833                          DBG("[WPS] Encryption request succeeded");
3834                  else
3835                          DBG("[WPS] Encryption request failed %d", ret);
3836
3837 #else
3838                 connman_network_set_string(network, "WiFi.Passphrase",
3839                                         wps_key);
3840
3841                 connman_network_set_string(network, "WiFi.PinWPS", NULL);
3842 #endif
3843         }
3844
3845         return true;
3846 }
3847
3848 static bool handle_assoc_status_code(GSupplicantInterface *interface,
3849                                      struct wifi_data *wifi)
3850 {
3851         if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING &&
3852 #if defined TIZEN_EXT
3853                         wifi->assoc_code > 0 &&
3854 #else
3855                         wifi->assoc_code == ASSOC_STATUS_NO_CLIENT &&
3856 #endif
3857                         wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) {
3858                 wifi->load_shaping_retries ++;
3859                 return TRUE;
3860         }
3861         wifi->load_shaping_retries = 0;
3862         return FALSE;
3863 }
3864
3865 static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
3866                                         struct connman_network *network,
3867                                         struct wifi_data *wifi)
3868 {
3869 #if defined TIZEN_EXT
3870         const char *security;
3871         struct connman_service *service;
3872
3873         if (wifi->connected)
3874                 return false;
3875
3876         security = connman_network_get_string(network, "WiFi.Security");
3877
3878         if (security && g_str_equal(security, "ieee8021x") == true &&
3879                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
3880                 wifi->retries = 0;
3881                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
3882
3883                 return false;
3884         }
3885
3886         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
3887                 return false;
3888 #else
3889         struct connman_service *service;
3890
3891         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
3892                 return false;
3893
3894         if (wifi->connected)
3895                 return false;
3896 #endif
3897
3898         service = connman_service_lookup_from_network(network);
3899         if (!service)
3900                 return false;
3901
3902         wifi->retries++;
3903
3904         if (connman_service_get_favorite(service)) {
3905                 if (wifi->retries < FAVORITE_MAXIMUM_RETRIES)
3906                         return true;
3907         }
3908
3909         wifi->retries = 0;
3910         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
3911
3912         return false;
3913 }
3914
3915 #if defined TIZEN_EXT
3916 static bool handle_wifi_assoc_retry(struct connman_network *network,
3917                                         struct wifi_data *wifi)
3918 {
3919         const char *security;
3920
3921         if (!wifi->network || wifi->connected || wifi->disconnecting ||
3922                         connman_network_get_connecting(network) != true) {
3923                 wifi->assoc_retry_count = 0;
3924                 return false;
3925         }
3926
3927         if (wifi->state != G_SUPPLICANT_STATE_ASSOCIATING &&
3928                         wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) {
3929                 wifi->assoc_retry_count = 0;
3930                 return false;
3931         }
3932
3933         security = connman_network_get_string(network, "WiFi.Security");
3934         if (security && g_str_equal(security, "ieee8021x") == true &&
3935                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
3936                 wifi->assoc_retry_count = 0;
3937                 return false;
3938         }
3939
3940         if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) {
3941                 wifi->assoc_retry_count = 0;
3942
3943                 /* Honestly it's not an invalid-key error,
3944                  * however QA team recommends that the invalid-key error
3945                  * might be better to display for user experience.
3946                  */
3947                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
3948
3949                 return false;
3950         }
3951
3952         return true;
3953 }
3954 #endif
3955
3956 static void interface_state(GSupplicantInterface *interface)
3957 {
3958         struct connman_network *network;
3959         struct connman_device *device;
3960         struct wifi_data *wifi;
3961         GSupplicantState state = g_supplicant_interface_get_state(interface);
3962         bool wps;
3963         bool old_connected;
3964
3965         wifi = g_supplicant_interface_get_data(interface);
3966
3967         DBG("wifi %p interface state %d", wifi, state);
3968
3969         if (!wifi)
3970                 return;
3971
3972         if (state == G_SUPPLICANT_STATE_COMPLETED) {
3973                 if (wifi->tethering_param) {
3974                         g_free(wifi->tethering_param->ssid);
3975                         g_free(wifi->tethering_param);
3976                         wifi->tethering_param = NULL;
3977                 }
3978         }
3979
3980         device = wifi->device;
3981         if (!device)
3982                 return;
3983
3984         if (g_supplicant_interface_get_ready(interface) &&
3985                                         !wifi->interface_ready) {
3986                 wifi->interface_ready = true;
3987                 finalize_interface_creation(wifi);
3988         }
3989
3990         network = wifi->network;
3991         if (!network)
3992                 return;
3993
3994         switch (state) {
3995         case G_SUPPLICANT_STATE_SCANNING:
3996                 if (wifi->connected)
3997                         connman_network_set_connected(network, false);
3998
3999                 break;
4000
4001         case G_SUPPLICANT_STATE_AUTHENTICATING:
4002         case G_SUPPLICANT_STATE_ASSOCIATING:
4003 #if defined TIZEN_EXT
4004                 reset_autoscan(device);
4005 #else
4006                 stop_autoscan(device);
4007 #endif
4008
4009                 if (!wifi->connected)
4010                         connman_network_set_associating(network, true);
4011
4012                 break;
4013
4014         case G_SUPPLICANT_STATE_COMPLETED:
4015 #if defined TIZEN_EXT
4016                 /* though it should be already reset: */
4017                 reset_autoscan(device);
4018
4019                 wifi->assoc_retry_count = 0;
4020
4021                 wifi->scan_pending_network = NULL;
4022
4023                 /* should be cleared scanning flag */
4024                 bool scanning = connman_device_get_scanning(device);
4025                 if (scanning){
4026                         connman_device_set_scanning(device,
4027                                 CONNMAN_SERVICE_TYPE_WIFI, false);
4028                         connman_device_unref(device);
4029                 }
4030
4031                 if (!wifi->automaxspeed_timeout) {
4032                         DBG("Going to start signalpoll timer!!");
4033                         int ret = network_signalpoll(wifi);
4034                         if (ret < 0)
4035                                 DBG("Fail to get max speed !!");
4036                         else
4037                                 wifi->automaxspeed_timeout = g_timeout_add_seconds(30, autosignalpoll_timeout, wifi);
4038                 }
4039
4040                 g_hash_table_remove_all(failed_bssids);
4041 #else
4042                 /* though it should be already stopped: */
4043                 stop_autoscan(device);
4044 #endif
4045
4046                 if (!handle_wps_completion(interface, network, device, wifi))
4047                         break;
4048
4049                 connman_network_set_connected(network, true);
4050
4051                 wifi->disconnect_code = 0;
4052                 wifi->assoc_code = 0;
4053                 wifi->load_shaping_retries = 0;
4054                 break;
4055
4056         case G_SUPPLICANT_STATE_DISCONNECTED:
4057 #if defined TIZEN_EXT
4058                 connman_network_set_maxspeed(network, 0);
4059
4060                 if (wifi->automaxspeed_timeout != 0) {
4061                         g_source_remove(wifi->automaxspeed_timeout);
4062                         wifi->automaxspeed_timeout = 0;
4063                         DBG("Remove signalpoll timer!!");
4064                 }
4065 #endif
4066                 /*
4067                  * If we're in one of the idle modes, we have
4068                  * not started association yet and thus setting
4069                  * those ones to FALSE could cancel an association
4070                  * in progress.
4071                  */
4072                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
4073                 if (wps)
4074                         if (is_idle_wps(interface, wifi))
4075                                 break;
4076
4077                 if (is_idle(wifi))
4078                         break;
4079
4080 #if defined TIZEN_EXT
4081                 if (handle_assoc_status_code(interface, wifi)) {
4082                         GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network);
4083                         guint bssid_length = 0;
4084
4085                         if (bssid_list)
4086                                 bssid_length = g_slist_length(bssid_list);
4087
4088                         if (bssid_length > 1 && bssid_length > g_hash_table_size(failed_bssids)) {
4089                                 network_connect(network);
4090                                 break;
4091                         }
4092
4093                         wifi->load_shaping_retries = 0;
4094                 }
4095
4096                 g_hash_table_remove_all(failed_bssids);
4097 #else
4098                 if (handle_assoc_status_code(interface, wifi))
4099                         break;
4100 #endif
4101
4102                 /* If previous state was 4way-handshake, then
4103                  * it's either: psk was incorrect and thus we retry
4104                  * or if we reach the maximum retries we declare the
4105                  * psk as wrong */
4106                 if (handle_4way_handshake_failure(interface,
4107                                                 network, wifi))
4108                         break;
4109
4110                 /* See table 8-36 Reason codes in IEEE Std 802.11 */
4111                 switch (wifi->disconnect_code) {
4112                 case 1: /* Unspecified reason */
4113                         /* Let's assume it's because we got blocked */
4114
4115                 case 6: /* Class 2 frame received from nonauthenticated STA */
4116                         connman_network_set_error(network,
4117                                                 CONNMAN_NETWORK_ERROR_BLOCKED);
4118                         break;
4119
4120                 default:
4121                         break;
4122                 }
4123
4124 #if defined TIZEN_EXT
4125                 /* Some of Wi-Fi networks are not comply Wi-Fi specification.
4126                  * Retry association until its retry count is expired */
4127                 if (handle_wifi_assoc_retry(network, wifi) == true) {
4128                         throw_wifi_scan(wifi->device, scan_callback);
4129                         wifi->scan_pending_network = wifi->network;
4130                         break;
4131                 }
4132
4133                 if(wifi->disconnect_code > 0){
4134                         DBG("Set disconnect reason code(%d)", wifi->disconnect_code);
4135                         connman_network_set_disconnect_reason(network, wifi->disconnect_code);
4136                 }
4137 #endif
4138
4139                 connman_network_set_connected(network, false);
4140                 connman_network_set_associating(network, false);
4141                 wifi->disconnecting = false;
4142
4143                 start_autoscan(device);
4144
4145                 break;
4146
4147         case G_SUPPLICANT_STATE_INACTIVE:
4148 #if defined TIZEN_EXT
4149                 if (handle_wps_completion(interface, network, device, wifi) == false)
4150                         break;
4151 #endif
4152                 connman_network_set_associating(network, false);
4153                 start_autoscan(device);
4154
4155                 break;
4156
4157         case G_SUPPLICANT_STATE_UNKNOWN:
4158         case G_SUPPLICANT_STATE_DISABLED:
4159         case G_SUPPLICANT_STATE_ASSOCIATED:
4160         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4161         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4162                 break;
4163         }
4164
4165         old_connected = wifi->connected;
4166         wifi->state = state;
4167
4168         /* Saving wpa_s state policy:
4169          * If connected and if the state changes are roaming related:
4170          * --> We stay connected
4171          * If completed
4172          * --> We are connected
4173          * All other case:
4174          * --> We are not connected
4175          * */
4176         switch (state) {
4177         case G_SUPPLICANT_STATE_AUTHENTICATING:
4178         case G_SUPPLICANT_STATE_ASSOCIATING:
4179         case G_SUPPLICANT_STATE_ASSOCIATED:
4180         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4181         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4182                 if (wifi->connected)
4183                         connman_warn("Probably roaming right now!"
4184                                                 " Staying connected...");
4185                 break;
4186         case G_SUPPLICANT_STATE_SCANNING:
4187                 wifi->connected = false;
4188
4189                 if (old_connected)
4190                         start_autoscan(device);
4191                 break;
4192         case G_SUPPLICANT_STATE_COMPLETED:
4193                 wifi->connected = true;
4194                 break;
4195         default:
4196                 wifi->connected = false;
4197                 break;
4198         }
4199
4200         DBG("DONE");
4201 }
4202
4203 static void interface_removed(GSupplicantInterface *interface)
4204 {
4205         const char *ifname = g_supplicant_interface_get_ifname(interface);
4206         struct wifi_data *wifi;
4207
4208         DBG("ifname %s", ifname);
4209
4210         wifi = g_supplicant_interface_get_data(interface);
4211
4212 #if defined TIZEN_EXT_WIFI_MESH
4213         if (wifi && wifi->mesh_interface) {
4214                 DBG("Notify mesh interface remove");
4215                 connman_mesh_notify_interface_remove(true);
4216                 struct wifi_mesh_info *mesh_info = wifi->mesh_info;
4217                 g_free(mesh_info->parent_ifname);
4218                 g_free(mesh_info->ifname);
4219                 g_free(mesh_info->identifier);
4220                 g_free(mesh_info);
4221                 wifi->mesh_interface = false;
4222                 wifi->mesh_info = NULL;
4223                 return;
4224         }
4225 #endif
4226
4227         if (wifi)
4228                 wifi->interface = NULL;
4229
4230         if (wifi && wifi->tethering)
4231                 return;
4232
4233         if (!wifi || !wifi->device) {
4234                 DBG("wifi interface already removed");
4235                 return;
4236         }
4237
4238         connman_device_set_powered(wifi->device, false);
4239
4240         check_p2p_technology();
4241 #if defined TIZEN_EXT_WIFI_MESH
4242         check_mesh_technology();
4243 #endif
4244 }
4245
4246 static void set_device_type(const char *type, char dev_type[17])
4247 {
4248         const char *oui = "0050F204";
4249         const char *category = "0001";
4250         const char *sub_category = "0000";
4251
4252         if (!g_strcmp0(type, "handset")) {
4253                 category = "000A";
4254                 sub_category = "0005";
4255         } else if (!g_strcmp0(type, "vm") || !g_strcmp0(type, "container"))
4256                 sub_category = "0001";
4257         else if (!g_strcmp0(type, "server"))
4258                 sub_category = "0002";
4259         else if (!g_strcmp0(type, "laptop"))
4260                 sub_category = "0005";
4261         else if (!g_strcmp0(type, "desktop"))
4262                 sub_category = "0006";
4263         else if (!g_strcmp0(type, "tablet"))
4264                 sub_category = "0009";
4265         else if (!g_strcmp0(type, "watch"))
4266                 category = "00FF";
4267
4268         snprintf(dev_type, 17, "%s%s%s", category, oui, sub_category);
4269 }
4270
4271 static void p2p_support(GSupplicantInterface *interface)
4272 {
4273         char dev_type[17] = {};
4274         const char *hostname;
4275
4276         DBG("");
4277
4278         if (!interface)
4279                 return;
4280
4281         if (!g_supplicant_interface_has_p2p(interface))
4282                 return;
4283
4284         if (connman_technology_driver_register(&p2p_tech_driver) < 0) {
4285                 DBG("Could not register P2P technology driver");
4286                 return;
4287         }
4288
4289         hostname = connman_utsname_get_hostname();
4290         if (!hostname)
4291                 hostname = "ConnMan";
4292
4293         set_device_type(connman_machine_get_type(), dev_type);
4294         g_supplicant_interface_set_p2p_device_config(interface,
4295                                                         hostname, dev_type);
4296         connman_peer_driver_register(&peer_driver);
4297 }
4298
4299 static void scan_started(GSupplicantInterface *interface)
4300 {
4301         DBG("");
4302 }
4303
4304 static void scan_finished(GSupplicantInterface *interface)
4305 {
4306 #if defined TIZEN_EXT
4307         struct wifi_data *wifi;
4308         bool is_associating = false;
4309         static bool is_scanning = true;
4310 #endif
4311
4312         DBG("");
4313
4314 #if defined TIZEN_EXT
4315         wifi = g_supplicant_interface_get_data(interface);
4316         if (wifi && wifi->scan_pending_network) {
4317                 network_connect(wifi->scan_pending_network);
4318                 wifi->scan_pending_network = NULL;
4319         }
4320
4321         //service state - associating
4322         if(!wifi || !wifi->network)
4323                 return;
4324
4325         is_associating = connman_network_get_associating(wifi->network);
4326         if(is_associating && is_scanning){
4327                 is_scanning = false;
4328                 DBG("send scan for connecting");
4329                 throw_wifi_scan(wifi->device, scan_callback);
4330
4331                 return;
4332         }
4333         is_scanning = true;
4334
4335         //go scan
4336
4337 #endif
4338 }
4339
4340 static void ap_create_fail(GSupplicantInterface *interface)
4341 {
4342         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
4343         int ret;
4344
4345         if ((wifi->tethering) && (wifi->tethering_param)) {
4346                 DBG("%s create AP fail \n",
4347                                 g_supplicant_interface_get_ifname(wifi->interface));
4348
4349                 connman_inet_remove_from_bridge(wifi->index, wifi->bridge);
4350                 wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
4351                 wifi->tethering = false;
4352
4353                 ret = tech_set_tethering(wifi->tethering_param->technology,
4354                                 wifi->tethering_param->ssid->ssid,
4355                                 wifi->tethering_param->ssid->passphrase,
4356                                 wifi->bridge, true);
4357
4358                 if ((ret == -EOPNOTSUPP) && (wifi_technology)) {
4359                         connman_technology_tethering_notify(wifi_technology,false);
4360                 }
4361
4362                 g_free(wifi->tethering_param->ssid);
4363                 g_free(wifi->tethering_param);
4364                 wifi->tethering_param = NULL;
4365         }
4366
4367         return;
4368 }
4369
4370 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
4371 {
4372         unsigned char strength;
4373
4374         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
4375
4376 #if !defined TIZEN_EXT
4377         if (strength > 100)
4378                 strength = 100;
4379 #endif
4380         return strength;
4381 }
4382
4383 #if defined TIZEN_EXT_WIFI_MESH
4384 static void mesh_peer_added(GSupplicantNetwork *supplicant_network)
4385 {
4386         GSupplicantInterface *interface;
4387         struct wifi_data *wifi;
4388         const char *name, *security;
4389         struct connman_mesh *connman_mesh;
4390         struct wifi_mesh_info *mesh_info;
4391         const unsigned char *bssid;
4392         const char *identifier;
4393         char *address;
4394         uint16_t frequency;
4395         int ret;
4396
4397         interface = g_supplicant_network_get_interface(supplicant_network);
4398         wifi = g_supplicant_interface_get_data(interface);
4399         if (!wifi || !wifi->mesh_interface) {
4400                 DBG("Virtual Mesh interface not created");
4401                 return;
4402         }
4403
4404         bssid = g_supplicant_network_get_bssid(supplicant_network);
4405         address = g_malloc0(19);
4406         snprintf(address, 19, "%02x:%02x:%02x:%02x:%02x:%02x", bssid[0], bssid[1],
4407                                                                  bssid[2], bssid[3], bssid[4], bssid[5]);
4408
4409         identifier = g_supplicant_network_get_identifier(supplicant_network);
4410         name = g_supplicant_network_get_name(supplicant_network);
4411         security = g_supplicant_network_get_security(supplicant_network);
4412         frequency = g_supplicant_network_get_frequency(supplicant_network);
4413
4414         mesh_info = wifi->mesh_info;
4415         connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
4416         if (connman_mesh)
4417                 goto done;
4418
4419         DBG("Mesh Peer name %s identifier %s security %s added", name, identifier,
4420                                         security);
4421         connman_mesh = connman_mesh_create(mesh_info->identifier, identifier);
4422         connman_mesh_set_name(connman_mesh, name);
4423         connman_mesh_set_security(connman_mesh, security);
4424         connman_mesh_set_frequency(connman_mesh, frequency);
4425         connman_mesh_set_address(connman_mesh, address);
4426         connman_mesh_set_index(connman_mesh, mesh_info->index);
4427         connman_mesh_set_strength(connman_mesh,
4428                                                 calculate_strength(supplicant_network));
4429         connman_mesh_set_peer_type(connman_mesh, CONNMAN_MESH_PEER_TYPE_DISCOVERED);
4430
4431         ret = connman_mesh_register(connman_mesh);
4432         if (ret == -EALREADY)
4433                 DBG("Mesh Peer is already registered");
4434
4435 done:
4436         g_free(address);
4437 }
4438
4439 static void mesh_peer_removed(GSupplicantNetwork *supplicant_network)
4440 {
4441         GSupplicantInterface *interface;
4442         struct wifi_data *wifi;
4443         struct connman_mesh *connman_mesh;
4444         struct wifi_mesh_info *mesh_info;
4445         const char *identifier;
4446
4447         interface = g_supplicant_network_get_interface(supplicant_network);
4448         wifi = g_supplicant_interface_get_data(interface);
4449         if (!wifi || !wifi->mesh_interface) {
4450                 DBG("Virtual Mesh interface not created");
4451                 return;
4452         }
4453
4454         identifier = g_supplicant_network_get_identifier(supplicant_network);
4455         if (!identifier) {
4456                 DBG("Failed to get Mesh Peer identifier");
4457                 return;
4458         }
4459
4460         mesh_info = wifi->mesh_info;
4461         connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
4462         if (connman_mesh) {
4463                 /* Do not unregister connected mesh peer */
4464                 if (connman_mesh_peer_is_connected_state(connman_mesh)) {
4465                         DBG("Mesh Peer %s is connected", identifier);
4466                         return;
4467                 }
4468                 DBG("Mesh Peer identifier %s removed", identifier);
4469                 connman_mesh_unregister(connman_mesh);
4470         }
4471 }
4472 #endif
4473
4474 static void network_added(GSupplicantNetwork *supplicant_network)
4475 {
4476         struct connman_network *network;
4477         GSupplicantInterface *interface;
4478         struct wifi_data *wifi;
4479         const char *name, *identifier, *security, *group, *mode;
4480         const unsigned char *ssid;
4481         unsigned int ssid_len;
4482         bool wps;
4483         bool wps_pbc;
4484         bool wps_ready;
4485         bool wps_advertizing;
4486
4487 #if defined TIZEN_EXT
4488         GSList *vsie_list = NULL;
4489         const unsigned char *country_code;
4490         ieee80211_modes_e phy_mode;
4491 #endif
4492
4493         mode = g_supplicant_network_get_mode(supplicant_network);
4494         identifier = g_supplicant_network_get_identifier(supplicant_network);
4495
4496         DBG("%s", identifier);
4497
4498         if (!g_strcmp0(mode, "adhoc"))
4499                 return;
4500
4501 #if defined TIZEN_EXT_WIFI_MESH
4502         if (!g_strcmp0(mode, "mesh")) {
4503                 mesh_peer_added(supplicant_network);
4504                 return;
4505         }
4506 #endif
4507
4508         interface = g_supplicant_network_get_interface(supplicant_network);
4509         wifi = g_supplicant_interface_get_data(interface);
4510         name = g_supplicant_network_get_name(supplicant_network);
4511         security = g_supplicant_network_get_security(supplicant_network);
4512         group = g_supplicant_network_get_identifier(supplicant_network);
4513         wps = g_supplicant_network_get_wps(supplicant_network);
4514         wps_pbc = g_supplicant_network_is_wps_pbc(supplicant_network);
4515         wps_ready = g_supplicant_network_is_wps_active(supplicant_network);
4516         wps_advertizing = g_supplicant_network_is_wps_advertizing(
4517                                                         supplicant_network);
4518
4519         if (!wifi)
4520                 return;
4521
4522         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
4523
4524         network = connman_device_get_network(wifi->device, identifier);
4525
4526         if (!network) {
4527                 network = connman_network_create(identifier,
4528                                                 CONNMAN_NETWORK_TYPE_WIFI);
4529                 if (!network)
4530                         return;
4531
4532                 connman_network_set_index(network, wifi->index);
4533
4534                 if (connman_device_add_network(wifi->device, network) < 0) {
4535                         connman_network_unref(network);
4536                         return;
4537                 }
4538
4539                 wifi->networks = g_slist_prepend(wifi->networks, network);
4540         }
4541
4542         if (name && name[0] != '\0')
4543                 connman_network_set_name(network, name);
4544
4545         connman_network_set_blob(network, "WiFi.SSID",
4546                                                 ssid, ssid_len);
4547 #if defined TIZEN_EXT
4548         vsie_list = (GSList *)g_supplicant_network_get_wifi_vsie(supplicant_network);
4549         if (vsie_list)
4550                 connman_network_set_vsie_list(network, vsie_list);
4551         else
4552                 DBG("vsie_list is NULL");
4553         country_code = g_supplicant_network_get_countrycode(supplicant_network);
4554         connman_network_set_countrycode(network, country_code);
4555         phy_mode = g_supplicant_network_get_phy_mode(supplicant_network);
4556         connman_network_set_phy_mode(network, phy_mode);
4557 #endif
4558         connman_network_set_string(network, "WiFi.Security", security);
4559         connman_network_set_strength(network,
4560                                 calculate_strength(supplicant_network));
4561         connman_network_set_bool(network, "WiFi.WPS", wps);
4562
4563         if (wps) {
4564                 /* Is AP advertizing for WPS association?
4565                  * If so, we decide to use WPS by default */
4566                 if (wps_ready && wps_pbc &&
4567                                                 wps_advertizing) {
4568 #if !defined TIZEN_EXT
4569                         connman_network_set_bool(network, "WiFi.UseWPS", true);
4570 #else
4571                         DBG("wps is activating by ap but ignore it.");
4572 #endif
4573                 }
4574         }
4575
4576         connman_network_set_frequency(network,
4577                         g_supplicant_network_get_frequency(supplicant_network));
4578 #if defined TIZEN_EXT
4579         connman_network_set_bssid(network,
4580                         g_supplicant_network_get_bssid(supplicant_network));
4581         connman_network_set_maxrate(network,
4582                         g_supplicant_network_get_maxrate(supplicant_network));
4583         connman_network_set_enc_mode(network,
4584                         g_supplicant_network_get_enc_mode(supplicant_network));
4585         connman_network_set_rsn_mode(network,
4586                         g_supplicant_network_get_rsn_mode(supplicant_network));
4587         connman_network_set_keymgmt(network,
4588                         g_supplicant_network_get_keymgmt(supplicant_network));
4589         connman_network_set_bool(network, "WiFi.HS20AP",
4590                         g_supplicant_network_is_hs20AP(supplicant_network));
4591         connman_network_set_bssid_list(network,
4592                         (GSList *)g_supplicant_network_get_bssid_list(supplicant_network));
4593 #endif
4594         connman_network_set_available(network, true);
4595         connman_network_set_string(network, "WiFi.Mode", mode);
4596
4597 #if defined TIZEN_EXT
4598         if (group)
4599 #else
4600         if (ssid)
4601 #endif
4602                 connman_network_set_group(network, group);
4603
4604 #if defined TIZEN_EXT
4605         if (wifi_first_scan == true)
4606                 found_with_first_scan = true;
4607 #endif
4608
4609         if (wifi->hidden && ssid) {
4610 #if defined TIZEN_EXT
4611                 if (network_security(wifi->hidden->security) ==
4612                         network_security(security) &&
4613 #else
4614                 if (!g_strcmp0(wifi->hidden->security, security) &&
4615 #endif
4616                                 wifi->hidden->ssid_len == ssid_len &&
4617                                 !memcmp(wifi->hidden->ssid, ssid, ssid_len)) {
4618                         connman_network_connect_hidden(network,
4619                                         wifi->hidden->identity,
4620                                         wifi->hidden->passphrase,
4621                                         wifi->hidden->user_data);
4622                         wifi->hidden->user_data = NULL;
4623                         hidden_free(wifi->hidden);
4624                         wifi->hidden = NULL;
4625                 }
4626         }
4627 }
4628
4629 static void network_removed(GSupplicantNetwork *network)
4630 {
4631         GSupplicantInterface *interface;
4632         struct wifi_data *wifi;
4633         const char *name, *identifier;
4634         struct connman_network *connman_network;
4635
4636 #if defined TIZEN_EXT_WIFI_MESH
4637         const char *mode;
4638         mode = g_supplicant_network_get_mode(network);
4639         if (!g_strcmp0(mode, "mesh")) {
4640                 mesh_peer_removed(network);
4641                 return;
4642         }
4643 #endif
4644
4645         interface = g_supplicant_network_get_interface(network);
4646         wifi = g_supplicant_interface_get_data(interface);
4647         identifier = g_supplicant_network_get_identifier(network);
4648         name = g_supplicant_network_get_name(network);
4649
4650         DBG("name %s", name);
4651
4652         if (!wifi)
4653                 return;
4654
4655         connman_network = connman_device_get_network(wifi->device, identifier);
4656         if (!connman_network)
4657                 return;
4658
4659 #if defined TIZEN_EXT
4660         if (connman_network == wifi->scan_pending_network)
4661                 wifi->scan_pending_network = NULL;
4662
4663         if (connman_network == wifi->pending_network)
4664                 wifi->pending_network = NULL;
4665
4666         if(connman_network_get_connecting(connman_network) == true){
4667                 connman_network_set_connected(connman_network, false);
4668         }
4669 #endif
4670
4671         wifi->networks = g_slist_remove(wifi->networks, connman_network);
4672
4673         connman_device_remove_network(wifi->device, connman_network);
4674         connman_network_unref(connman_network);
4675 }
4676
4677 static void network_changed(GSupplicantNetwork *network, const char *property)
4678 {
4679         GSupplicantInterface *interface;
4680         struct wifi_data *wifi;
4681         const char *name, *identifier;
4682         struct connman_network *connman_network;
4683
4684 #if defined TIZEN_EXT
4685         const unsigned char *bssid;
4686         unsigned int maxrate;
4687         uint16_t frequency;
4688         bool wps;
4689         const unsigned char *country_code;
4690         ieee80211_modes_e phy_mode;
4691         GSList *bssid_list;
4692 #endif
4693
4694         interface = g_supplicant_network_get_interface(network);
4695         wifi = g_supplicant_interface_get_data(interface);
4696         identifier = g_supplicant_network_get_identifier(network);
4697         name = g_supplicant_network_get_name(network);
4698
4699         DBG("name %s", name);
4700
4701         if (!wifi)
4702                 return;
4703
4704         connman_network = connman_device_get_network(wifi->device, identifier);
4705         if (!connman_network)
4706                 return;
4707
4708         if (g_str_equal(property, "Signal")) {
4709                connman_network_set_strength(connman_network,
4710                                         calculate_strength(network));
4711                connman_network_update(connman_network);
4712         }
4713
4714 #if defined TIZEN_EXT
4715         bssid = g_supplicant_network_get_bssid(network);
4716         maxrate = g_supplicant_network_get_maxrate(network);
4717         frequency = g_supplicant_network_get_frequency(network);
4718         wps = g_supplicant_network_get_wps(network);
4719         phy_mode = g_supplicant_network_get_phy_mode(network);
4720
4721         connman_network_set_bssid(connman_network, bssid);
4722         connman_network_set_maxrate(connman_network, maxrate);
4723         connman_network_set_frequency(connman_network, frequency);
4724         connman_network_set_bool(connman_network, "WiFi.WPS", wps);
4725         country_code = g_supplicant_network_get_countrycode(network);
4726         connman_network_set_countrycode(connman_network, country_code);
4727         bssid_list = (GSList *)g_supplicant_network_get_bssid_list(network);
4728         connman_network_set_bssid_list(connman_network, bssid_list);
4729         connman_network_set_phy_mode(connman_network, phy_mode);
4730
4731         if (g_str_equal(property, "CheckMultiBssidConnect") &&
4732                         connman_network_get_associating(connman_network))
4733                 network_connect(connman_network);
4734 #endif
4735 }
4736
4737 static void network_associated(GSupplicantNetwork *network)
4738 {
4739         GSupplicantInterface *interface;
4740         struct wifi_data *wifi;
4741         struct connman_network *connman_network;
4742         const char *identifier;
4743
4744         DBG("");
4745
4746         interface = g_supplicant_network_get_interface(network);
4747         if (!interface)
4748                 return;
4749
4750         wifi = g_supplicant_interface_get_data(interface);
4751         if (!wifi)
4752                 return;
4753
4754         identifier = g_supplicant_network_get_identifier(network);
4755
4756         connman_network = connman_device_get_network(wifi->device, identifier);
4757         if (!connman_network)
4758                 return;
4759
4760         if (wifi->network) {
4761                 if (wifi->network == connman_network)
4762                         return;
4763
4764                 /*
4765                  * This should never happen, we got associated with
4766                  * a network different than the one we were expecting.
4767                  */
4768                 DBG("Associated to %p while expecting %p",
4769                                         connman_network, wifi->network);
4770
4771                 connman_network_set_associating(wifi->network, false);
4772         }
4773
4774         DBG("Reconnecting to previous network %p from wpa_s", connman_network);
4775
4776         wifi->network = connman_network_ref(connman_network);
4777         wifi->retries = 0;
4778
4779         /*
4780          * Interface state changes callback (interface_state) is always
4781          * called before network_associated callback thus we need to call
4782          * interface_state again in order to process the new state now that
4783          * we have the network properly set.
4784          */
4785         interface_state(interface);
4786 }
4787
4788 static void apply_peer_services(GSupplicantPeer *peer,
4789                                 struct connman_peer *connman_peer)
4790 {
4791         const unsigned char *data;
4792         int length;
4793
4794         DBG("");
4795
4796         connman_peer_reset_services(connman_peer);
4797
4798         data = g_supplicant_peer_get_widi_ies(peer, &length);
4799         if (data) {
4800                 connman_peer_add_service(connman_peer,
4801                         CONNMAN_PEER_SERVICE_WIFI_DISPLAY, data, length);
4802         }
4803 }
4804
4805 static void add_station(const char *mac)
4806 {
4807         connman_technology_tethering_add_station(CONNMAN_SERVICE_TYPE_WIFI,
4808                                                  mac);
4809 }
4810
4811 static void remove_station(const char *mac)
4812 {
4813         connman_technology_tethering_remove_station(mac);
4814 }
4815
4816 static void peer_found(GSupplicantPeer *peer)
4817 {
4818         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
4819         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
4820         struct connman_peer *connman_peer;
4821         const char *identifier, *name;
4822         int ret;
4823 #if defined TIZEN_EXT
4824         if (!wifi)
4825                 return;
4826 #endif
4827         identifier = g_supplicant_peer_get_identifier(peer);
4828         name = g_supplicant_peer_get_name(peer);
4829
4830         DBG("ident: %s", identifier);
4831
4832         connman_peer = connman_peer_get(wifi->device, identifier);
4833         if (connman_peer)
4834                 return;
4835
4836         connman_peer = connman_peer_create(identifier);
4837         connman_peer_set_name(connman_peer, name);
4838         connman_peer_set_device(connman_peer, wifi->device);
4839         apply_peer_services(peer, connman_peer);
4840
4841         ret = connman_peer_register(connman_peer);
4842         if (ret < 0 && ret != -EALREADY)
4843                 connman_peer_unref(connman_peer);
4844         else
4845                 wifi->peers = g_slist_prepend(wifi->peers, connman_peer);
4846 }
4847
4848 static void peer_lost(GSupplicantPeer *peer)
4849 {
4850         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
4851         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
4852         struct connman_peer *connman_peer;
4853         const char *identifier;
4854
4855         if (!wifi)
4856                 return;
4857
4858         identifier = g_supplicant_peer_get_identifier(peer);
4859
4860         DBG("ident: %s", identifier);
4861
4862         connman_peer = connman_peer_get(wifi->device, identifier);
4863         if (connman_peer) {
4864                 if (wifi->p2p_connecting &&
4865                                 wifi->pending_peer == connman_peer) {
4866                         peer_connect_timeout(wifi);
4867                 }
4868                 connman_peer_unregister(connman_peer);
4869                 connman_peer_unref(connman_peer);
4870         }
4871
4872         wifi->peers = g_slist_remove(wifi->peers, connman_peer);
4873 }
4874
4875 static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state)
4876 {
4877         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
4878         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
4879         enum connman_peer_state p_state = CONNMAN_PEER_STATE_UNKNOWN;
4880         struct connman_peer *connman_peer;
4881         const char *identifier;
4882
4883         identifier = g_supplicant_peer_get_identifier(peer);
4884
4885         DBG("ident: %s", identifier);
4886
4887         if (!wifi)
4888                 return;
4889
4890         connman_peer = connman_peer_get(wifi->device, identifier);
4891         if (!connman_peer)
4892                 return;
4893
4894         switch (state) {
4895         case G_SUPPLICANT_PEER_SERVICES_CHANGED:
4896                 apply_peer_services(peer, connman_peer);
4897                 connman_peer_services_changed(connman_peer);
4898                 return;
4899         case G_SUPPLICANT_PEER_GROUP_CHANGED:
4900                 if (!g_supplicant_peer_is_in_a_group(peer))
4901                         p_state = CONNMAN_PEER_STATE_IDLE;
4902                 else
4903                         p_state = CONNMAN_PEER_STATE_CONFIGURATION;
4904                 break;
4905         case G_SUPPLICANT_PEER_GROUP_STARTED:
4906                 break;
4907         case G_SUPPLICANT_PEER_GROUP_FINISHED:
4908                 p_state = CONNMAN_PEER_STATE_IDLE;
4909                 break;
4910         case G_SUPPLICANT_PEER_GROUP_JOINED:
4911                 connman_peer_set_iface_address(connman_peer,
4912                                 g_supplicant_peer_get_iface_address(peer));
4913                 break;
4914         case G_SUPPLICANT_PEER_GROUP_DISCONNECTED:
4915                 p_state = CONNMAN_PEER_STATE_IDLE;
4916                 break;
4917         case G_SUPPLICANT_PEER_GROUP_FAILED:
4918                 if (g_supplicant_peer_has_requested_connection(peer))
4919                         p_state = CONNMAN_PEER_STATE_IDLE;
4920                 else
4921                         p_state = CONNMAN_PEER_STATE_FAILURE;
4922                 break;
4923         }
4924
4925         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION ||
4926                                         p_state == CONNMAN_PEER_STATE_FAILURE) {
4927                 if (wifi->p2p_connecting
4928                                 && connman_peer == wifi->pending_peer)
4929                         peer_cancel_timeout(wifi);
4930                 else
4931                         p_state = CONNMAN_PEER_STATE_UNKNOWN;
4932         }
4933
4934         if (p_state == CONNMAN_PEER_STATE_UNKNOWN)
4935                 return;
4936
4937         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION) {
4938                 GSupplicantInterface *g_iface;
4939                 struct wifi_data *g_wifi;
4940
4941                 g_iface = g_supplicant_peer_get_group_interface(peer);
4942                 if (!g_iface)
4943                         return;
4944
4945                 g_wifi = g_supplicant_interface_get_data(g_iface);
4946                 if (!g_wifi)
4947                         return;
4948
4949                 connman_peer_set_as_master(connman_peer,
4950                                         !g_supplicant_peer_is_client(peer));
4951                 connman_peer_set_sub_device(connman_peer, g_wifi->device);
4952
4953                 /*
4954                  * If wpa_supplicant didn't create a dedicated p2p-group
4955                  * interface then mark this interface as p2p_device to avoid
4956                  * scan and auto-scan are launched on it while P2P is connected.
4957                  */
4958                 if (!g_list_find(p2p_iface_list, g_wifi))
4959                         wifi->p2p_device = true;
4960         }
4961
4962         connman_peer_set_state(connman_peer, p_state);
4963 }
4964
4965 static void peer_request(GSupplicantPeer *peer)
4966 {
4967         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
4968         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
4969         struct connman_peer *connman_peer;
4970         const char *identifier;
4971
4972 #if defined TIZEN_EXT
4973         if (!wifi)
4974                 return;
4975 #endif
4976
4977         identifier = g_supplicant_peer_get_identifier(peer);
4978
4979         DBG("ident: %s", identifier);
4980
4981         connman_peer = connman_peer_get(wifi->device, identifier);
4982         if (!connman_peer)
4983                 return;
4984
4985         connman_peer_request_connection(connman_peer);
4986 }
4987
4988 #if defined TIZEN_EXT
4989 static void system_power_off(void)
4990 {
4991         GList *list;
4992         struct wifi_data *wifi;
4993         struct connman_service *service;
4994         struct connman_ipconfig *ipconfig_ipv4;
4995
4996         if (connman_setting_get_bool("WiFiDHCPRelease") == true) {
4997                 for (list = iface_list; list; list = list->next) {
4998                         wifi = list->data;
4999
5000                         if (wifi->network != NULL) {
5001                                 service = connman_service_lookup_from_network(wifi->network);
5002                                 ipconfig_ipv4 = __connman_service_get_ip4config(service);
5003                                 __connman_dhcp_stop(ipconfig_ipv4);
5004                         }
5005                 }
5006         }
5007 }
5008
5009 static void network_merged(GSupplicantNetwork *network)
5010 {
5011         GSupplicantInterface *interface;
5012         GSupplicantState state;
5013         struct wifi_data *wifi;
5014         const char *identifier;
5015         struct connman_network *connman_network;
5016         bool ishs20AP = 0;
5017         char *temp = NULL;
5018
5019         interface = g_supplicant_network_get_interface(network);
5020         if (!interface)
5021                 return;
5022
5023         state = g_supplicant_interface_get_state(interface);
5024         if (state < G_SUPPLICANT_STATE_AUTHENTICATING)
5025                 return;
5026
5027         wifi = g_supplicant_interface_get_data(interface);
5028         if (!wifi)
5029                 return;
5030
5031         identifier = g_supplicant_network_get_identifier(network);
5032
5033         connman_network = connman_device_get_network(wifi->device, identifier);
5034         if (!connman_network)
5035                 return;
5036
5037         DBG("merged identifier %s", identifier);
5038
5039         if (wifi->connected == FALSE) {
5040                 switch (state) {
5041                 case G_SUPPLICANT_STATE_AUTHENTICATING:
5042                 case G_SUPPLICANT_STATE_ASSOCIATING:
5043                 case G_SUPPLICANT_STATE_ASSOCIATED:
5044                 case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
5045                 case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
5046                         connman_network_set_associating(connman_network, TRUE);
5047                         break;
5048                 case G_SUPPLICANT_STATE_COMPLETED:
5049                         connman_network_set_connected(connman_network, TRUE);
5050                         break;
5051                 default:
5052                         DBG("Not handled the state : %d", state);
5053                         break;
5054                 }
5055         }
5056
5057         ishs20AP = g_supplicant_network_is_hs20AP(network);
5058
5059         if (ishs20AP &&
5060                 g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) {
5061                 temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1);
5062                 connman_network_set_string(connman_network, "WiFi.EAP",
5063                                 temp);
5064                 connman_network_set_string(connman_network, "WiFi.Identity",
5065                                 g_supplicant_network_get_identity(network));
5066                 connman_network_set_string(connman_network, "WiFi.Phase2",
5067                                 g_supplicant_network_get_phase2(network));
5068
5069                 g_free(temp);
5070         }
5071
5072         wifi->network = connman_network;
5073 }
5074
5075 static void assoc_failed(void *user_data)
5076 {
5077         struct connman_network *network = user_data;
5078         connman_network_set_associating(network, false);
5079 }
5080 #endif
5081
5082 static void debug(const char *str)
5083 {
5084         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
5085                 connman_debug("%s", str);
5086 }
5087
5088 static void disconnect_reasoncode(GSupplicantInterface *interface,
5089                                 int reasoncode)
5090 {
5091         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5092
5093         if (wifi != NULL) {
5094                 wifi->disconnect_code = reasoncode;
5095         }
5096 }
5097
5098 static void assoc_status_code(GSupplicantInterface *interface, int status_code)
5099 {
5100         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5101
5102         if (wifi != NULL) {
5103                 wifi->assoc_code = status_code;
5104         }
5105 }
5106
5107 static const GSupplicantCallbacks callbacks = {
5108         .system_ready           = system_ready,
5109         .system_killed          = system_killed,
5110         .interface_added        = interface_added,
5111         .interface_state        = interface_state,
5112         .interface_removed      = interface_removed,
5113         .p2p_support            = p2p_support,
5114         .scan_started           = scan_started,
5115         .scan_finished          = scan_finished,
5116         .ap_create_fail         = ap_create_fail,
5117         .network_added          = network_added,
5118         .network_removed        = network_removed,
5119         .network_changed        = network_changed,
5120         .network_associated     = network_associated,
5121         .add_station            = add_station,
5122         .remove_station         = remove_station,
5123         .peer_found             = peer_found,
5124         .peer_lost              = peer_lost,
5125         .peer_changed           = peer_changed,
5126         .peer_request           = peer_request,
5127 #if defined TIZEN_EXT
5128         .system_power_off       = system_power_off,
5129         .network_merged = network_merged,
5130         .assoc_failed           = assoc_failed,
5131 #endif
5132         .debug                  = debug,
5133         .disconnect_reasoncode  = disconnect_reasoncode,
5134         .assoc_status_code      = assoc_status_code,
5135 #if defined TIZEN_EXT_WIFI_MESH
5136         .mesh_support           = mesh_support,
5137         .mesh_group_started = mesh_group_started,
5138         .mesh_group_removed = mesh_group_removed,
5139         .mesh_peer_connected = mesh_peer_connected,
5140         .mesh_peer_disconnected = mesh_peer_disconnected,
5141 #endif
5142 };
5143
5144
5145 static int tech_probe(struct connman_technology *technology)
5146 {
5147         wifi_technology = technology;
5148
5149         return 0;
5150 }
5151
5152 static void tech_remove(struct connman_technology *technology)
5153 {
5154         wifi_technology = NULL;
5155 }
5156
5157 static GSupplicantSSID *ssid_ap_init(const char *ssid,
5158                 const char *passphrase)
5159 {
5160         GSupplicantSSID *ap;
5161
5162         ap = g_try_malloc0(sizeof(GSupplicantSSID));
5163         if (!ap)
5164                 return NULL;
5165
5166         ap->mode = G_SUPPLICANT_MODE_MASTER;
5167 #if defined TIZEN_EXT
5168         ap->ssid = (void *) ssid;
5169 #else
5170         ap->ssid = ssid;
5171 #endif
5172         ap->ssid_len = strlen(ssid);
5173         ap->scan_ssid = 0;
5174         ap->freq = 2412;
5175
5176         if (!passphrase || strlen(passphrase) == 0) {
5177                 ap->security = G_SUPPLICANT_SECURITY_NONE;
5178                 ap->passphrase = NULL;
5179         } else {
5180                ap->security = G_SUPPLICANT_SECURITY_PSK;
5181                ap->protocol = G_SUPPLICANT_PROTO_RSN;
5182                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
5183                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
5184                ap->passphrase = passphrase;
5185         }
5186
5187         return ap;
5188 }
5189
5190 static void ap_start_callback(int result, GSupplicantInterface *interface,
5191                                                         void *user_data)
5192 {
5193         struct wifi_tethering_info *info = user_data;
5194
5195         DBG("result %d index %d bridge %s",
5196                 result, info->wifi->index, info->wifi->bridge);
5197
5198         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
5199                 connman_inet_remove_from_bridge(info->wifi->index,
5200                                                         info->wifi->bridge);
5201
5202                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
5203                         connman_technology_tethering_notify(info->technology, false);
5204                         g_free(info->wifi->tethering_param->ssid);
5205                         g_free(info->wifi->tethering_param);
5206                         info->wifi->tethering_param = NULL;
5207                 }
5208         }
5209
5210         g_free(info->ifname);
5211         g_free(info);
5212 }
5213
5214 static void ap_create_callback(int result,
5215                                 GSupplicantInterface *interface,
5216                                         void *user_data)
5217 {
5218         struct wifi_tethering_info *info = user_data;
5219
5220         DBG("result %d ifname %s", result,
5221                                 g_supplicant_interface_get_ifname(interface));
5222
5223         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
5224                 connman_inet_remove_from_bridge(info->wifi->index,
5225                                                         info->wifi->bridge);
5226
5227                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
5228                         connman_technology_tethering_notify(info->technology, false);
5229                         g_free(info->wifi->tethering_param->ssid);
5230                         g_free(info->wifi->tethering_param);
5231                         info->wifi->tethering_param = NULL;
5232
5233                 }
5234
5235                 g_free(info->ifname);
5236                 g_free(info->ssid);
5237                 g_free(info);
5238                 return;
5239         }
5240
5241         info->wifi->interface = interface;
5242         g_supplicant_interface_set_data(interface, info->wifi);
5243
5244         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
5245                 connman_error("Failed to set interface ap_scan property");
5246
5247         g_supplicant_interface_connect(interface, info->ssid,
5248                                                 ap_start_callback, info);
5249 }
5250
5251 static void sta_remove_callback(int result,
5252                                 GSupplicantInterface *interface,
5253                                         void *user_data)
5254 {
5255         struct wifi_tethering_info *info = user_data;
5256         const char *driver = connman_option_get_string("wifi");
5257
5258         DBG("ifname %s result %d ", info->ifname, result);
5259
5260         if (result < 0 || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
5261                 info->wifi->tethering = false;
5262                 connman_technology_tethering_notify(info->technology, false);
5263
5264                 g_free(info->ifname);
5265                 g_free(info->ssid);
5266                 g_free(info);
5267
5268                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
5269                         g_free(info->wifi->tethering_param->ssid);
5270                         g_free(info->wifi->tethering_param);
5271                         info->wifi->tethering_param = NULL;
5272                 }
5273                 return;
5274         }
5275
5276         info->wifi->interface = NULL;
5277
5278         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
5279                                                 ap_create_callback,
5280                                                         info);
5281 }
5282
5283 static int enable_wifi_tethering(struct connman_technology *technology,
5284                                 const char *bridge, const char *identifier,
5285                                 const char *passphrase, bool available)
5286 {
5287         GList *list;
5288         GSupplicantInterface *interface;
5289         struct wifi_data *wifi;
5290         struct wifi_tethering_info *info;
5291         const char *ifname;
5292         unsigned int mode;
5293         int err, berr = 0;
5294
5295         for (list = iface_list; list; list = list->next) {
5296                 wifi = list->data;
5297
5298                 DBG("wifi %p network %p pending_network %p", wifi,
5299                         wifi->network, wifi->pending_network);
5300
5301                 interface = wifi->interface;
5302
5303                 if (!interface)
5304                         continue;
5305
5306                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED)
5307                         continue;
5308
5309                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
5310
5311                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED) {
5312                         DBG("%s does not support AP mode (detected)", ifname);
5313                         continue;
5314                 }
5315
5316                 mode = g_supplicant_interface_get_mode(interface);
5317                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
5318                         wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
5319                         DBG("%s does not support AP mode (capability)", ifname);
5320                         continue;
5321                 }
5322
5323                 if (wifi->network && available)
5324                         continue;
5325
5326                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
5327                 if (!info)
5328                         return -ENOMEM;
5329
5330                 wifi->tethering_param = g_try_malloc0(sizeof(struct wifi_tethering_info));
5331                 if (!wifi->tethering_param) {
5332                         g_free(info);
5333                         return -ENOMEM;
5334                 }
5335
5336                 info->wifi = wifi;
5337                 info->technology = technology;
5338                 info->wifi->bridge = bridge;
5339                 info->ssid = ssid_ap_init(identifier, passphrase);
5340                 if (!info->ssid)
5341                         goto failed;
5342
5343                 info->ifname = g_strdup(ifname);
5344                 if (!info->ifname)
5345                         goto failed;
5346
5347                 wifi->tethering_param->technology = technology;
5348                 wifi->tethering_param->ssid = ssid_ap_init(identifier, passphrase);
5349                 if (!wifi->tethering_param->ssid)
5350                         goto failed;
5351
5352                 info->wifi->tethering = true;
5353                 info->wifi->ap_supported = WIFI_AP_SUPPORTED;
5354
5355                 berr = connman_technology_tethering_notify(technology, true);
5356                 if (berr < 0)
5357                         goto failed;
5358
5359                 err = g_supplicant_interface_remove(interface,
5360                                                 sta_remove_callback,
5361                                                         info);
5362                 if (err >= 0) {
5363                         DBG("tethering wifi %p ifname %s", wifi, ifname);
5364                         return 0;
5365                 }
5366
5367         failed:
5368                 g_free(info->ifname);
5369                 g_free(info->ssid);
5370                 g_free(info);
5371                 g_free(wifi->tethering_param);
5372                 wifi->tethering_param = NULL;
5373
5374                 /*
5375                  * Remove bridge if it was correctly created but remove
5376                  * operation failed. Instead, if bridge creation failed then
5377                  * break out and do not try again on another interface,
5378                  * bridge set-up does not depend on it.
5379                  */
5380                 if (berr == 0)
5381                         connman_technology_tethering_notify(technology, false);
5382                 else
5383                         break;
5384         }
5385
5386         return -EOPNOTSUPP;
5387 }
5388
5389 static int tech_set_tethering(struct connman_technology *technology,
5390                                 const char *identifier, const char *passphrase,
5391                                 const char *bridge, bool enabled)
5392 {
5393         GList *list;
5394         struct wifi_data *wifi;
5395         int err;
5396
5397         DBG("");
5398
5399         if (!enabled) {
5400                 for (list = iface_list; list; list = list->next) {
5401                         wifi = list->data;
5402
5403                         if (wifi->tethering) {
5404                                 wifi->tethering = false;
5405
5406                                 connman_inet_remove_from_bridge(wifi->index,
5407                                                                         bridge);
5408                                 wifi->bridged = false;
5409                         }
5410                 }
5411
5412                 connman_technology_tethering_notify(technology, false);
5413
5414                 return 0;
5415         }
5416
5417         DBG("trying tethering for available devices");
5418         err = enable_wifi_tethering(technology, bridge, identifier, passphrase,
5419                                 true);
5420
5421         if (err < 0) {
5422                 DBG("trying tethering for any device");
5423                 err = enable_wifi_tethering(technology, bridge, identifier,
5424                                         passphrase, false);
5425         }
5426
5427         return err;
5428 }
5429
5430 static void regdom_callback(int result, const char *alpha2, void *user_data)
5431 {
5432         DBG("");
5433
5434         if (!wifi_technology)
5435                 return;
5436
5437         if (result != 0)
5438                 alpha2 = NULL;
5439
5440         connman_technology_regdom_notify(wifi_technology, alpha2);
5441 }
5442
5443 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
5444 {
5445         return g_supplicant_set_country(alpha2, regdom_callback, NULL);
5446 }
5447
5448 static struct connman_technology_driver tech_driver = {
5449         .name           = "wifi",
5450         .type           = CONNMAN_SERVICE_TYPE_WIFI,
5451         .probe          = tech_probe,
5452         .remove         = tech_remove,
5453         .set_tethering  = tech_set_tethering,
5454         .set_regdom     = tech_set_regdom,
5455 };
5456
5457 static int wifi_init(void)
5458 {
5459         int err;
5460
5461         err = connman_network_driver_register(&network_driver);
5462         if (err < 0)
5463                 return err;
5464
5465         err = g_supplicant_register(&callbacks);
5466         if (err < 0) {
5467                 connman_network_driver_unregister(&network_driver);
5468                 return err;
5469         }
5470
5471         err = connman_technology_driver_register(&tech_driver);
5472         if (err < 0) {
5473                 g_supplicant_unregister(&callbacks);
5474                 connman_network_driver_unregister(&network_driver);
5475                 return err;
5476         }
5477
5478 #if defined TIZEN_EXT
5479         failed_bssids = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
5480 #endif
5481         return 0;
5482 }
5483
5484 static void wifi_exit(void)
5485 {
5486         DBG();
5487
5488         connman_technology_driver_unregister(&tech_driver);
5489
5490         g_supplicant_unregister(&callbacks);
5491
5492         connman_network_driver_unregister(&network_driver);
5493
5494 #if defined TIZEN_EXT
5495         g_hash_table_unref(failed_bssids);
5496 #endif
5497 }
5498
5499 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
5500                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)