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