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