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