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