Added support of WPA3-SAE security mode.
[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         else if (g_str_equal(security, "sae"))
3180                 return G_SUPPLICANT_SECURITY_SAE;
3181 #endif
3182
3183         return G_SUPPLICANT_SECURITY_UNKNOWN;
3184 }
3185
3186 #if defined TIZEN_EXT
3187 static GSupplicantEapKeymgmt network_eap_keymgmt(const char *security)
3188 {
3189         if (security == NULL)
3190                 return G_SUPPLICANT_EAP_KEYMGMT_NONE;
3191
3192         if (g_str_equal(security, "FT") == TRUE)
3193                 return G_SUPPLICANT_EAP_KEYMGMT_FT;
3194         else if (g_str_equal(security, "CCKM") == TRUE)
3195                 return G_SUPPLICANT_EAP_KEYMGMT_CCKM;
3196
3197         return G_SUPPLICANT_EAP_KEYMGMT_NONE;
3198 }
3199 #endif
3200
3201 static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
3202 {
3203         const char *security;
3204 #if defined TIZEN_EXT
3205         const void *ssid_data;
3206 #endif
3207
3208         memset(ssid, 0, sizeof(*ssid));
3209         ssid->mode = G_SUPPLICANT_MODE_INFRA;
3210 #if defined TIZEN_EXT
3211         ssid_data = connman_network_get_blob(network, "WiFi.SSID",
3212                                                 &ssid->ssid_len);
3213         ssid->ssid = g_try_malloc0(ssid->ssid_len);
3214
3215         if (!ssid->ssid)
3216                 ssid->ssid_len = 0;
3217         else
3218                 memcpy(ssid->ssid, ssid_data, ssid->ssid_len);
3219 #else
3220         ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
3221                                                 &ssid->ssid_len);
3222 #endif
3223         ssid->scan_ssid = 1;
3224         security = connman_network_get_string(network, "WiFi.Security");
3225         ssid->security = network_security(security);
3226 #if defined TIZEN_EXT
3227         ssid->ieee80211w = 1;
3228 #endif
3229         ssid->passphrase = connman_network_get_string(network,
3230                                                 "WiFi.Passphrase");
3231         ssid->eap = connman_network_get_string(network, "WiFi.EAP");
3232
3233         /*
3234          * If our private key password is unset,
3235          * we use the supplied passphrase. That is needed
3236          * for PEAP where 2 passphrases (identity and client
3237          * cert may have to be provided.
3238          */
3239         if (!connman_network_get_string(network, "WiFi.PrivateKeyPassphrase"))
3240                 connman_network_set_string(network,
3241                                                 "WiFi.PrivateKeyPassphrase",
3242                                                 ssid->passphrase);
3243         /* We must have an identity for both PEAP and TLS */
3244         ssid->identity = connman_network_get_string(network, "WiFi.Identity");
3245
3246         /* Use agent provided identity as a fallback */
3247         if (!ssid->identity || strlen(ssid->identity) == 0)
3248                 ssid->identity = connman_network_get_string(network,
3249                                                         "WiFi.AgentIdentity");
3250
3251         ssid->anonymous_identity = connman_network_get_string(network,
3252                                                 "WiFi.AnonymousIdentity");
3253         ssid->ca_cert_path = connman_network_get_string(network,
3254                                                         "WiFi.CACertFile");
3255         ssid->subject_match = connman_network_get_string(network,
3256                                                         "WiFi.SubjectMatch");
3257         ssid->altsubject_match = connman_network_get_string(network,
3258                                                         "WiFi.AltSubjectMatch");
3259         ssid->domain_suffix_match = connman_network_get_string(network,
3260                                                         "WiFi.DomainSuffixMatch");
3261         ssid->domain_match = connman_network_get_string(network,
3262                                                         "WiFi.DomainMatch");
3263         ssid->client_cert_path = connman_network_get_string(network,
3264                                                         "WiFi.ClientCertFile");
3265         ssid->private_key_path = connman_network_get_string(network,
3266                                                         "WiFi.PrivateKeyFile");
3267         ssid->private_key_passphrase = connman_network_get_string(network,
3268                                                 "WiFi.PrivateKeyPassphrase");
3269         ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
3270
3271         ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS");
3272         ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS");
3273
3274 #if defined TIZEN_EXT
3275         if (set_connman_bssid(CHECK_BSSID, NULL) == 6) {
3276                 ssid->bssid_for_connect_len = 6;
3277                 set_connman_bssid(GET_BSSID, (char *)ssid->bssid_for_connect);
3278                 DBG("BSSID : %02x:%02x:%02x:%02x:%02x:%02x",
3279                         ssid->bssid_for_connect[0], ssid->bssid_for_connect[1],
3280                         ssid->bssid_for_connect[2], ssid->bssid_for_connect[3],
3281                         ssid->bssid_for_connect[4], ssid->bssid_for_connect[5]);
3282         } else {
3283                 ssid->freq = connman_network_get_frequency(network);
3284         }
3285
3286         GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network);
3287         if (bssid_list && g_slist_length(bssid_list) > 1) {
3288
3289                 /* If there are more than one bssid,
3290                  * the user-specified bssid is tried only once at the beginning.
3291                  * After that, the bssids in the list are tried in order.
3292                  */
3293                 if (set_connman_bssid(CHECK_BSSID, NULL) == 6) {
3294                         set_connman_bssid(RESET_BSSID, NULL);
3295                         goto done;
3296                 }
3297
3298                 GSList *list;
3299                 char buff[MAC_ADDRESS_LENGTH];
3300                 for (list = bssid_list; list; list = list->next) {
3301                         struct connman_bssids * bssids = (struct connman_bssids *)list->data;
3302
3303                         g_snprintf(buff, MAC_ADDRESS_LENGTH, "%02x:%02x:%02x:%02x:%02x:%02x",
3304                                         bssids->bssid[0], bssids->bssid[1], bssids->bssid[2],
3305                                         bssids->bssid[3], bssids->bssid[4], bssids->bssid[5]);
3306                         buff[MAC_ADDRESS_LENGTH - 1] = '\0';
3307
3308                         gchar *curr_bssid = g_strdup((const gchar *)buff);
3309
3310                         if (g_hash_table_contains(failed_bssids, curr_bssid)) {
3311                                 DBG("bssid match, try next bssid");
3312                                 g_free(curr_bssid);
3313                                 continue;
3314                         } else {
3315                                 g_hash_table_add(failed_bssids, curr_bssid);
3316
3317                                 memcpy(buff_bssid, bssids->bssid, WIFI_BSSID_LEN_MAX);
3318                                 ssid->bssid = buff_bssid;
3319                                 ssid->freq = (unsigned int)bssids->frequency;
3320                                 break;
3321                         }
3322                 }
3323
3324                 if (!list) {
3325                         ssid->bssid = connman_network_get_bssid(network);
3326                         g_hash_table_remove_all(failed_bssids);
3327                 }
3328         } else
3329                 ssid->bssid = connman_network_get_bssid(network);
3330
3331 done:
3332         ssid->eap_keymgmt = network_eap_keymgmt(
3333                         connman_network_get_string(network, "WiFi.KeymgmtType"));
3334         ssid->phase1 = connman_network_get_string(network, "WiFi.Phase1");
3335
3336         if(g_strcmp0(ssid->eap, "fast") == 0)
3337                 ssid->pac_file = g_strdup(WIFI_EAP_FAST_PAC_FILE);
3338 #endif
3339
3340         if (connman_setting_get_bool("BackgroundScanning"))
3341                 ssid->bgscan = BGSCAN_DEFAULT;
3342 }
3343
3344 static int network_connect(struct connman_network *network)
3345 {
3346         struct connman_device *device = connman_network_get_device(network);
3347         struct wifi_data *wifi;
3348         GSupplicantInterface *interface;
3349         GSupplicantSSID *ssid;
3350
3351         DBG("network %p", network);
3352
3353         if (!device)
3354                 return -ENODEV;
3355
3356         wifi = connman_device_get_data(device);
3357         if (!wifi)
3358                 return -ENODEV;
3359
3360         ssid = g_try_malloc0(sizeof(GSupplicantSSID));
3361         if (!ssid)
3362                 return -ENOMEM;
3363
3364         interface = wifi->interface;
3365
3366         ssid_init(ssid, network);
3367
3368         if (wifi->disconnecting) {
3369                 wifi->pending_network = network;
3370 #if defined TIZEN_EXT
3371                 g_free(ssid->ssid);
3372 #endif
3373                 g_free(ssid);
3374         } else {
3375                 wifi->network = connman_network_ref(network);
3376                 wifi->retries = 0;
3377 #if defined TIZEN_EXT
3378                 wifi->scan_pending_network = NULL;
3379 #endif
3380
3381                 return g_supplicant_interface_connect(interface, ssid,
3382                                                 connect_callback, network);
3383         }
3384
3385         return -EINPROGRESS;
3386 }
3387
3388 static void disconnect_callback(int result, GSupplicantInterface *interface,
3389                                                                 void *user_data)
3390 {
3391 #if defined TIZEN_EXT
3392         GList *list;
3393         struct wifi_data *wifi;
3394         struct connman_network *network = user_data;
3395
3396         DBG("network %p result %d", network, result);
3397
3398         for (list = iface_list; list; list = list->next) {
3399                 wifi = list->data;
3400
3401                 if (wifi->network == NULL && wifi->disconnecting == true)
3402                         wifi->disconnecting = false;
3403
3404                 if (wifi->network == network)
3405                         goto found;
3406         }
3407
3408         /* wifi_data may be invalid because wifi is already disabled */
3409         return;
3410
3411 found:
3412 #else
3413         struct wifi_data *wifi = user_data;
3414 #endif
3415
3416         DBG("result %d supplicant interface %p wifi %p",
3417                         result, interface, wifi);
3418
3419         if (result == -ECONNABORTED) {
3420                 DBG("wifi interface no longer available");
3421                 return;
3422         }
3423
3424         if (wifi->network) {
3425                 connman_network_set_connected(wifi->network, false);
3426                 wifi->network = NULL;
3427         }
3428
3429         wifi->disconnecting = false;
3430         wifi->connected = false;
3431
3432         if (wifi->pending_network) {
3433                 network_connect(wifi->pending_network);
3434                 wifi->pending_network = NULL;
3435         }
3436
3437         start_autoscan(wifi->device);
3438 }
3439
3440 static int network_disconnect(struct connman_network *network)
3441 {
3442         struct connman_device *device = connman_network_get_device(network);
3443         struct wifi_data *wifi;
3444         int err;
3445 #if defined TIZEN_EXT
3446         struct connman_service *service;
3447 #endif
3448
3449         DBG("network %p", network);
3450
3451         wifi = connman_device_get_data(device);
3452         if (!wifi || !wifi->interface)
3453                 return -ENODEV;
3454
3455 #if defined TIZEN_EXT
3456         if (connman_network_get_associating(network) == true) {
3457                 connman_network_clear_associating(network);
3458                 connman_network_set_bool(network, "WiFi.UseWPS", false);
3459         } else {
3460                 service = connman_service_lookup_from_network(network);
3461
3462                 if (service != NULL &&
3463                         (__connman_service_is_connected_state(service,
3464                                         CONNMAN_IPCONFIG_TYPE_IPV4) == false &&
3465                         __connman_service_is_connected_state(service,
3466                                         CONNMAN_IPCONFIG_TYPE_IPV6) == false) &&
3467                         (connman_service_get_favorite(service) == false))
3468                                         __connman_service_set_passphrase(service, NULL);
3469         }
3470
3471         if (wifi->pending_network == network)
3472                 wifi->pending_network = NULL;
3473
3474         if (wifi->scan_pending_network == network)
3475                 wifi->scan_pending_network = NULL;
3476
3477 #endif
3478         connman_network_set_associating(network, false);
3479
3480         if (wifi->disconnecting)
3481                 return -EALREADY;
3482
3483         wifi->disconnecting = true;
3484
3485 #if defined TIZEN_EXT
3486         err = g_supplicant_interface_disconnect(wifi->interface,
3487                                                 disconnect_callback, network);
3488 #else
3489         err = g_supplicant_interface_disconnect(wifi->interface,
3490                                                 disconnect_callback, wifi);
3491 #endif
3492
3493         if (err < 0)
3494                 wifi->disconnecting = false;
3495
3496         return err;
3497 }
3498
3499 #if defined TIZEN_EXT
3500 static void set_connection_mode(struct connman_network *network,
3501                 int linkspeed)
3502 {
3503         ieee80211_modes_e phy_mode;
3504         connection_mode_e conn_mode;
3505
3506         phy_mode = connman_network_get_phy_mode(network);
3507         switch (phy_mode) {
3508         case IEEE80211_MODE_B:
3509                 if (linkspeed > 0 && linkspeed <= 11)
3510                         conn_mode = CONNECTION_MODE_IEEE80211B;
3511                 else
3512                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3513
3514                 break;
3515         case IEEE80211_MODE_BG:
3516                 if (linkspeed > 0 && linkspeed <= 11)
3517                         conn_mode = CONNECTION_MODE_IEEE80211B;
3518                 else if (linkspeed > 11 && linkspeed <= 54)
3519                         conn_mode = CONNECTION_MODE_IEEE80211G;
3520                 else
3521                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3522
3523                 break;
3524         case IEEE80211_MODE_BGN:
3525                 if (linkspeed > 0 && linkspeed <= 11)
3526                         conn_mode = CONNECTION_MODE_IEEE80211B;
3527                 else if (linkspeed > 11 && linkspeed <= 54)
3528                         conn_mode = CONNECTION_MODE_IEEE80211G;
3529                 else if (linkspeed > 54 && linkspeed <= 450)
3530                         conn_mode = CONNECTION_MODE_IEEE80211N;
3531                 else
3532                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3533
3534                 break;
3535         case IEEE80211_MODE_A:
3536                 if (linkspeed > 0 && linkspeed <= 54)
3537                         conn_mode = CONNECTION_MODE_IEEE80211A;
3538                 else
3539                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3540
3541                 break;
3542         case IEEE80211_MODE_AN:
3543                 if (linkspeed > 0 && linkspeed <= 54)
3544                         conn_mode = CONNECTION_MODE_IEEE80211A;
3545                 else if (linkspeed > 54 && linkspeed <= 450)
3546                         conn_mode = CONNECTION_MODE_IEEE80211N;
3547                 else
3548                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3549
3550                 break;
3551         case IEEE80211_MODE_ANAC:
3552                 if (linkspeed > 0 && linkspeed <= 54)
3553                         conn_mode = CONNECTION_MODE_IEEE80211A;
3554                 else if (linkspeed > 54 && linkspeed <= 450)
3555                         conn_mode = CONNECTION_MODE_IEEE80211N;
3556                 else if (linkspeed > 450 && linkspeed <= 1300)
3557                         conn_mode = CONNECTION_MODE_IEEE80211AC;
3558                 else
3559                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3560
3561                 break;
3562         default:
3563                         conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN;
3564                 break;
3565         }
3566
3567         DBG("connection mode(%d)", conn_mode);
3568         connman_network_set_connection_mode(network, conn_mode);
3569 }
3570
3571 static void signalpoll_callback(int result, int maxspeed, void *user_data)
3572 {
3573         struct connman_network *network = user_data;
3574
3575         if (result != 0) {
3576                 DBG("Failed to get maxspeed from signalpoll !");
3577                 return;
3578         }
3579
3580         DBG("maxspeed = %d", maxspeed);
3581         if (network) {
3582                 connman_network_set_maxspeed(network, maxspeed);
3583                 set_connection_mode(network, maxspeed);
3584         }
3585 }
3586
3587 static int network_signalpoll(struct wifi_data *wifi)
3588 {
3589         GSupplicantInterface *interface;
3590         struct connman_network *network;
3591
3592         if (!wifi || !wifi->network)
3593                 return -ENODEV;
3594
3595         interface = wifi->interface;
3596         network = wifi->network;
3597
3598         DBG("network %p", network);
3599
3600         return g_supplicant_interface_signalpoll(interface, signalpoll_callback, network);
3601 }
3602
3603 static gboolean autosignalpoll_timeout(gpointer data)
3604 {
3605         struct wifi_data *wifi = data;
3606
3607         if (!wifi || !wifi->automaxspeed_timeout) {
3608                 DBG("automaxspeed_timeout is found to be zero. i.e. currently in disconnected state. !!");
3609                 return FALSE;
3610         }
3611
3612         int ret = network_signalpoll(wifi);
3613         if (ret < 0) {
3614                 DBG("Fail to get max speed !!");
3615                 wifi->automaxspeed_timeout = 0;
3616                 return FALSE;
3617         }
3618
3619         return TRUE;
3620 }
3621 #endif
3622
3623 static struct connman_network_driver network_driver = {
3624         .name           = "wifi",
3625         .type           = CONNMAN_NETWORK_TYPE_WIFI,
3626         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
3627         .probe          = network_probe,
3628         .remove         = network_remove,
3629         .connect        = network_connect,
3630         .disconnect     = network_disconnect,
3631 };
3632
3633 static void interface_added(GSupplicantInterface *interface)
3634 {
3635         const char *ifname = g_supplicant_interface_get_ifname(interface);
3636         const char *driver = g_supplicant_interface_get_driver(interface);
3637 #if defined TIZEN_EXT
3638         bool is_5_0_ghz_supported = g_supplicant_interface_get_is_5_0_ghz_supported(interface);
3639 #endif
3640
3641         struct wifi_data *wifi;
3642
3643         wifi = g_supplicant_interface_get_data(interface);
3644         if (!wifi) {
3645                 wifi = get_pending_wifi_data(ifname);
3646                 if (!wifi)
3647                         return;
3648
3649                 wifi->interface = interface;
3650                 g_supplicant_interface_set_data(interface, wifi);
3651                 p2p_iface_list = g_list_append(p2p_iface_list, wifi);
3652                 wifi->p2p_device = true;
3653         }
3654
3655         DBG("ifname %s driver %s wifi %p tethering %d",
3656                         ifname, driver, wifi, wifi->tethering);
3657
3658         if (!wifi->device) {
3659                 connman_error("WiFi device not set");
3660                 return;
3661         }
3662
3663         connman_device_set_powered(wifi->device, true);
3664 #if defined TIZEN_EXT
3665         connman_techonology_wifi_set_5ghz_supported(wifi_technology, is_5_0_ghz_supported);
3666         /* Max number of SSIDs supported by wlan chipset that can be scanned */
3667         int max_scan_ssids = g_supplicant_interface_get_max_scan_ssids(interface);
3668         connman_techonology_set_max_scan_ssids(wifi_technology, max_scan_ssids);
3669 #endif
3670 }
3671
3672 static bool is_idle(struct wifi_data *wifi)
3673 {
3674         DBG("state %d", wifi->state);
3675
3676         switch (wifi->state) {
3677         case G_SUPPLICANT_STATE_UNKNOWN:
3678         case G_SUPPLICANT_STATE_DISABLED:
3679         case G_SUPPLICANT_STATE_DISCONNECTED:
3680         case G_SUPPLICANT_STATE_INACTIVE:
3681         case G_SUPPLICANT_STATE_SCANNING:
3682                 return true;
3683
3684         case G_SUPPLICANT_STATE_AUTHENTICATING:
3685         case G_SUPPLICANT_STATE_ASSOCIATING:
3686         case G_SUPPLICANT_STATE_ASSOCIATED:
3687         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3688         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3689         case G_SUPPLICANT_STATE_COMPLETED:
3690                 return false;
3691         }
3692
3693         return false;
3694 }
3695
3696 static bool is_idle_wps(GSupplicantInterface *interface,
3697                                                 struct wifi_data *wifi)
3698 {
3699         /* First, let's check if WPS processing did not went wrong */
3700         if (g_supplicant_interface_get_wps_state(interface) ==
3701                 G_SUPPLICANT_WPS_STATE_FAIL)
3702                 return false;
3703
3704         /* Unlike normal connection, being associated while processing wps
3705          * actually means that we are idling. */
3706         switch (wifi->state) {
3707         case G_SUPPLICANT_STATE_UNKNOWN:
3708         case G_SUPPLICANT_STATE_DISABLED:
3709         case G_SUPPLICANT_STATE_DISCONNECTED:
3710         case G_SUPPLICANT_STATE_INACTIVE:
3711         case G_SUPPLICANT_STATE_SCANNING:
3712         case G_SUPPLICANT_STATE_ASSOCIATED:
3713                 return true;
3714         case G_SUPPLICANT_STATE_AUTHENTICATING:
3715         case G_SUPPLICANT_STATE_ASSOCIATING:
3716         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3717         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3718         case G_SUPPLICANT_STATE_COMPLETED:
3719                 return false;
3720         }
3721
3722         return false;
3723 }
3724
3725 static bool handle_wps_completion(GSupplicantInterface *interface,
3726                                         struct connman_network *network,
3727                                         struct connman_device *device,
3728                                         struct wifi_data *wifi)
3729 {
3730         bool wps;
3731
3732         wps = connman_network_get_bool(network, "WiFi.UseWPS");
3733         if (wps) {
3734                 const unsigned char *ssid, *wps_ssid;
3735                 unsigned int ssid_len, wps_ssid_len;
3736                 const char *wps_key;
3737
3738                 /* Checking if we got associated with requested
3739                  * network */
3740                 ssid = connman_network_get_blob(network, "WiFi.SSID",
3741                                                 &ssid_len);
3742
3743                 wps_ssid = g_supplicant_interface_get_wps_ssid(
3744                         interface, &wps_ssid_len);
3745
3746                 if (!wps_ssid || wps_ssid_len != ssid_len ||
3747                                 memcmp(ssid, wps_ssid, ssid_len) != 0) {
3748                         connman_network_set_associating(network, false);
3749 #if defined TIZEN_EXT
3750                         g_supplicant_interface_disconnect(wifi->interface,
3751                                                 disconnect_callback, wifi->network);
3752
3753                         connman_network_set_bool(network, "WiFi.UseWPS", false);
3754                         connman_network_set_string(network, "WiFi.PinWPS", NULL);
3755 #else
3756                         g_supplicant_interface_disconnect(wifi->interface,
3757                                                 disconnect_callback, wifi);
3758 #endif
3759                         return false;
3760                 }
3761
3762                 wps_key = g_supplicant_interface_get_wps_key(interface);
3763 #if defined TIZEN_EXT
3764                 /* Check the passphrase and encrypt it
3765                  */
3766                  int ret;
3767                  gchar *passphrase = g_strdup(wps_key);
3768
3769                  connman_network_set_string(network, "WiFi.PinWPS", NULL);
3770
3771                  if (check_passphrase_ext(network, passphrase) < 0) {
3772                          DBG("[WPS] Invalid passphrase");
3773                          g_free(passphrase);
3774                          return true;
3775                  }
3776
3777                  ret = send_encryption_request(passphrase, network);
3778
3779                  g_free(passphrase);
3780
3781                  if (!ret)
3782                          DBG("[WPS] Encryption request succeeded");
3783                  else
3784                          DBG("[WPS] Encryption request failed %d", ret);
3785
3786 #else
3787                 connman_network_set_string(network, "WiFi.Passphrase",
3788                                         wps_key);
3789
3790                 connman_network_set_string(network, "WiFi.PinWPS", NULL);
3791 #endif
3792         }
3793
3794         return true;
3795 }
3796
3797 static bool handle_assoc_status_code(GSupplicantInterface *interface,
3798                                      struct wifi_data *wifi)
3799 {
3800         if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING &&
3801 #if defined TIZEN_EXT
3802                         wifi->assoc_code > 0 &&
3803 #else
3804                         wifi->assoc_code == ASSOC_STATUS_NO_CLIENT &&
3805 #endif
3806                         wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) {
3807                 wifi->load_shaping_retries ++;
3808                 return TRUE;
3809         }
3810         wifi->load_shaping_retries = 0;
3811         return FALSE;
3812 }
3813
3814 static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
3815                                         struct connman_network *network,
3816                                         struct wifi_data *wifi)
3817 {
3818 #if defined TIZEN_EXT
3819         const char *security;
3820         struct connman_service *service;
3821
3822         if (wifi->connected)
3823                 return false;
3824
3825         security = connman_network_get_string(network, "WiFi.Security");
3826
3827         if (security && g_str_equal(security, "ieee8021x") == true &&
3828                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
3829                 wifi->retries = 0;
3830                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
3831
3832                 return false;
3833         }
3834
3835         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
3836                 return false;
3837 #else
3838         struct connman_service *service;
3839
3840         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
3841                 return false;
3842
3843         if (wifi->connected)
3844                 return false;
3845 #endif
3846
3847         service = connman_service_lookup_from_network(network);
3848         if (!service)
3849                 return false;
3850
3851         wifi->retries++;
3852
3853         if (connman_service_get_favorite(service)) {
3854                 if (wifi->retries < FAVORITE_MAXIMUM_RETRIES)
3855                         return true;
3856         }
3857
3858         wifi->retries = 0;
3859         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
3860
3861         return false;
3862 }
3863
3864 #if defined TIZEN_EXT
3865 static bool handle_wifi_assoc_retry(struct connman_network *network,
3866                                         struct wifi_data *wifi)
3867 {
3868         const char *security;
3869
3870         if (!wifi->network || wifi->connected || wifi->disconnecting ||
3871                         connman_network_get_connecting(network) != true) {
3872                 wifi->assoc_retry_count = 0;
3873                 return false;
3874         }
3875
3876         if (wifi->state != G_SUPPLICANT_STATE_ASSOCIATING &&
3877                         wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) {
3878                 wifi->assoc_retry_count = 0;
3879                 return false;
3880         }
3881
3882         security = connman_network_get_string(network, "WiFi.Security");
3883         if (security && g_str_equal(security, "ieee8021x") == true &&
3884                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
3885                 wifi->assoc_retry_count = 0;
3886                 return false;
3887         }
3888
3889         if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) {
3890                 wifi->assoc_retry_count = 0;
3891
3892                 /* Honestly it's not an invalid-key error,
3893                  * however QA team recommends that the invalid-key error
3894                  * might be better to display for user experience.
3895                  */
3896                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
3897
3898                 return false;
3899         }
3900
3901         return true;
3902 }
3903 #endif
3904
3905 static void interface_state(GSupplicantInterface *interface)
3906 {
3907         struct connman_network *network;
3908         struct connman_device *device;
3909         struct wifi_data *wifi;
3910         GSupplicantState state = g_supplicant_interface_get_state(interface);
3911         bool wps;
3912         bool old_connected;
3913
3914         wifi = g_supplicant_interface_get_data(interface);
3915
3916         DBG("wifi %p interface state %d", wifi, state);
3917
3918         if (!wifi)
3919                 return;
3920
3921         if (state == G_SUPPLICANT_STATE_COMPLETED) {
3922                 if (wifi->tethering_param) {
3923                         g_free(wifi->tethering_param->ssid);
3924                         g_free(wifi->tethering_param);
3925                         wifi->tethering_param = NULL;
3926                 }
3927         }
3928
3929         device = wifi->device;
3930         if (!device)
3931                 return;
3932
3933         if (g_supplicant_interface_get_ready(interface) &&
3934                                         !wifi->interface_ready) {
3935                 wifi->interface_ready = true;
3936                 finalize_interface_creation(wifi);
3937         }
3938
3939         network = wifi->network;
3940         if (!network)
3941                 return;
3942
3943         switch (state) {
3944         case G_SUPPLICANT_STATE_SCANNING:
3945                 if (wifi->connected)
3946                         connman_network_set_connected(network, false);
3947
3948                 break;
3949
3950         case G_SUPPLICANT_STATE_AUTHENTICATING:
3951         case G_SUPPLICANT_STATE_ASSOCIATING:
3952 #if defined TIZEN_EXT
3953                 reset_autoscan(device);
3954 #else
3955                 stop_autoscan(device);
3956 #endif
3957
3958                 if (!wifi->connected)
3959                         connman_network_set_associating(network, true);
3960
3961                 break;
3962
3963         case G_SUPPLICANT_STATE_COMPLETED:
3964 #if defined TIZEN_EXT
3965                 /* though it should be already reset: */
3966                 reset_autoscan(device);
3967
3968                 wifi->assoc_retry_count = 0;
3969
3970                 wifi->scan_pending_network = NULL;
3971
3972                 /* should be cleared scanning flag */
3973                 bool scanning = connman_device_get_scanning(device);
3974                 if (scanning){
3975                         connman_device_set_scanning(device,
3976                                 CONNMAN_SERVICE_TYPE_WIFI, false);
3977                         connman_device_unref(device);
3978                 }
3979
3980                 if (!wifi->automaxspeed_timeout) {
3981                         DBG("Going to start signalpoll timer!!");
3982                         int ret = network_signalpoll(wifi);
3983                         if (ret < 0)
3984                                 DBG("Fail to get max speed !!");
3985                         else
3986                                 wifi->automaxspeed_timeout = g_timeout_add_seconds(30, autosignalpoll_timeout, wifi);
3987                 }
3988
3989                 g_hash_table_remove_all(failed_bssids);
3990 #else
3991                 /* though it should be already stopped: */
3992                 stop_autoscan(device);
3993 #endif
3994
3995                 if (!handle_wps_completion(interface, network, device, wifi))
3996                         break;
3997
3998                 connman_network_set_connected(network, true);
3999
4000                 wifi->disconnect_code = 0;
4001                 wifi->assoc_code = 0;
4002                 wifi->load_shaping_retries = 0;
4003                 break;
4004
4005         case G_SUPPLICANT_STATE_DISCONNECTED:
4006 #if defined TIZEN_EXT
4007                 connman_network_set_maxspeed(network, 0);
4008
4009                 if (wifi->automaxspeed_timeout != 0) {
4010                         g_source_remove(wifi->automaxspeed_timeout);
4011                         wifi->automaxspeed_timeout = 0;
4012                         DBG("Remove signalpoll timer!!");
4013                 }
4014 #endif
4015                 /*
4016                  * If we're in one of the idle modes, we have
4017                  * not started association yet and thus setting
4018                  * those ones to FALSE could cancel an association
4019                  * in progress.
4020                  */
4021                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
4022                 if (wps)
4023                         if (is_idle_wps(interface, wifi))
4024                                 break;
4025
4026                 if (is_idle(wifi))
4027                         break;
4028
4029 #if defined TIZEN_EXT
4030                 if (handle_assoc_status_code(interface, wifi)) {
4031                         GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network);
4032                         guint bssid_length = 0;
4033
4034                         if (bssid_list)
4035                                 bssid_length = g_slist_length(bssid_list);
4036
4037                         if (bssid_length > 1 && bssid_length > g_hash_table_size(failed_bssids)) {
4038                                 network_connect(network);
4039                                 break;
4040                         }
4041
4042                         wifi->load_shaping_retries = 0;
4043                 }
4044
4045                 g_hash_table_remove_all(failed_bssids);
4046 #else
4047                 if (handle_assoc_status_code(interface, wifi))
4048                         break;
4049 #endif
4050
4051                 /* If previous state was 4way-handshake, then
4052                  * it's either: psk was incorrect and thus we retry
4053                  * or if we reach the maximum retries we declare the
4054                  * psk as wrong */
4055                 if (handle_4way_handshake_failure(interface,
4056                                                 network, wifi))
4057                         break;
4058
4059                 /* See table 8-36 Reason codes in IEEE Std 802.11 */
4060                 switch (wifi->disconnect_code) {
4061                 case 1: /* Unspecified reason */
4062                         /* Let's assume it's because we got blocked */
4063
4064                 case 6: /* Class 2 frame received from nonauthenticated STA */
4065                         connman_network_set_error(network,
4066                                                 CONNMAN_NETWORK_ERROR_BLOCKED);
4067                         break;
4068
4069                 default:
4070                         break;
4071                 }
4072
4073 #if defined TIZEN_EXT
4074                 /* Some of Wi-Fi networks are not comply Wi-Fi specification.
4075                  * Retry association until its retry count is expired */
4076                 if (handle_wifi_assoc_retry(network, wifi) == true) {
4077                         throw_wifi_scan(wifi->device, scan_callback);
4078                         wifi->scan_pending_network = wifi->network;
4079                         break;
4080                 }
4081
4082                 if(wifi->disconnect_code > 0){
4083                         DBG("Set disconnect reason code(%d)", wifi->disconnect_code);
4084                         connman_network_set_disconnect_reason(network, wifi->disconnect_code);
4085                 }
4086 #endif
4087
4088                 connman_network_set_connected(network, false);
4089                 connman_network_set_associating(network, false);
4090                 wifi->disconnecting = false;
4091
4092                 start_autoscan(device);
4093
4094                 break;
4095
4096         case G_SUPPLICANT_STATE_INACTIVE:
4097 #if defined TIZEN_EXT
4098                 if (handle_wps_completion(interface, network, device, wifi) == false)
4099                         break;
4100 #endif
4101                 connman_network_set_associating(network, false);
4102                 start_autoscan(device);
4103
4104                 break;
4105
4106         case G_SUPPLICANT_STATE_UNKNOWN:
4107         case G_SUPPLICANT_STATE_DISABLED:
4108         case G_SUPPLICANT_STATE_ASSOCIATED:
4109         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4110         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4111                 break;
4112         }
4113
4114         old_connected = wifi->connected;
4115         wifi->state = state;
4116
4117         /* Saving wpa_s state policy:
4118          * If connected and if the state changes are roaming related:
4119          * --> We stay connected
4120          * If completed
4121          * --> We are connected
4122          * All other case:
4123          * --> We are not connected
4124          * */
4125         switch (state) {
4126         case G_SUPPLICANT_STATE_AUTHENTICATING:
4127         case G_SUPPLICANT_STATE_ASSOCIATING:
4128         case G_SUPPLICANT_STATE_ASSOCIATED:
4129         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4130         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4131                 if (wifi->connected)
4132                         connman_warn("Probably roaming right now!"
4133                                                 " Staying connected...");
4134                 break;
4135         case G_SUPPLICANT_STATE_SCANNING:
4136                 wifi->connected = false;
4137
4138                 if (old_connected)
4139                         start_autoscan(device);
4140                 break;
4141         case G_SUPPLICANT_STATE_COMPLETED:
4142                 wifi->connected = true;
4143                 break;
4144         default:
4145                 wifi->connected = false;
4146                 break;
4147         }
4148
4149         DBG("DONE");
4150 }
4151
4152 static void interface_removed(GSupplicantInterface *interface)
4153 {
4154         const char *ifname = g_supplicant_interface_get_ifname(interface);
4155         struct wifi_data *wifi;
4156
4157         DBG("ifname %s", ifname);
4158
4159         wifi = g_supplicant_interface_get_data(interface);
4160
4161 #if defined TIZEN_EXT_WIFI_MESH
4162         if (wifi && wifi->mesh_interface) {
4163                 DBG("Notify mesh interface remove");
4164                 connman_mesh_notify_interface_remove(true);
4165                 struct wifi_mesh_info *mesh_info = wifi->mesh_info;
4166                 g_free(mesh_info->parent_ifname);
4167                 g_free(mesh_info->ifname);
4168                 g_free(mesh_info->identifier);
4169                 g_free(mesh_info);
4170                 wifi->mesh_interface = false;
4171                 wifi->mesh_info = NULL;
4172                 return;
4173         }
4174 #endif
4175
4176         if (wifi)
4177                 wifi->interface = NULL;
4178
4179         if (wifi && wifi->tethering)
4180                 return;
4181
4182         if (!wifi || !wifi->device) {
4183                 DBG("wifi interface already removed");
4184                 return;
4185         }
4186
4187         connman_device_set_powered(wifi->device, false);
4188
4189         check_p2p_technology();
4190 #if defined TIZEN_EXT_WIFI_MESH
4191         check_mesh_technology();
4192 #endif
4193 }
4194
4195 static void set_device_type(const char *type, char dev_type[17])
4196 {
4197         const char *oui = "0050F204";
4198         const char *category = "0001";
4199         const char *sub_category = "0000";
4200
4201         if (!g_strcmp0(type, "handset")) {
4202                 category = "000A";
4203                 sub_category = "0005";
4204         } else if (!g_strcmp0(type, "vm") || !g_strcmp0(type, "container"))
4205                 sub_category = "0001";
4206         else if (!g_strcmp0(type, "server"))
4207                 sub_category = "0002";
4208         else if (!g_strcmp0(type, "laptop"))
4209                 sub_category = "0005";
4210         else if (!g_strcmp0(type, "desktop"))
4211                 sub_category = "0006";
4212         else if (!g_strcmp0(type, "tablet"))
4213                 sub_category = "0009";
4214         else if (!g_strcmp0(type, "watch"))
4215                 category = "00FF";
4216
4217         snprintf(dev_type, 17, "%s%s%s", category, oui, sub_category);
4218 }
4219
4220 static void p2p_support(GSupplicantInterface *interface)
4221 {
4222         char dev_type[17] = {};
4223         const char *hostname;
4224
4225         DBG("");
4226
4227         if (!interface)
4228                 return;
4229
4230         if (!g_supplicant_interface_has_p2p(interface))
4231                 return;
4232
4233         if (connman_technology_driver_register(&p2p_tech_driver) < 0) {
4234                 DBG("Could not register P2P technology driver");
4235                 return;
4236         }
4237
4238         hostname = connman_utsname_get_hostname();
4239         if (!hostname)
4240                 hostname = "ConnMan";
4241
4242         set_device_type(connman_machine_get_type(), dev_type);
4243         g_supplicant_interface_set_p2p_device_config(interface,
4244                                                         hostname, dev_type);
4245         connman_peer_driver_register(&peer_driver);
4246 }
4247
4248 static void scan_started(GSupplicantInterface *interface)
4249 {
4250         DBG("");
4251 }
4252
4253 static void scan_finished(GSupplicantInterface *interface)
4254 {
4255 #if defined TIZEN_EXT
4256         struct wifi_data *wifi;
4257         bool is_associating = false;
4258         static bool is_scanning = true;
4259 #endif
4260
4261         DBG("");
4262
4263 #if defined TIZEN_EXT
4264         wifi = g_supplicant_interface_get_data(interface);
4265         if (wifi && wifi->scan_pending_network) {
4266                 network_connect(wifi->scan_pending_network);
4267                 wifi->scan_pending_network = NULL;
4268         }
4269
4270         //service state - associating
4271         if(!wifi || !wifi->network)
4272                 return;
4273
4274         is_associating = connman_network_get_associating(wifi->network);
4275         if(is_associating && is_scanning){
4276                 is_scanning = false;
4277                 DBG("send scan for connecting");
4278                 throw_wifi_scan(wifi->device, scan_callback);
4279
4280                 return;
4281         }
4282         is_scanning = true;
4283
4284         //go scan
4285
4286 #endif
4287 }
4288
4289 static void ap_create_fail(GSupplicantInterface *interface)
4290 {
4291         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
4292         int ret;
4293
4294         if ((wifi->tethering) && (wifi->tethering_param)) {
4295                 DBG("%s create AP fail \n",
4296                                 g_supplicant_interface_get_ifname(wifi->interface));
4297
4298                 connman_inet_remove_from_bridge(wifi->index, wifi->bridge);
4299                 wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
4300                 wifi->tethering = false;
4301
4302                 ret = tech_set_tethering(wifi->tethering_param->technology,
4303                                 wifi->tethering_param->ssid->ssid,
4304                                 wifi->tethering_param->ssid->passphrase,
4305                                 wifi->bridge, true);
4306
4307                 if ((ret == -EOPNOTSUPP) && (wifi_technology)) {
4308                         connman_technology_tethering_notify(wifi_technology,false);
4309                 }
4310
4311                 g_free(wifi->tethering_param->ssid);
4312                 g_free(wifi->tethering_param);
4313                 wifi->tethering_param = NULL;
4314         }
4315
4316         return;
4317 }
4318
4319 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
4320 {
4321         unsigned char strength;
4322
4323         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
4324
4325 #if !defined TIZEN_EXT
4326         if (strength > 100)
4327                 strength = 100;
4328 #endif
4329         return strength;
4330 }
4331
4332 #if defined TIZEN_EXT_WIFI_MESH
4333 static void mesh_peer_added(GSupplicantNetwork *supplicant_network)
4334 {
4335         GSupplicantInterface *interface;
4336         struct wifi_data *wifi;
4337         const char *name, *security;
4338         struct connman_mesh *connman_mesh;
4339         struct wifi_mesh_info *mesh_info;
4340         const unsigned char *bssid;
4341         const char *identifier;
4342         char *address;
4343         uint16_t frequency;
4344         int ret;
4345
4346         interface = g_supplicant_network_get_interface(supplicant_network);
4347         wifi = g_supplicant_interface_get_data(interface);
4348         if (!wifi || !wifi->mesh_interface) {
4349                 DBG("Virtual Mesh interface not created");
4350                 return;
4351         }
4352
4353         bssid = g_supplicant_network_get_bssid(supplicant_network);
4354         address = g_malloc0(19);
4355         snprintf(address, 19, "%02x:%02x:%02x:%02x:%02x:%02x", bssid[0], bssid[1],
4356                                                                  bssid[2], bssid[3], bssid[4], bssid[5]);
4357
4358         identifier = g_supplicant_network_get_identifier(supplicant_network);
4359         name = g_supplicant_network_get_name(supplicant_network);
4360         security = g_supplicant_network_get_security(supplicant_network);
4361         frequency = g_supplicant_network_get_frequency(supplicant_network);
4362
4363         mesh_info = wifi->mesh_info;
4364         connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
4365         if (connman_mesh)
4366                 goto done;
4367
4368         DBG("Mesh Peer name %s identifier %s security %s added", name, identifier,
4369                                         security);
4370         connman_mesh = connman_mesh_create(mesh_info->identifier, identifier);
4371         connman_mesh_set_name(connman_mesh, name);
4372         connman_mesh_set_security(connman_mesh, security);
4373         connman_mesh_set_frequency(connman_mesh, frequency);
4374         connman_mesh_set_address(connman_mesh, address);
4375         connman_mesh_set_index(connman_mesh, mesh_info->index);
4376         connman_mesh_set_strength(connman_mesh,
4377                                                 calculate_strength(supplicant_network));
4378         connman_mesh_set_peer_type(connman_mesh, CONNMAN_MESH_PEER_TYPE_DISCOVERED);
4379
4380         ret = connman_mesh_register(connman_mesh);
4381         if (ret == -EALREADY)
4382                 DBG("Mesh Peer is already registered");
4383
4384 done:
4385         g_free(address);
4386 }
4387
4388 static void mesh_peer_removed(GSupplicantNetwork *supplicant_network)
4389 {
4390         GSupplicantInterface *interface;
4391         struct wifi_data *wifi;
4392         struct connman_mesh *connman_mesh;
4393         struct wifi_mesh_info *mesh_info;
4394         const char *identifier;
4395
4396         interface = g_supplicant_network_get_interface(supplicant_network);
4397         wifi = g_supplicant_interface_get_data(interface);
4398         if (!wifi || !wifi->mesh_interface) {
4399                 DBG("Virtual Mesh interface not created");
4400                 return;
4401         }
4402
4403         identifier = g_supplicant_network_get_identifier(supplicant_network);
4404         if (!identifier) {
4405                 DBG("Failed to get Mesh Peer identifier");
4406                 return;
4407         }
4408
4409         mesh_info = wifi->mesh_info;
4410         connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
4411         if (connman_mesh) {
4412                 /* Do not unregister connected mesh peer */
4413                 if (connman_mesh_peer_is_connected_state(connman_mesh)) {
4414                         DBG("Mesh Peer %s is connected", identifier);
4415                         return;
4416                 }
4417                 DBG("Mesh Peer identifier %s removed", identifier);
4418                 connman_mesh_unregister(connman_mesh);
4419         }
4420 }
4421 #endif
4422
4423 static void network_added(GSupplicantNetwork *supplicant_network)
4424 {
4425         struct connman_network *network;
4426         GSupplicantInterface *interface;
4427         struct wifi_data *wifi;
4428         const char *name, *identifier, *security, *group, *mode;
4429         const unsigned char *ssid;
4430         unsigned int ssid_len;
4431         bool wps;
4432         bool wps_pbc;
4433         bool wps_ready;
4434         bool wps_advertizing;
4435
4436 #if defined TIZEN_EXT
4437         GSList *vsie_list = NULL;
4438         const unsigned char *country_code;
4439         ieee80211_modes_e phy_mode;
4440 #endif
4441
4442         mode = g_supplicant_network_get_mode(supplicant_network);
4443         identifier = g_supplicant_network_get_identifier(supplicant_network);
4444
4445         DBG("%s", identifier);
4446
4447         if (!g_strcmp0(mode, "adhoc"))
4448                 return;
4449
4450 #if defined TIZEN_EXT_WIFI_MESH
4451         if (!g_strcmp0(mode, "mesh")) {
4452                 mesh_peer_added(supplicant_network);
4453                 return;
4454         }
4455 #endif
4456
4457         interface = g_supplicant_network_get_interface(supplicant_network);
4458         wifi = g_supplicant_interface_get_data(interface);
4459         name = g_supplicant_network_get_name(supplicant_network);
4460         security = g_supplicant_network_get_security(supplicant_network);
4461         group = g_supplicant_network_get_identifier(supplicant_network);
4462         wps = g_supplicant_network_get_wps(supplicant_network);
4463         wps_pbc = g_supplicant_network_is_wps_pbc(supplicant_network);
4464         wps_ready = g_supplicant_network_is_wps_active(supplicant_network);
4465         wps_advertizing = g_supplicant_network_is_wps_advertizing(
4466                                                         supplicant_network);
4467
4468         if (!wifi)
4469                 return;
4470
4471         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
4472
4473         network = connman_device_get_network(wifi->device, identifier);
4474
4475         if (!network) {
4476                 network = connman_network_create(identifier,
4477                                                 CONNMAN_NETWORK_TYPE_WIFI);
4478                 if (!network)
4479                         return;
4480
4481                 connman_network_set_index(network, wifi->index);
4482
4483                 if (connman_device_add_network(wifi->device, network) < 0) {
4484                         connman_network_unref(network);
4485                         return;
4486                 }
4487
4488                 wifi->networks = g_slist_prepend(wifi->networks, network);
4489         }
4490
4491         if (name && name[0] != '\0')
4492                 connman_network_set_name(network, name);
4493
4494         connman_network_set_blob(network, "WiFi.SSID",
4495                                                 ssid, ssid_len);
4496 #if defined TIZEN_EXT
4497         vsie_list = (GSList *)g_supplicant_network_get_wifi_vsie(supplicant_network);
4498         if (vsie_list)
4499                 connman_network_set_vsie_list(network, vsie_list);
4500         else
4501                 DBG("vsie_list is NULL");
4502         country_code = g_supplicant_network_get_countrycode(supplicant_network);
4503         connman_network_set_countrycode(network, country_code);
4504         phy_mode = g_supplicant_network_get_phy_mode(supplicant_network);
4505         connman_network_set_phy_mode(network, phy_mode);
4506 #endif
4507         connman_network_set_string(network, "WiFi.Security", security);
4508         connman_network_set_strength(network,
4509                                 calculate_strength(supplicant_network));
4510         connman_network_set_bool(network, "WiFi.WPS", wps);
4511
4512         if (wps) {
4513                 /* Is AP advertizing for WPS association?
4514                  * If so, we decide to use WPS by default */
4515                 if (wps_ready && wps_pbc &&
4516                                                 wps_advertizing) {
4517 #if !defined TIZEN_EXT
4518                         connman_network_set_bool(network, "WiFi.UseWPS", true);
4519 #else
4520                         DBG("wps is activating by ap but ignore it.");
4521 #endif
4522                 }
4523         }
4524
4525         connman_network_set_frequency(network,
4526                         g_supplicant_network_get_frequency(supplicant_network));
4527 #if defined TIZEN_EXT
4528         connman_network_set_bssid(network,
4529                         g_supplicant_network_get_bssid(supplicant_network));
4530         connman_network_set_maxrate(network,
4531                         g_supplicant_network_get_maxrate(supplicant_network));
4532         connman_network_set_enc_mode(network,
4533                         g_supplicant_network_get_enc_mode(supplicant_network));
4534         connman_network_set_rsn_mode(network,
4535                         g_supplicant_network_get_rsn_mode(supplicant_network));
4536         connman_network_set_keymgmt(network,
4537                         g_supplicant_network_get_keymgmt(supplicant_network));
4538         connman_network_set_bool(network, "WiFi.HS20AP",
4539                         g_supplicant_network_is_hs20AP(supplicant_network));
4540         connman_network_set_bssid_list(network,
4541                         (GSList *)g_supplicant_network_get_bssid_list(supplicant_network));
4542 #endif
4543         connman_network_set_available(network, true);
4544         connman_network_set_string(network, "WiFi.Mode", mode);
4545
4546 #if defined TIZEN_EXT
4547         if (group)
4548 #else
4549         if (ssid)
4550 #endif
4551                 connman_network_set_group(network, group);
4552
4553 #if defined TIZEN_EXT
4554         if (wifi_first_scan == true)
4555                 found_with_first_scan = true;
4556 #endif
4557
4558         if (wifi->hidden && ssid) {
4559 #if defined TIZEN_EXT
4560                 if (network_security(wifi->hidden->security) ==
4561                         network_security(security) &&
4562 #else
4563                 if (!g_strcmp0(wifi->hidden->security, security) &&
4564 #endif
4565                                 wifi->hidden->ssid_len == ssid_len &&
4566                                 !memcmp(wifi->hidden->ssid, ssid, ssid_len)) {
4567                         connman_network_connect_hidden(network,
4568                                         wifi->hidden->identity,
4569                                         wifi->hidden->passphrase,
4570                                         wifi->hidden->user_data);
4571                         wifi->hidden->user_data = NULL;
4572                         hidden_free(wifi->hidden);
4573                         wifi->hidden = NULL;
4574                 }
4575         }
4576 }
4577
4578 static void network_removed(GSupplicantNetwork *network)
4579 {
4580         GSupplicantInterface *interface;
4581         struct wifi_data *wifi;
4582         const char *name, *identifier;
4583         struct connman_network *connman_network;
4584
4585 #if defined TIZEN_EXT_WIFI_MESH
4586         const char *mode;
4587         mode = g_supplicant_network_get_mode(network);
4588         if (!g_strcmp0(mode, "mesh")) {
4589                 mesh_peer_removed(network);
4590                 return;
4591         }
4592 #endif
4593
4594         interface = g_supplicant_network_get_interface(network);
4595         wifi = g_supplicant_interface_get_data(interface);
4596         identifier = g_supplicant_network_get_identifier(network);
4597         name = g_supplicant_network_get_name(network);
4598
4599         DBG("name %s", name);
4600
4601         if (!wifi)
4602                 return;
4603
4604         connman_network = connman_device_get_network(wifi->device, identifier);
4605         if (!connman_network)
4606                 return;
4607
4608 #if defined TIZEN_EXT
4609         if (connman_network == wifi->scan_pending_network)
4610                 wifi->scan_pending_network = NULL;
4611
4612         if (connman_network == wifi->pending_network)
4613                 wifi->pending_network = NULL;
4614
4615         if(connman_network_get_connecting(connman_network) == true){
4616                 connman_network_set_connected(connman_network, false);
4617         }
4618 #endif
4619
4620         wifi->networks = g_slist_remove(wifi->networks, connman_network);
4621
4622         connman_device_remove_network(wifi->device, connman_network);
4623         connman_network_unref(connman_network);
4624 }
4625
4626 static void network_changed(GSupplicantNetwork *network, const char *property)
4627 {
4628         GSupplicantInterface *interface;
4629         struct wifi_data *wifi;
4630         const char *name, *identifier;
4631         struct connman_network *connman_network;
4632
4633 #if defined TIZEN_EXT
4634         const unsigned char *bssid;
4635         unsigned int maxrate;
4636         uint16_t frequency;
4637         bool wps;
4638         const unsigned char *country_code;
4639         ieee80211_modes_e phy_mode;
4640         GSList *bssid_list;
4641 #endif
4642
4643         interface = g_supplicant_network_get_interface(network);
4644         wifi = g_supplicant_interface_get_data(interface);
4645         identifier = g_supplicant_network_get_identifier(network);
4646         name = g_supplicant_network_get_name(network);
4647
4648         DBG("name %s", name);
4649
4650         if (!wifi)
4651                 return;
4652
4653         connman_network = connman_device_get_network(wifi->device, identifier);
4654         if (!connman_network)
4655                 return;
4656
4657         if (g_str_equal(property, "Signal")) {
4658                connman_network_set_strength(connman_network,
4659                                         calculate_strength(network));
4660                connman_network_update(connman_network);
4661         }
4662
4663 #if defined TIZEN_EXT
4664         bssid = g_supplicant_network_get_bssid(network);
4665         maxrate = g_supplicant_network_get_maxrate(network);
4666         frequency = g_supplicant_network_get_frequency(network);
4667         wps = g_supplicant_network_get_wps(network);
4668         phy_mode = g_supplicant_network_get_phy_mode(network);
4669
4670         connman_network_set_bssid(connman_network, bssid);
4671         connman_network_set_maxrate(connman_network, maxrate);
4672         connman_network_set_frequency(connman_network, frequency);
4673         connman_network_set_bool(connman_network, "WiFi.WPS", wps);
4674         country_code = g_supplicant_network_get_countrycode(network);
4675         connman_network_set_countrycode(connman_network, country_code);
4676         bssid_list = (GSList *)g_supplicant_network_get_bssid_list(network);
4677         connman_network_set_bssid_list(connman_network, bssid_list);
4678         connman_network_set_phy_mode(connman_network, phy_mode);
4679
4680         if (g_str_equal(property, "CheckMultiBssidConnect") &&
4681                         connman_network_get_associating(connman_network))
4682                 network_connect(connman_network);
4683 #endif
4684 }
4685
4686 static void network_associated(GSupplicantNetwork *network)
4687 {
4688         GSupplicantInterface *interface;
4689         struct wifi_data *wifi;
4690         struct connman_network *connman_network;
4691         const char *identifier;
4692
4693         DBG("");
4694
4695         interface = g_supplicant_network_get_interface(network);
4696         if (!interface)
4697                 return;
4698
4699         wifi = g_supplicant_interface_get_data(interface);
4700         if (!wifi)
4701                 return;
4702
4703         identifier = g_supplicant_network_get_identifier(network);
4704
4705         connman_network = connman_device_get_network(wifi->device, identifier);
4706         if (!connman_network)
4707                 return;
4708
4709         if (wifi->network) {
4710                 if (wifi->network == connman_network)
4711                         return;
4712
4713                 /*
4714                  * This should never happen, we got associated with
4715                  * a network different than the one we were expecting.
4716                  */
4717                 DBG("Associated to %p while expecting %p",
4718                                         connman_network, wifi->network);
4719
4720                 connman_network_set_associating(wifi->network, false);
4721         }
4722
4723         DBG("Reconnecting to previous network %p from wpa_s", connman_network);
4724
4725         wifi->network = connman_network_ref(connman_network);
4726         wifi->retries = 0;
4727
4728         /*
4729          * Interface state changes callback (interface_state) is always
4730          * called before network_associated callback thus we need to call
4731          * interface_state again in order to process the new state now that
4732          * we have the network properly set.
4733          */
4734         interface_state(interface);
4735 }
4736
4737 static void apply_peer_services(GSupplicantPeer *peer,
4738                                 struct connman_peer *connman_peer)
4739 {
4740         const unsigned char *data;
4741         int length;
4742
4743         DBG("");
4744
4745         connman_peer_reset_services(connman_peer);
4746
4747         data = g_supplicant_peer_get_widi_ies(peer, &length);
4748         if (data) {
4749                 connman_peer_add_service(connman_peer,
4750                         CONNMAN_PEER_SERVICE_WIFI_DISPLAY, data, length);
4751         }
4752 }
4753
4754 static void add_station(const char *mac)
4755 {
4756         connman_technology_tethering_add_station(CONNMAN_SERVICE_TYPE_WIFI,
4757                                                  mac);
4758 }
4759
4760 static void remove_station(const char *mac)
4761 {
4762         connman_technology_tethering_remove_station(mac);
4763 }
4764
4765 static void peer_found(GSupplicantPeer *peer)
4766 {
4767         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
4768         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
4769         struct connman_peer *connman_peer;
4770         const char *identifier, *name;
4771         int ret;
4772 #if defined TIZEN_EXT
4773         if (!wifi)
4774                 return;
4775 #endif
4776         identifier = g_supplicant_peer_get_identifier(peer);
4777         name = g_supplicant_peer_get_name(peer);
4778
4779         DBG("ident: %s", identifier);
4780
4781         connman_peer = connman_peer_get(wifi->device, identifier);
4782         if (connman_peer)
4783                 return;
4784
4785         connman_peer = connman_peer_create(identifier);
4786         connman_peer_set_name(connman_peer, name);
4787         connman_peer_set_device(connman_peer, wifi->device);
4788         apply_peer_services(peer, connman_peer);
4789
4790         ret = connman_peer_register(connman_peer);
4791         if (ret < 0 && ret != -EALREADY)
4792                 connman_peer_unref(connman_peer);
4793         else
4794                 wifi->peers = g_slist_prepend(wifi->peers, connman_peer);
4795 }
4796
4797 static void peer_lost(GSupplicantPeer *peer)
4798 {
4799         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
4800         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
4801         struct connman_peer *connman_peer;
4802         const char *identifier;
4803
4804         if (!wifi)
4805                 return;
4806
4807         identifier = g_supplicant_peer_get_identifier(peer);
4808
4809         DBG("ident: %s", identifier);
4810
4811         connman_peer = connman_peer_get(wifi->device, identifier);
4812         if (connman_peer) {
4813                 if (wifi->p2p_connecting &&
4814                                 wifi->pending_peer == connman_peer) {
4815                         peer_connect_timeout(wifi);
4816                 }
4817                 connman_peer_unregister(connman_peer);
4818                 connman_peer_unref(connman_peer);
4819         }
4820
4821         wifi->peers = g_slist_remove(wifi->peers, connman_peer);
4822 }
4823
4824 static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state)
4825 {
4826         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
4827         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
4828         enum connman_peer_state p_state = CONNMAN_PEER_STATE_UNKNOWN;
4829         struct connman_peer *connman_peer;
4830         const char *identifier;
4831
4832         identifier = g_supplicant_peer_get_identifier(peer);
4833
4834         DBG("ident: %s", identifier);
4835
4836         if (!wifi)
4837                 return;
4838
4839         connman_peer = connman_peer_get(wifi->device, identifier);
4840         if (!connman_peer)
4841                 return;
4842
4843         switch (state) {
4844         case G_SUPPLICANT_PEER_SERVICES_CHANGED:
4845                 apply_peer_services(peer, connman_peer);
4846                 connman_peer_services_changed(connman_peer);
4847                 return;
4848         case G_SUPPLICANT_PEER_GROUP_CHANGED:
4849                 if (!g_supplicant_peer_is_in_a_group(peer))
4850                         p_state = CONNMAN_PEER_STATE_IDLE;
4851                 else
4852                         p_state = CONNMAN_PEER_STATE_CONFIGURATION;
4853                 break;
4854         case G_SUPPLICANT_PEER_GROUP_STARTED:
4855                 break;
4856         case G_SUPPLICANT_PEER_GROUP_FINISHED:
4857                 p_state = CONNMAN_PEER_STATE_IDLE;
4858                 break;
4859         case G_SUPPLICANT_PEER_GROUP_JOINED:
4860                 connman_peer_set_iface_address(connman_peer,
4861                                 g_supplicant_peer_get_iface_address(peer));
4862                 break;
4863         case G_SUPPLICANT_PEER_GROUP_DISCONNECTED:
4864                 p_state = CONNMAN_PEER_STATE_IDLE;
4865                 break;
4866         case G_SUPPLICANT_PEER_GROUP_FAILED:
4867                 if (g_supplicant_peer_has_requested_connection(peer))
4868                         p_state = CONNMAN_PEER_STATE_IDLE;
4869                 else
4870                         p_state = CONNMAN_PEER_STATE_FAILURE;
4871                 break;
4872         }
4873
4874         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION ||
4875                                         p_state == CONNMAN_PEER_STATE_FAILURE) {
4876                 if (wifi->p2p_connecting
4877                                 && connman_peer == wifi->pending_peer)
4878                         peer_cancel_timeout(wifi);
4879                 else
4880                         p_state = CONNMAN_PEER_STATE_UNKNOWN;
4881         }
4882
4883         if (p_state == CONNMAN_PEER_STATE_UNKNOWN)
4884                 return;
4885
4886         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION) {
4887                 GSupplicantInterface *g_iface;
4888                 struct wifi_data *g_wifi;
4889
4890                 g_iface = g_supplicant_peer_get_group_interface(peer);
4891                 if (!g_iface)
4892                         return;
4893
4894                 g_wifi = g_supplicant_interface_get_data(g_iface);
4895                 if (!g_wifi)
4896                         return;
4897
4898                 connman_peer_set_as_master(connman_peer,
4899                                         !g_supplicant_peer_is_client(peer));
4900                 connman_peer_set_sub_device(connman_peer, g_wifi->device);
4901
4902                 /*
4903                  * If wpa_supplicant didn't create a dedicated p2p-group
4904                  * interface then mark this interface as p2p_device to avoid
4905                  * scan and auto-scan are launched on it while P2P is connected.
4906                  */
4907                 if (!g_list_find(p2p_iface_list, g_wifi))
4908                         wifi->p2p_device = true;
4909         }
4910
4911         connman_peer_set_state(connman_peer, p_state);
4912 }
4913
4914 static void peer_request(GSupplicantPeer *peer)
4915 {
4916         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
4917         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
4918         struct connman_peer *connman_peer;
4919         const char *identifier;
4920
4921 #if defined TIZEN_EXT
4922         if (!wifi)
4923                 return;
4924 #endif
4925
4926         identifier = g_supplicant_peer_get_identifier(peer);
4927
4928         DBG("ident: %s", identifier);
4929
4930         connman_peer = connman_peer_get(wifi->device, identifier);
4931         if (!connman_peer)
4932                 return;
4933
4934         connman_peer_request_connection(connman_peer);
4935 }
4936
4937 #if defined TIZEN_EXT
4938 static void system_power_off(void)
4939 {
4940         GList *list;
4941         struct wifi_data *wifi;
4942         struct connman_service *service;
4943         struct connman_ipconfig *ipconfig_ipv4;
4944
4945         if (connman_setting_get_bool("WiFiDHCPRelease") == true) {
4946                 for (list = iface_list; list; list = list->next) {
4947                         wifi = list->data;
4948
4949                         if (wifi->network != NULL) {
4950                                 service = connman_service_lookup_from_network(wifi->network);
4951                                 ipconfig_ipv4 = __connman_service_get_ip4config(service);
4952                                 __connman_dhcp_stop(ipconfig_ipv4);
4953                         }
4954                 }
4955         }
4956 }
4957
4958 static void network_merged(GSupplicantNetwork *network)
4959 {
4960         GSupplicantInterface *interface;
4961         GSupplicantState state;
4962         struct wifi_data *wifi;
4963         const char *identifier;
4964         struct connman_network *connman_network;
4965         bool ishs20AP = 0;
4966         char *temp = NULL;
4967
4968         interface = g_supplicant_network_get_interface(network);
4969         if (!interface)
4970                 return;
4971
4972         state = g_supplicant_interface_get_state(interface);
4973         if (state < G_SUPPLICANT_STATE_AUTHENTICATING)
4974                 return;
4975
4976         wifi = g_supplicant_interface_get_data(interface);
4977         if (!wifi)
4978                 return;
4979
4980         identifier = g_supplicant_network_get_identifier(network);
4981
4982         connman_network = connman_device_get_network(wifi->device, identifier);
4983         if (!connman_network)
4984                 return;
4985
4986         DBG("merged identifier %s", identifier);
4987
4988         if (wifi->connected == FALSE) {
4989                 switch (state) {
4990                 case G_SUPPLICANT_STATE_AUTHENTICATING:
4991                 case G_SUPPLICANT_STATE_ASSOCIATING:
4992                 case G_SUPPLICANT_STATE_ASSOCIATED:
4993                 case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4994                 case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4995                         connman_network_set_associating(connman_network, TRUE);
4996                         break;
4997                 case G_SUPPLICANT_STATE_COMPLETED:
4998                         connman_network_set_connected(connman_network, TRUE);
4999                         break;
5000                 default:
5001                         DBG("Not handled the state : %d", state);
5002                         break;
5003                 }
5004         }
5005
5006         ishs20AP = g_supplicant_network_is_hs20AP(network);
5007
5008         if (ishs20AP &&
5009                 g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) {
5010                 temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1);
5011                 connman_network_set_string(connman_network, "WiFi.EAP",
5012                                 temp);
5013                 connman_network_set_string(connman_network, "WiFi.Identity",
5014                                 g_supplicant_network_get_identity(network));
5015                 connman_network_set_string(connman_network, "WiFi.Phase2",
5016                                 g_supplicant_network_get_phase2(network));
5017
5018                 g_free(temp);
5019         }
5020
5021         wifi->network = connman_network;
5022 }
5023
5024 static void assoc_failed(void *user_data)
5025 {
5026         struct connman_network *network = user_data;
5027         connman_network_set_associating(network, false);
5028 }
5029 #endif
5030
5031 static void debug(const char *str)
5032 {
5033         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
5034                 connman_debug("%s", str);
5035 }
5036
5037 static void disconnect_reasoncode(GSupplicantInterface *interface,
5038                                 int reasoncode)
5039 {
5040         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5041
5042         if (wifi != NULL) {
5043                 wifi->disconnect_code = reasoncode;
5044         }
5045 }
5046
5047 static void assoc_status_code(GSupplicantInterface *interface, int status_code)
5048 {
5049         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5050
5051         if (wifi != NULL) {
5052                 wifi->assoc_code = status_code;
5053         }
5054 }
5055
5056 static const GSupplicantCallbacks callbacks = {
5057         .system_ready           = system_ready,
5058         .system_killed          = system_killed,
5059         .interface_added        = interface_added,
5060         .interface_state        = interface_state,
5061         .interface_removed      = interface_removed,
5062         .p2p_support            = p2p_support,
5063         .scan_started           = scan_started,
5064         .scan_finished          = scan_finished,
5065         .ap_create_fail         = ap_create_fail,
5066         .network_added          = network_added,
5067         .network_removed        = network_removed,
5068         .network_changed        = network_changed,
5069         .network_associated     = network_associated,
5070         .add_station            = add_station,
5071         .remove_station         = remove_station,
5072         .peer_found             = peer_found,
5073         .peer_lost              = peer_lost,
5074         .peer_changed           = peer_changed,
5075         .peer_request           = peer_request,
5076 #if defined TIZEN_EXT
5077         .system_power_off       = system_power_off,
5078         .network_merged = network_merged,
5079         .assoc_failed           = assoc_failed,
5080 #endif
5081         .debug                  = debug,
5082         .disconnect_reasoncode  = disconnect_reasoncode,
5083         .assoc_status_code      = assoc_status_code,
5084 #if defined TIZEN_EXT_WIFI_MESH
5085         .mesh_support           = mesh_support,
5086         .mesh_group_started = mesh_group_started,
5087         .mesh_group_removed = mesh_group_removed,
5088         .mesh_peer_connected = mesh_peer_connected,
5089         .mesh_peer_disconnected = mesh_peer_disconnected,
5090 #endif
5091 };
5092
5093
5094 static int tech_probe(struct connman_technology *technology)
5095 {
5096         wifi_technology = technology;
5097
5098         return 0;
5099 }
5100
5101 static void tech_remove(struct connman_technology *technology)
5102 {
5103         wifi_technology = NULL;
5104 }
5105
5106 static GSupplicantSSID *ssid_ap_init(const char *ssid,
5107                 const char *passphrase)
5108 {
5109         GSupplicantSSID *ap;
5110
5111         ap = g_try_malloc0(sizeof(GSupplicantSSID));
5112         if (!ap)
5113                 return NULL;
5114
5115         ap->mode = G_SUPPLICANT_MODE_MASTER;
5116 #if defined TIZEN_EXT
5117         ap->ssid = (void *) ssid;
5118 #else
5119         ap->ssid = ssid;
5120 #endif
5121         ap->ssid_len = strlen(ssid);
5122         ap->scan_ssid = 0;
5123         ap->freq = 2412;
5124
5125         if (!passphrase || strlen(passphrase) == 0) {
5126                 ap->security = G_SUPPLICANT_SECURITY_NONE;
5127                 ap->passphrase = NULL;
5128         } else {
5129                ap->security = G_SUPPLICANT_SECURITY_PSK;
5130                ap->protocol = G_SUPPLICANT_PROTO_RSN;
5131                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
5132                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
5133                ap->passphrase = passphrase;
5134         }
5135
5136         return ap;
5137 }
5138
5139 static void ap_start_callback(int result, GSupplicantInterface *interface,
5140                                                         void *user_data)
5141 {
5142         struct wifi_tethering_info *info = user_data;
5143
5144         DBG("result %d index %d bridge %s",
5145                 result, info->wifi->index, info->wifi->bridge);
5146
5147         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
5148                 connman_inet_remove_from_bridge(info->wifi->index,
5149                                                         info->wifi->bridge);
5150
5151                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
5152                         connman_technology_tethering_notify(info->technology, false);
5153                         g_free(info->wifi->tethering_param->ssid);
5154                         g_free(info->wifi->tethering_param);
5155                         info->wifi->tethering_param = NULL;
5156                 }
5157         }
5158
5159         g_free(info->ifname);
5160         g_free(info);
5161 }
5162
5163 static void ap_create_callback(int result,
5164                                 GSupplicantInterface *interface,
5165                                         void *user_data)
5166 {
5167         struct wifi_tethering_info *info = user_data;
5168
5169         DBG("result %d ifname %s", result,
5170                                 g_supplicant_interface_get_ifname(interface));
5171
5172         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
5173                 connman_inet_remove_from_bridge(info->wifi->index,
5174                                                         info->wifi->bridge);
5175
5176                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
5177                         connman_technology_tethering_notify(info->technology, false);
5178                         g_free(info->wifi->tethering_param->ssid);
5179                         g_free(info->wifi->tethering_param);
5180                         info->wifi->tethering_param = NULL;
5181
5182                 }
5183
5184                 g_free(info->ifname);
5185                 g_free(info->ssid);
5186                 g_free(info);
5187                 return;
5188         }
5189
5190         info->wifi->interface = interface;
5191         g_supplicant_interface_set_data(interface, info->wifi);
5192
5193         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
5194                 connman_error("Failed to set interface ap_scan property");
5195
5196         g_supplicant_interface_connect(interface, info->ssid,
5197                                                 ap_start_callback, info);
5198 }
5199
5200 static void sta_remove_callback(int result,
5201                                 GSupplicantInterface *interface,
5202                                         void *user_data)
5203 {
5204         struct wifi_tethering_info *info = user_data;
5205         const char *driver = connman_option_get_string("wifi");
5206
5207         DBG("ifname %s result %d ", info->ifname, result);
5208
5209         if (result < 0 || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
5210                 info->wifi->tethering = false;
5211                 connman_technology_tethering_notify(info->technology, false);
5212
5213                 g_free(info->ifname);
5214                 g_free(info->ssid);
5215                 g_free(info);
5216
5217                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
5218                         g_free(info->wifi->tethering_param->ssid);
5219                         g_free(info->wifi->tethering_param);
5220                         info->wifi->tethering_param = NULL;
5221                 }
5222                 return;
5223         }
5224
5225         info->wifi->interface = NULL;
5226
5227         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
5228                                                 ap_create_callback,
5229                                                         info);
5230 }
5231
5232 static int enable_wifi_tethering(struct connman_technology *technology,
5233                                 const char *bridge, const char *identifier,
5234                                 const char *passphrase, bool available)
5235 {
5236         GList *list;
5237         GSupplicantInterface *interface;
5238         struct wifi_data *wifi;
5239         struct wifi_tethering_info *info;
5240         const char *ifname;
5241         unsigned int mode;
5242         int err, berr = 0;
5243
5244         for (list = iface_list; list; list = list->next) {
5245                 wifi = list->data;
5246
5247                 DBG("wifi %p network %p pending_network %p", wifi,
5248                         wifi->network, wifi->pending_network);
5249
5250                 interface = wifi->interface;
5251
5252                 if (!interface)
5253                         continue;
5254
5255                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED)
5256                         continue;
5257
5258                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
5259
5260                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED) {
5261                         DBG("%s does not support AP mode (detected)", ifname);
5262                         continue;
5263                 }
5264
5265                 mode = g_supplicant_interface_get_mode(interface);
5266                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
5267                         wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
5268                         DBG("%s does not support AP mode (capability)", ifname);
5269                         continue;
5270                 }
5271
5272                 if (wifi->network && available)
5273                         continue;
5274
5275                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
5276                 if (!info)
5277                         return -ENOMEM;
5278
5279                 wifi->tethering_param = g_try_malloc0(sizeof(struct wifi_tethering_info));
5280                 if (!wifi->tethering_param) {
5281                         g_free(info);
5282                         return -ENOMEM;
5283                 }
5284
5285                 info->wifi = wifi;
5286                 info->technology = technology;
5287                 info->wifi->bridge = bridge;
5288                 info->ssid = ssid_ap_init(identifier, passphrase);
5289                 if (!info->ssid)
5290                         goto failed;
5291
5292                 info->ifname = g_strdup(ifname);
5293                 if (!info->ifname)
5294                         goto failed;
5295
5296                 wifi->tethering_param->technology = technology;
5297                 wifi->tethering_param->ssid = ssid_ap_init(identifier, passphrase);
5298                 if (!wifi->tethering_param->ssid)
5299                         goto failed;
5300
5301                 info->wifi->tethering = true;
5302                 info->wifi->ap_supported = WIFI_AP_SUPPORTED;
5303
5304                 berr = connman_technology_tethering_notify(technology, true);
5305                 if (berr < 0)
5306                         goto failed;
5307
5308                 err = g_supplicant_interface_remove(interface,
5309                                                 sta_remove_callback,
5310                                                         info);
5311                 if (err >= 0) {
5312                         DBG("tethering wifi %p ifname %s", wifi, ifname);
5313                         return 0;
5314                 }
5315
5316         failed:
5317                 g_free(info->ifname);
5318                 g_free(info->ssid);
5319                 g_free(info);
5320                 g_free(wifi->tethering_param);
5321                 wifi->tethering_param = NULL;
5322
5323                 /*
5324                  * Remove bridge if it was correctly created but remove
5325                  * operation failed. Instead, if bridge creation failed then
5326                  * break out and do not try again on another interface,
5327                  * bridge set-up does not depend on it.
5328                  */
5329                 if (berr == 0)
5330                         connman_technology_tethering_notify(technology, false);
5331                 else
5332                         break;
5333         }
5334
5335         return -EOPNOTSUPP;
5336 }
5337
5338 static int tech_set_tethering(struct connman_technology *technology,
5339                                 const char *identifier, const char *passphrase,
5340                                 const char *bridge, bool enabled)
5341 {
5342         GList *list;
5343         struct wifi_data *wifi;
5344         int err;
5345
5346         DBG("");
5347
5348         if (!enabled) {
5349                 for (list = iface_list; list; list = list->next) {
5350                         wifi = list->data;
5351
5352                         if (wifi->tethering) {
5353                                 wifi->tethering = false;
5354
5355                                 connman_inet_remove_from_bridge(wifi->index,
5356                                                                         bridge);
5357                                 wifi->bridged = false;
5358                         }
5359                 }
5360
5361                 connman_technology_tethering_notify(technology, false);
5362
5363                 return 0;
5364         }
5365
5366         DBG("trying tethering for available devices");
5367         err = enable_wifi_tethering(technology, bridge, identifier, passphrase,
5368                                 true);
5369
5370         if (err < 0) {
5371                 DBG("trying tethering for any device");
5372                 err = enable_wifi_tethering(technology, bridge, identifier,
5373                                         passphrase, false);
5374         }
5375
5376         return err;
5377 }
5378
5379 static void regdom_callback(int result, const char *alpha2, void *user_data)
5380 {
5381         DBG("");
5382
5383         if (!wifi_technology)
5384                 return;
5385
5386         if (result != 0)
5387                 alpha2 = NULL;
5388
5389         connman_technology_regdom_notify(wifi_technology, alpha2);
5390 }
5391
5392 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
5393 {
5394         return g_supplicant_set_country(alpha2, regdom_callback, NULL);
5395 }
5396
5397 static struct connman_technology_driver tech_driver = {
5398         .name           = "wifi",
5399         .type           = CONNMAN_SERVICE_TYPE_WIFI,
5400         .probe          = tech_probe,
5401         .remove         = tech_remove,
5402         .set_tethering  = tech_set_tethering,
5403         .set_regdom     = tech_set_regdom,
5404 };
5405
5406 static int wifi_init(void)
5407 {
5408         int err;
5409
5410         err = connman_network_driver_register(&network_driver);
5411         if (err < 0)
5412                 return err;
5413
5414         err = g_supplicant_register(&callbacks);
5415         if (err < 0) {
5416                 connman_network_driver_unregister(&network_driver);
5417                 return err;
5418         }
5419
5420         err = connman_technology_driver_register(&tech_driver);
5421         if (err < 0) {
5422                 g_supplicant_unregister(&callbacks);
5423                 connman_network_driver_unregister(&network_driver);
5424                 return err;
5425         }
5426
5427 #if defined TIZEN_EXT
5428         failed_bssids = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
5429 #endif
5430         return 0;
5431 }
5432
5433 static void wifi_exit(void)
5434 {
5435         DBG();
5436
5437         connman_technology_driver_unregister(&tech_driver);
5438
5439         g_supplicant_unregister(&callbacks);
5440
5441         connman_network_driver_unregister(&network_driver);
5442
5443 #if defined TIZEN_EXT
5444         g_hash_table_unref(failed_bssids);
5445 #endif
5446 }
5447
5448 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
5449                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)