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