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