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