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