Added support to get maximum scan SSIDs.
[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         /* Max number of SSIDs supported by wlan chipset that can be scanned */
3637         int max_scan_ssids = g_supplicant_interface_get_max_scan_ssids(interface);
3638         connman_techonology_set_max_scan_ssids(wifi_technology, max_scan_ssids);
3639 #endif
3640 }
3641
3642 static bool is_idle(struct wifi_data *wifi)
3643 {
3644         DBG("state %d", wifi->state);
3645
3646         switch (wifi->state) {
3647         case G_SUPPLICANT_STATE_UNKNOWN:
3648         case G_SUPPLICANT_STATE_DISABLED:
3649         case G_SUPPLICANT_STATE_DISCONNECTED:
3650         case G_SUPPLICANT_STATE_INACTIVE:
3651         case G_SUPPLICANT_STATE_SCANNING:
3652                 return true;
3653
3654         case G_SUPPLICANT_STATE_AUTHENTICATING:
3655         case G_SUPPLICANT_STATE_ASSOCIATING:
3656         case G_SUPPLICANT_STATE_ASSOCIATED:
3657         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3658         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3659         case G_SUPPLICANT_STATE_COMPLETED:
3660                 return false;
3661         }
3662
3663         return false;
3664 }
3665
3666 static bool is_idle_wps(GSupplicantInterface *interface,
3667                                                 struct wifi_data *wifi)
3668 {
3669         /* First, let's check if WPS processing did not went wrong */
3670         if (g_supplicant_interface_get_wps_state(interface) ==
3671                 G_SUPPLICANT_WPS_STATE_FAIL)
3672                 return false;
3673
3674         /* Unlike normal connection, being associated while processing wps
3675          * actually means that we are idling. */
3676         switch (wifi->state) {
3677         case G_SUPPLICANT_STATE_UNKNOWN:
3678         case G_SUPPLICANT_STATE_DISABLED:
3679         case G_SUPPLICANT_STATE_DISCONNECTED:
3680         case G_SUPPLICANT_STATE_INACTIVE:
3681         case G_SUPPLICANT_STATE_SCANNING:
3682         case G_SUPPLICANT_STATE_ASSOCIATED:
3683                 return true;
3684         case G_SUPPLICANT_STATE_AUTHENTICATING:
3685         case G_SUPPLICANT_STATE_ASSOCIATING:
3686         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3687         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3688         case G_SUPPLICANT_STATE_COMPLETED:
3689                 return false;
3690         }
3691
3692         return false;
3693 }
3694
3695 static bool handle_wps_completion(GSupplicantInterface *interface,
3696                                         struct connman_network *network,
3697                                         struct connman_device *device,
3698                                         struct wifi_data *wifi)
3699 {
3700         bool wps;
3701
3702         wps = connman_network_get_bool(network, "WiFi.UseWPS");
3703         if (wps) {
3704                 const unsigned char *ssid, *wps_ssid;
3705                 unsigned int ssid_len, wps_ssid_len;
3706                 const char *wps_key;
3707
3708                 /* Checking if we got associated with requested
3709                  * network */
3710                 ssid = connman_network_get_blob(network, "WiFi.SSID",
3711                                                 &ssid_len);
3712
3713                 wps_ssid = g_supplicant_interface_get_wps_ssid(
3714                         interface, &wps_ssid_len);
3715
3716                 if (!wps_ssid || wps_ssid_len != ssid_len ||
3717                                 memcmp(ssid, wps_ssid, ssid_len) != 0) {
3718                         connman_network_set_associating(network, false);
3719 #if defined TIZEN_EXT
3720                         g_supplicant_interface_disconnect(wifi->interface,
3721                                                 disconnect_callback, wifi->network);
3722
3723                         connman_network_set_bool(network, "WiFi.UseWPS", false);
3724                         connman_network_set_string(network, "WiFi.PinWPS", NULL);
3725 #else
3726                         g_supplicant_interface_disconnect(wifi->interface,
3727                                                 disconnect_callback, wifi);
3728 #endif
3729                         return false;
3730                 }
3731
3732                 wps_key = g_supplicant_interface_get_wps_key(interface);
3733 #if defined TIZEN_EXT
3734                 /* Check the passphrase and encrypt it
3735                  */
3736                  int ret;
3737                  gchar *passphrase = g_strdup(wps_key);
3738
3739                  connman_network_set_string(network, "WiFi.PinWPS", NULL);
3740
3741                  if (check_passphrase_ext(network, passphrase) < 0) {
3742                          DBG("[WPS] Invalid passphrase");
3743                          g_free(passphrase);
3744                          return true;
3745                  }
3746
3747                  ret = send_encryption_request(passphrase, network);
3748
3749                  g_free(passphrase);
3750
3751                  if (!ret)
3752                          DBG("[WPS] Encryption request succeeded");
3753                  else
3754                          DBG("[WPS] Encryption request failed %d", ret);
3755
3756 #else
3757                 connman_network_set_string(network, "WiFi.Passphrase",
3758                                         wps_key);
3759
3760                 connman_network_set_string(network, "WiFi.PinWPS", NULL);
3761 #endif
3762         }
3763
3764         return true;
3765 }
3766
3767 static bool handle_assoc_status_code(GSupplicantInterface *interface,
3768                                      struct wifi_data *wifi)
3769 {
3770         if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING &&
3771 #if defined TIZEN_EXT
3772                         wifi->assoc_code > 0 &&
3773 #else
3774                         wifi->assoc_code == ASSOC_STATUS_NO_CLIENT &&
3775 #endif
3776                         wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) {
3777                 wifi->load_shaping_retries ++;
3778                 return TRUE;
3779         }
3780         wifi->load_shaping_retries = 0;
3781         return FALSE;
3782 }
3783
3784 static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
3785                                         struct connman_network *network,
3786                                         struct wifi_data *wifi)
3787 {
3788 #if defined TIZEN_EXT
3789         const char *security;
3790         struct connman_service *service;
3791
3792         if (wifi->connected)
3793                 return false;
3794
3795         security = connman_network_get_string(network, "WiFi.Security");
3796
3797         if (security && g_str_equal(security, "ieee8021x") == true &&
3798                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
3799                 wifi->retries = 0;
3800                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
3801
3802                 return false;
3803         }
3804
3805         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
3806                 return false;
3807 #else
3808         struct connman_service *service;
3809
3810         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
3811                 return false;
3812
3813         if (wifi->connected)
3814                 return false;
3815 #endif
3816
3817         service = connman_service_lookup_from_network(network);
3818         if (!service)
3819                 return false;
3820
3821         wifi->retries++;
3822
3823         if (connman_service_get_favorite(service)) {
3824                 if (wifi->retries < FAVORITE_MAXIMUM_RETRIES)
3825                         return true;
3826         }
3827
3828         wifi->retries = 0;
3829         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
3830
3831         return false;
3832 }
3833
3834 #if defined TIZEN_EXT
3835 static bool handle_wifi_assoc_retry(struct connman_network *network,
3836                                         struct wifi_data *wifi)
3837 {
3838         const char *security;
3839
3840         if (!wifi->network || wifi->connected || wifi->disconnecting ||
3841                         connman_network_get_connecting(network) != true) {
3842                 wifi->assoc_retry_count = 0;
3843                 return false;
3844         }
3845
3846         if (wifi->state != G_SUPPLICANT_STATE_ASSOCIATING &&
3847                         wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) {
3848                 wifi->assoc_retry_count = 0;
3849                 return false;
3850         }
3851
3852         security = connman_network_get_string(network, "WiFi.Security");
3853         if (security && g_str_equal(security, "ieee8021x") == true &&
3854                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
3855                 wifi->assoc_retry_count = 0;
3856                 return false;
3857         }
3858
3859         if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) {
3860                 wifi->assoc_retry_count = 0;
3861
3862                 /* Honestly it's not an invalid-key error,
3863                  * however QA team recommends that the invalid-key error
3864                  * might be better to display for user experience.
3865                  */
3866                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
3867
3868                 return false;
3869         }
3870
3871         return true;
3872 }
3873 #endif
3874
3875 static void interface_state(GSupplicantInterface *interface)
3876 {
3877         struct connman_network *network;
3878         struct connman_device *device;
3879         struct wifi_data *wifi;
3880         GSupplicantState state = g_supplicant_interface_get_state(interface);
3881         bool wps;
3882         bool old_connected;
3883
3884         wifi = g_supplicant_interface_get_data(interface);
3885
3886         DBG("wifi %p interface state %d", wifi, state);
3887
3888         if (!wifi)
3889                 return;
3890
3891         if (state == G_SUPPLICANT_STATE_COMPLETED) {
3892                 if (wifi->tethering_param) {
3893                         g_free(wifi->tethering_param->ssid);
3894                         g_free(wifi->tethering_param);
3895                         wifi->tethering_param = NULL;
3896                 }
3897         }
3898
3899         device = wifi->device;
3900         if (!device)
3901                 return;
3902
3903         if (g_supplicant_interface_get_ready(interface) &&
3904                                         !wifi->interface_ready) {
3905                 wifi->interface_ready = true;
3906                 finalize_interface_creation(wifi);
3907         }
3908
3909         network = wifi->network;
3910         if (!network)
3911                 return;
3912
3913         switch (state) {
3914         case G_SUPPLICANT_STATE_SCANNING:
3915                 if (wifi->connected)
3916                         connman_network_set_connected(network, false);
3917
3918                 break;
3919
3920         case G_SUPPLICANT_STATE_AUTHENTICATING:
3921         case G_SUPPLICANT_STATE_ASSOCIATING:
3922 #if defined TIZEN_EXT
3923                 reset_autoscan(device);
3924 #else
3925                 stop_autoscan(device);
3926 #endif
3927
3928                 if (!wifi->connected)
3929                         connman_network_set_associating(network, true);
3930
3931                 break;
3932
3933         case G_SUPPLICANT_STATE_COMPLETED:
3934 #if defined TIZEN_EXT
3935                 /* though it should be already reset: */
3936                 reset_autoscan(device);
3937
3938                 wifi->assoc_retry_count = 0;
3939
3940                 wifi->scan_pending_network = NULL;
3941
3942                 /* should be cleared scanning flag */
3943                 bool scanning = connman_device_get_scanning(device);
3944                 if (scanning){
3945                         connman_device_set_scanning(device,
3946                                 CONNMAN_SERVICE_TYPE_WIFI, false);
3947                         connman_device_unref(device);
3948                 }
3949
3950                 if (!wifi->automaxspeed_timeout) {
3951                         DBG("Going to start signalpoll timer!!");
3952                         int ret = network_signalpoll(wifi);
3953                         if (ret < 0)
3954                                 DBG("Fail to get max speed !!");
3955                         else
3956                                 wifi->automaxspeed_timeout = g_timeout_add_seconds(30, autosignalpoll_timeout, wifi);
3957                 }
3958 #else
3959                 /* though it should be already stopped: */
3960                 stop_autoscan(device);
3961 #endif
3962
3963                 if (!handle_wps_completion(interface, network, device, wifi))
3964                         break;
3965
3966                 connman_network_set_connected(network, true);
3967
3968                 wifi->disconnect_code = 0;
3969                 wifi->assoc_code = 0;
3970                 wifi->load_shaping_retries = 0;
3971                 break;
3972
3973         case G_SUPPLICANT_STATE_DISCONNECTED:
3974 #if defined TIZEN_EXT
3975                 connman_network_set_maxspeed(network, 0);
3976
3977                 if (wifi->automaxspeed_timeout != 0) {
3978                         g_source_remove(wifi->automaxspeed_timeout);
3979                         wifi->automaxspeed_timeout = 0;
3980                         DBG("Remove signalpoll timer!!");
3981                 }
3982 #endif
3983                 /*
3984                  * If we're in one of the idle modes, we have
3985                  * not started association yet and thus setting
3986                  * those ones to FALSE could cancel an association
3987                  * in progress.
3988                  */
3989                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
3990                 if (wps)
3991                         if (is_idle_wps(interface, wifi))
3992                                 break;
3993
3994                 if (is_idle(wifi))
3995                         break;
3996
3997 #if defined TIZEN_EXT
3998                 if (handle_assoc_status_code(interface, wifi)) {
3999                         network_connect(network);
4000                         break;
4001                 }
4002 #else
4003                 if (handle_assoc_status_code(interface, wifi))
4004                         break;
4005 #endif
4006
4007                 /* If previous state was 4way-handshake, then
4008                  * it's either: psk was incorrect and thus we retry
4009                  * or if we reach the maximum retries we declare the
4010                  * psk as wrong */
4011                 if (handle_4way_handshake_failure(interface,
4012                                                 network, wifi))
4013                         break;
4014
4015                 /* See table 8-36 Reason codes in IEEE Std 802.11 */
4016                 switch (wifi->disconnect_code) {
4017                 case 1: /* Unspecified reason */
4018                         /* Let's assume it's because we got blocked */
4019
4020                 case 6: /* Class 2 frame received from nonauthenticated STA */
4021                         connman_network_set_error(network,
4022                                                 CONNMAN_NETWORK_ERROR_BLOCKED);
4023                         break;
4024
4025                 default:
4026                         break;
4027                 }
4028
4029 #if defined TIZEN_EXT
4030                 /* Some of Wi-Fi networks are not comply Wi-Fi specification.
4031                  * Retry association until its retry count is expired */
4032                 if (handle_wifi_assoc_retry(network, wifi) == true) {
4033                         throw_wifi_scan(wifi->device, scan_callback);
4034                         wifi->scan_pending_network = wifi->network;
4035                         break;
4036                 }
4037
4038                 if(wifi->disconnect_code > 0){
4039                         DBG("Set disconnect reason code(%d)", wifi->disconnect_code);
4040                         connman_network_set_disconnect_reason(network, wifi->disconnect_code);
4041                 }
4042 #endif
4043
4044                 connman_network_set_connected(network, false);
4045                 connman_network_set_associating(network, false);
4046                 wifi->disconnecting = false;
4047
4048                 start_autoscan(device);
4049
4050                 break;
4051
4052         case G_SUPPLICANT_STATE_INACTIVE:
4053 #if defined TIZEN_EXT
4054                 if (handle_wps_completion(interface, network, device, wifi) == false)
4055                         break;
4056 #endif
4057                 connman_network_set_associating(network, false);
4058                 start_autoscan(device);
4059
4060                 break;
4061
4062         case G_SUPPLICANT_STATE_UNKNOWN:
4063         case G_SUPPLICANT_STATE_DISABLED:
4064         case G_SUPPLICANT_STATE_ASSOCIATED:
4065         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4066         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4067                 break;
4068         }
4069
4070         old_connected = wifi->connected;
4071         wifi->state = state;
4072
4073         /* Saving wpa_s state policy:
4074          * If connected and if the state changes are roaming related:
4075          * --> We stay connected
4076          * If completed
4077          * --> We are connected
4078          * All other case:
4079          * --> We are not connected
4080          * */
4081         switch (state) {
4082         case G_SUPPLICANT_STATE_AUTHENTICATING:
4083         case G_SUPPLICANT_STATE_ASSOCIATING:
4084         case G_SUPPLICANT_STATE_ASSOCIATED:
4085         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4086         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4087                 if (wifi->connected)
4088                         connman_warn("Probably roaming right now!"
4089                                                 " Staying connected...");
4090                 break;
4091         case G_SUPPLICANT_STATE_SCANNING:
4092                 wifi->connected = false;
4093
4094                 if (old_connected)
4095                         start_autoscan(device);
4096                 break;
4097         case G_SUPPLICANT_STATE_COMPLETED:
4098                 wifi->connected = true;
4099                 break;
4100         default:
4101                 wifi->connected = false;
4102                 break;
4103         }
4104
4105         DBG("DONE");
4106 }
4107
4108 static void interface_removed(GSupplicantInterface *interface)
4109 {
4110         const char *ifname = g_supplicant_interface_get_ifname(interface);
4111         struct wifi_data *wifi;
4112
4113         DBG("ifname %s", ifname);
4114
4115         wifi = g_supplicant_interface_get_data(interface);
4116
4117 #if defined TIZEN_EXT_WIFI_MESH
4118         if (wifi && wifi->mesh_interface) {
4119                 DBG("Notify mesh interface remove");
4120                 connman_mesh_notify_interface_remove(true);
4121                 struct wifi_mesh_info *mesh_info = wifi->mesh_info;
4122                 g_free(mesh_info->parent_ifname);
4123                 g_free(mesh_info->ifname);
4124                 g_free(mesh_info->identifier);
4125                 g_free(mesh_info);
4126                 wifi->mesh_interface = false;
4127                 wifi->mesh_info = NULL;
4128                 return;
4129         }
4130 #endif
4131
4132         if (wifi)
4133                 wifi->interface = NULL;
4134
4135         if (wifi && wifi->tethering)
4136                 return;
4137
4138         if (!wifi || !wifi->device) {
4139                 DBG("wifi interface already removed");
4140                 return;
4141         }
4142
4143         connman_device_set_powered(wifi->device, false);
4144
4145         check_p2p_technology();
4146 #if defined TIZEN_EXT_WIFI_MESH
4147         check_mesh_technology();
4148 #endif
4149 }
4150
4151 static void set_device_type(const char *type, char dev_type[17])
4152 {
4153         const char *oui = "0050F204";
4154         const char *category = "0001";
4155         const char *sub_category = "0000";
4156
4157         if (!g_strcmp0(type, "handset")) {
4158                 category = "000A";
4159                 sub_category = "0005";
4160         } else if (!g_strcmp0(type, "vm") || !g_strcmp0(type, "container"))
4161                 sub_category = "0001";
4162         else if (!g_strcmp0(type, "server"))
4163                 sub_category = "0002";
4164         else if (!g_strcmp0(type, "laptop"))
4165                 sub_category = "0005";
4166         else if (!g_strcmp0(type, "desktop"))
4167                 sub_category = "0006";
4168         else if (!g_strcmp0(type, "tablet"))
4169                 sub_category = "0009";
4170         else if (!g_strcmp0(type, "watch"))
4171                 category = "00FF";
4172
4173         snprintf(dev_type, 17, "%s%s%s", category, oui, sub_category);
4174 }
4175
4176 static void p2p_support(GSupplicantInterface *interface)
4177 {
4178         char dev_type[17] = {};
4179         const char *hostname;
4180
4181         DBG("");
4182
4183         if (!interface)
4184                 return;
4185
4186         if (!g_supplicant_interface_has_p2p(interface))
4187                 return;
4188
4189         if (connman_technology_driver_register(&p2p_tech_driver) < 0) {
4190                 DBG("Could not register P2P technology driver");
4191                 return;
4192         }
4193
4194         hostname = connman_utsname_get_hostname();
4195         if (!hostname)
4196                 hostname = "ConnMan";
4197
4198         set_device_type(connman_machine_get_type(), dev_type);
4199         g_supplicant_interface_set_p2p_device_config(interface,
4200                                                         hostname, dev_type);
4201         connman_peer_driver_register(&peer_driver);
4202 }
4203
4204 static void scan_started(GSupplicantInterface *interface)
4205 {
4206         DBG("");
4207 }
4208
4209 static void scan_finished(GSupplicantInterface *interface)
4210 {
4211 #if defined TIZEN_EXT
4212         struct wifi_data *wifi;
4213         bool is_associating = false;
4214         static bool is_scanning = true;
4215 #endif
4216
4217         DBG("");
4218
4219 #if defined TIZEN_EXT
4220         wifi = g_supplicant_interface_get_data(interface);
4221         if (wifi && wifi->scan_pending_network) {
4222                 network_connect(wifi->scan_pending_network);
4223                 wifi->scan_pending_network = NULL;
4224         }
4225
4226         //service state - associating
4227         if(!wifi || !wifi->network)
4228                 return;
4229
4230         is_associating = connman_network_get_associating(wifi->network);
4231         if(is_associating && is_scanning){
4232                 is_scanning = false;
4233                 DBG("send scan for connecting");
4234                 throw_wifi_scan(wifi->device, scan_callback);
4235
4236                 return;
4237         }
4238         is_scanning = true;
4239
4240         //go scan
4241
4242 #endif
4243 }
4244
4245 static void ap_create_fail(GSupplicantInterface *interface)
4246 {
4247         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
4248         int ret;
4249
4250         if ((wifi->tethering) && (wifi->tethering_param)) {
4251                 DBG("%s create AP fail \n",
4252                                 g_supplicant_interface_get_ifname(wifi->interface));
4253
4254                 connman_inet_remove_from_bridge(wifi->index, wifi->bridge);
4255                 wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
4256                 wifi->tethering = false;
4257
4258                 ret = tech_set_tethering(wifi->tethering_param->technology,
4259                                 wifi->tethering_param->ssid->ssid,
4260                                 wifi->tethering_param->ssid->passphrase,
4261                                 wifi->bridge, true);
4262
4263                 if ((ret == -EOPNOTSUPP) && (wifi_technology)) {
4264                         connman_technology_tethering_notify(wifi_technology,false);
4265                 }
4266
4267                 g_free(wifi->tethering_param->ssid);
4268                 g_free(wifi->tethering_param);
4269                 wifi->tethering_param = NULL;
4270         }
4271
4272         return;
4273 }
4274
4275 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
4276 {
4277         unsigned char strength;
4278
4279         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
4280
4281 #if !defined TIZEN_EXT
4282         if (strength > 100)
4283                 strength = 100;
4284 #endif
4285         return strength;
4286 }
4287
4288 #if defined TIZEN_EXT_WIFI_MESH
4289 static void mesh_peer_added(GSupplicantNetwork *supplicant_network)
4290 {
4291         GSupplicantInterface *interface;
4292         struct wifi_data *wifi;
4293         const char *name, *security;
4294         struct connman_mesh *connman_mesh;
4295         struct wifi_mesh_info *mesh_info;
4296         const unsigned char *bssid;
4297         const char *identifier;
4298         char *address;
4299         uint16_t frequency;
4300         int ret;
4301
4302         interface = g_supplicant_network_get_interface(supplicant_network);
4303         wifi = g_supplicant_interface_get_data(interface);
4304         if (!wifi || !wifi->mesh_interface) {
4305                 DBG("Virtual Mesh interface not created");
4306                 return;
4307         }
4308
4309         bssid = g_supplicant_network_get_bssid(supplicant_network);
4310         address = g_malloc0(19);
4311         snprintf(address, 19, "%02x:%02x:%02x:%02x:%02x:%02x", bssid[0], bssid[1],
4312                                                                  bssid[2], bssid[3], bssid[4], bssid[5]);
4313
4314         identifier = g_supplicant_network_get_identifier(supplicant_network);
4315         name = g_supplicant_network_get_name(supplicant_network);
4316         security = g_supplicant_network_get_security(supplicant_network);
4317         frequency = g_supplicant_network_get_frequency(supplicant_network);
4318
4319         mesh_info = wifi->mesh_info;
4320         connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
4321         if (connman_mesh)
4322                 goto done;
4323
4324         DBG("Mesh Peer name %s identifier %s security %s added", name, identifier,
4325                                         security);
4326         connman_mesh = connman_mesh_create(mesh_info->identifier, identifier);
4327         connman_mesh_set_name(connman_mesh, name);
4328         connman_mesh_set_security(connman_mesh, security);
4329         connman_mesh_set_frequency(connman_mesh, frequency);
4330         connman_mesh_set_address(connman_mesh, address);
4331         connman_mesh_set_index(connman_mesh, mesh_info->index);
4332         connman_mesh_set_strength(connman_mesh,
4333                                                 calculate_strength(supplicant_network));
4334         connman_mesh_set_peer_type(connman_mesh, CONNMAN_MESH_PEER_TYPE_DISCOVERED);
4335
4336         ret = connman_mesh_register(connman_mesh);
4337         if (ret == -EALREADY)
4338                 DBG("Mesh Peer is already registered");
4339
4340 done:
4341         g_free(address);
4342 }
4343
4344 static void mesh_peer_removed(GSupplicantNetwork *supplicant_network)
4345 {
4346         GSupplicantInterface *interface;
4347         struct wifi_data *wifi;
4348         struct connman_mesh *connman_mesh;
4349         struct wifi_mesh_info *mesh_info;
4350         const char *identifier;
4351
4352         interface = g_supplicant_network_get_interface(supplicant_network);
4353         wifi = g_supplicant_interface_get_data(interface);
4354         if (!wifi || !wifi->mesh_interface) {
4355                 DBG("Virtual Mesh interface not created");
4356                 return;
4357         }
4358
4359         identifier = g_supplicant_network_get_identifier(supplicant_network);
4360         if (!identifier) {
4361                 DBG("Failed to get Mesh Peer identifier");
4362                 return;
4363         }
4364
4365         mesh_info = wifi->mesh_info;
4366         connman_mesh = connman_mesh_get(mesh_info->identifier, identifier);
4367         if (connman_mesh) {
4368                 /* Do not unregister connected mesh peer */
4369                 if (connman_mesh_peer_is_connected_state(connman_mesh)) {
4370                         DBG("Mesh Peer %s is connected", identifier);
4371                         return;
4372                 }
4373                 DBG("Mesh Peer identifier %s removed", identifier);
4374                 connman_mesh_unregister(connman_mesh);
4375         }
4376 }
4377 #endif
4378
4379 static void network_added(GSupplicantNetwork *supplicant_network)
4380 {
4381         struct connman_network *network;
4382         GSupplicantInterface *interface;
4383         struct wifi_data *wifi;
4384         const char *name, *identifier, *security, *group, *mode;
4385         const unsigned char *ssid;
4386         unsigned int ssid_len;
4387         bool wps;
4388         bool wps_pbc;
4389         bool wps_ready;
4390         bool wps_advertizing;
4391
4392 #if defined TIZEN_EXT
4393         GSList *vsie_list = NULL;
4394         const unsigned char *country_code;
4395         ieee80211_modes_e phy_mode;
4396 #endif
4397
4398         mode = g_supplicant_network_get_mode(supplicant_network);
4399         identifier = g_supplicant_network_get_identifier(supplicant_network);
4400
4401         DBG("%s", identifier);
4402
4403         if (!g_strcmp0(mode, "adhoc"))
4404                 return;
4405
4406 #if defined TIZEN_EXT_WIFI_MESH
4407         if (!g_strcmp0(mode, "mesh")) {
4408                 mesh_peer_added(supplicant_network);
4409                 return;
4410         }
4411 #endif
4412
4413         interface = g_supplicant_network_get_interface(supplicant_network);
4414         wifi = g_supplicant_interface_get_data(interface);
4415         name = g_supplicant_network_get_name(supplicant_network);
4416         security = g_supplicant_network_get_security(supplicant_network);
4417         group = g_supplicant_network_get_identifier(supplicant_network);
4418         wps = g_supplicant_network_get_wps(supplicant_network);
4419         wps_pbc = g_supplicant_network_is_wps_pbc(supplicant_network);
4420         wps_ready = g_supplicant_network_is_wps_active(supplicant_network);
4421         wps_advertizing = g_supplicant_network_is_wps_advertizing(
4422                                                         supplicant_network);
4423
4424         if (!wifi)
4425                 return;
4426
4427         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
4428
4429         network = connman_device_get_network(wifi->device, identifier);
4430
4431         if (!network) {
4432                 network = connman_network_create(identifier,
4433                                                 CONNMAN_NETWORK_TYPE_WIFI);
4434                 if (!network)
4435                         return;
4436
4437                 connman_network_set_index(network, wifi->index);
4438
4439                 if (connman_device_add_network(wifi->device, network) < 0) {
4440                         connman_network_unref(network);
4441                         return;
4442                 }
4443
4444                 wifi->networks = g_slist_prepend(wifi->networks, network);
4445         }
4446
4447         if (name && name[0] != '\0')
4448                 connman_network_set_name(network, name);
4449
4450         connman_network_set_blob(network, "WiFi.SSID",
4451                                                 ssid, ssid_len);
4452 #if defined TIZEN_EXT
4453         vsie_list = (GSList *)g_supplicant_network_get_wifi_vsie(supplicant_network);
4454         if (vsie_list)
4455                 connman_network_set_vsie_list(network, vsie_list);
4456         else
4457                 DBG("vsie_list is NULL");
4458         country_code = g_supplicant_network_get_countrycode(supplicant_network);
4459         connman_network_set_countrycode(network, country_code);
4460         phy_mode = g_supplicant_network_get_phy_mode(supplicant_network);
4461         connman_network_set_phy_mode(network, phy_mode);
4462 #endif
4463         connman_network_set_string(network, "WiFi.Security", security);
4464         connman_network_set_strength(network,
4465                                 calculate_strength(supplicant_network));
4466         connman_network_set_bool(network, "WiFi.WPS", wps);
4467
4468         if (wps) {
4469                 /* Is AP advertizing for WPS association?
4470                  * If so, we decide to use WPS by default */
4471                 if (wps_ready && wps_pbc &&
4472                                                 wps_advertizing) {
4473 #if !defined TIZEN_EXT
4474                         connman_network_set_bool(network, "WiFi.UseWPS", true);
4475 #else
4476                         DBG("wps is activating by ap but ignore it.");
4477 #endif
4478                 }
4479         }
4480
4481         connman_network_set_frequency(network,
4482                         g_supplicant_network_get_frequency(supplicant_network));
4483 #if defined TIZEN_EXT
4484         connman_network_set_bssid(network,
4485                         g_supplicant_network_get_bssid(supplicant_network));
4486         connman_network_set_maxrate(network,
4487                         g_supplicant_network_get_maxrate(supplicant_network));
4488         connman_network_set_enc_mode(network,
4489                         g_supplicant_network_get_enc_mode(supplicant_network));
4490         connman_network_set_rsn_mode(network,
4491                         g_supplicant_network_get_rsn_mode(supplicant_network));
4492         connman_network_set_keymgmt(network,
4493                         g_supplicant_network_get_keymgmt(supplicant_network));
4494         connman_network_set_bool(network, "WiFi.HS20AP",
4495                         g_supplicant_network_is_hs20AP(supplicant_network));
4496         connman_network_set_bssid_list(network,
4497                         (GSList *)g_supplicant_network_get_bssid_list(supplicant_network));
4498 #endif
4499         connman_network_set_available(network, true);
4500         connman_network_set_string(network, "WiFi.Mode", mode);
4501
4502 #if defined TIZEN_EXT
4503         if (group)
4504 #else
4505         if (ssid)
4506 #endif
4507                 connman_network_set_group(network, group);
4508
4509 #if defined TIZEN_EXT
4510         if (wifi_first_scan == true)
4511                 found_with_first_scan = true;
4512 #endif
4513
4514         if (wifi->hidden && ssid) {
4515 #if defined TIZEN_EXT
4516                 if (network_security(wifi->hidden->security) ==
4517                         network_security(security) &&
4518 #else
4519                 if (!g_strcmp0(wifi->hidden->security, security) &&
4520 #endif
4521                                 wifi->hidden->ssid_len == ssid_len &&
4522                                 !memcmp(wifi->hidden->ssid, ssid, ssid_len)) {
4523                         connman_network_connect_hidden(network,
4524                                         wifi->hidden->identity,
4525                                         wifi->hidden->passphrase,
4526                                         wifi->hidden->user_data);
4527                         wifi->hidden->user_data = NULL;
4528                         hidden_free(wifi->hidden);
4529                         wifi->hidden = NULL;
4530                 }
4531         }
4532 }
4533
4534 static void network_removed(GSupplicantNetwork *network)
4535 {
4536         GSupplicantInterface *interface;
4537         struct wifi_data *wifi;
4538         const char *name, *identifier;
4539         struct connman_network *connman_network;
4540
4541 #if defined TIZEN_EXT_WIFI_MESH
4542         const char *mode;
4543         mode = g_supplicant_network_get_mode(network);
4544         if (!g_strcmp0(mode, "mesh")) {
4545                 mesh_peer_removed(network);
4546                 return;
4547         }
4548 #endif
4549
4550         interface = g_supplicant_network_get_interface(network);
4551         wifi = g_supplicant_interface_get_data(interface);
4552         identifier = g_supplicant_network_get_identifier(network);
4553         name = g_supplicant_network_get_name(network);
4554
4555         DBG("name %s", name);
4556
4557         if (!wifi)
4558                 return;
4559
4560         connman_network = connman_device_get_network(wifi->device, identifier);
4561         if (!connman_network)
4562                 return;
4563
4564 #if defined TIZEN_EXT
4565         if (connman_network == wifi->scan_pending_network)
4566                 wifi->scan_pending_network = NULL;
4567
4568         if (connman_network == wifi->pending_network)
4569                 wifi->pending_network = NULL;
4570
4571         if(connman_network_get_connecting(connman_network) == true){
4572                 connman_network_set_connected(connman_network, false);
4573         }
4574 #endif
4575
4576         wifi->networks = g_slist_remove(wifi->networks, connman_network);
4577
4578         connman_device_remove_network(wifi->device, connman_network);
4579         connman_network_unref(connman_network);
4580 }
4581
4582 static void network_changed(GSupplicantNetwork *network, const char *property)
4583 {
4584         GSupplicantInterface *interface;
4585         struct wifi_data *wifi;
4586         const char *name, *identifier;
4587         struct connman_network *connman_network;
4588
4589 #if defined TIZEN_EXT
4590         const unsigned char *bssid;
4591         unsigned int maxrate;
4592         uint16_t frequency;
4593         bool wps;
4594         const unsigned char *country_code;
4595         ieee80211_modes_e phy_mode;
4596         GSList *bssid_list;
4597 #endif
4598
4599         interface = g_supplicant_network_get_interface(network);
4600         wifi = g_supplicant_interface_get_data(interface);
4601         identifier = g_supplicant_network_get_identifier(network);
4602         name = g_supplicant_network_get_name(network);
4603
4604         DBG("name %s", name);
4605
4606         if (!wifi)
4607                 return;
4608
4609         connman_network = connman_device_get_network(wifi->device, identifier);
4610         if (!connman_network)
4611                 return;
4612
4613         if (g_str_equal(property, "Signal")) {
4614                connman_network_set_strength(connman_network,
4615                                         calculate_strength(network));
4616                connman_network_update(connman_network);
4617         }
4618
4619 #if defined TIZEN_EXT
4620         bssid = g_supplicant_network_get_bssid(network);
4621         maxrate = g_supplicant_network_get_maxrate(network);
4622         frequency = g_supplicant_network_get_frequency(network);
4623         wps = g_supplicant_network_get_wps(network);
4624         phy_mode = g_supplicant_network_get_phy_mode(network);
4625
4626         connman_network_set_bssid(connman_network, bssid);
4627         connman_network_set_maxrate(connman_network, maxrate);
4628         connman_network_set_frequency(connman_network, frequency);
4629         connman_network_set_bool(connman_network, "WiFi.WPS", wps);
4630         country_code = g_supplicant_network_get_countrycode(network);
4631         connman_network_set_countrycode(connman_network, country_code);
4632         bssid_list = (GSList *)g_supplicant_network_get_bssid_list(network);
4633         connman_network_set_bssid_list(connman_network, bssid_list);
4634         connman_network_set_phy_mode(connman_network, phy_mode);
4635
4636         if (g_str_equal(property, "CheckMultiBssidConnect") &&
4637                         connman_network_get_associating(connman_network))
4638                 network_connect(connman_network);
4639 #endif
4640 }
4641
4642 static void network_associated(GSupplicantNetwork *network)
4643 {
4644         GSupplicantInterface *interface;
4645         struct wifi_data *wifi;
4646         struct connman_network *connman_network;
4647         const char *identifier;
4648
4649         DBG("");
4650
4651         interface = g_supplicant_network_get_interface(network);
4652         if (!interface)
4653                 return;
4654
4655         wifi = g_supplicant_interface_get_data(interface);
4656         if (!wifi)
4657                 return;
4658
4659         identifier = g_supplicant_network_get_identifier(network);
4660
4661         connman_network = connman_device_get_network(wifi->device, identifier);
4662         if (!connman_network)
4663                 return;
4664
4665         if (wifi->network) {
4666                 if (wifi->network == connman_network)
4667                         return;
4668
4669                 /*
4670                  * This should never happen, we got associated with
4671                  * a network different than the one we were expecting.
4672                  */
4673                 DBG("Associated to %p while expecting %p",
4674                                         connman_network, wifi->network);
4675
4676                 connman_network_set_associating(wifi->network, false);
4677         }
4678
4679         DBG("Reconnecting to previous network %p from wpa_s", connman_network);
4680
4681         wifi->network = connman_network_ref(connman_network);
4682         wifi->retries = 0;
4683
4684         /*
4685          * Interface state changes callback (interface_state) is always
4686          * called before network_associated callback thus we need to call
4687          * interface_state again in order to process the new state now that
4688          * we have the network properly set.
4689          */
4690         interface_state(interface);
4691 }
4692
4693 static void apply_peer_services(GSupplicantPeer *peer,
4694                                 struct connman_peer *connman_peer)
4695 {
4696         const unsigned char *data;
4697         int length;
4698
4699         DBG("");
4700
4701         connman_peer_reset_services(connman_peer);
4702
4703         data = g_supplicant_peer_get_widi_ies(peer, &length);
4704         if (data) {
4705                 connman_peer_add_service(connman_peer,
4706                         CONNMAN_PEER_SERVICE_WIFI_DISPLAY, data, length);
4707         }
4708 }
4709
4710 static void add_station(const char *mac)
4711 {
4712         connman_technology_tethering_add_station(CONNMAN_SERVICE_TYPE_WIFI,
4713                                                  mac);
4714 }
4715
4716 static void remove_station(const char *mac)
4717 {
4718         connman_technology_tethering_remove_station(mac);
4719 }
4720
4721 static void peer_found(GSupplicantPeer *peer)
4722 {
4723         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
4724         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
4725         struct connman_peer *connman_peer;
4726         const char *identifier, *name;
4727         int ret;
4728 #if defined TIZEN_EXT
4729         if (!wifi)
4730                 return;
4731 #endif
4732         identifier = g_supplicant_peer_get_identifier(peer);
4733         name = g_supplicant_peer_get_name(peer);
4734
4735         DBG("ident: %s", identifier);
4736
4737         connman_peer = connman_peer_get(wifi->device, identifier);
4738         if (connman_peer)
4739                 return;
4740
4741         connman_peer = connman_peer_create(identifier);
4742         connman_peer_set_name(connman_peer, name);
4743         connman_peer_set_device(connman_peer, wifi->device);
4744         apply_peer_services(peer, connman_peer);
4745
4746         ret = connman_peer_register(connman_peer);
4747         if (ret < 0 && ret != -EALREADY)
4748                 connman_peer_unref(connman_peer);
4749         else
4750                 wifi->peers = g_slist_prepend(wifi->peers, connman_peer);
4751 }
4752
4753 static void peer_lost(GSupplicantPeer *peer)
4754 {
4755         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
4756         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
4757         struct connman_peer *connman_peer;
4758         const char *identifier;
4759
4760         if (!wifi)
4761                 return;
4762
4763         identifier = g_supplicant_peer_get_identifier(peer);
4764
4765         DBG("ident: %s", identifier);
4766
4767         connman_peer = connman_peer_get(wifi->device, identifier);
4768         if (connman_peer) {
4769                 if (wifi->p2p_connecting &&
4770                                 wifi->pending_peer == connman_peer) {
4771                         peer_connect_timeout(wifi);
4772                 }
4773                 connman_peer_unregister(connman_peer);
4774                 connman_peer_unref(connman_peer);
4775         }
4776
4777         wifi->peers = g_slist_remove(wifi->peers, connman_peer);
4778 }
4779
4780 static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state)
4781 {
4782         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
4783         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
4784         enum connman_peer_state p_state = CONNMAN_PEER_STATE_UNKNOWN;
4785         struct connman_peer *connman_peer;
4786         const char *identifier;
4787
4788         identifier = g_supplicant_peer_get_identifier(peer);
4789
4790         DBG("ident: %s", identifier);
4791
4792         if (!wifi)
4793                 return;
4794
4795         connman_peer = connman_peer_get(wifi->device, identifier);
4796         if (!connman_peer)
4797                 return;
4798
4799         switch (state) {
4800         case G_SUPPLICANT_PEER_SERVICES_CHANGED:
4801                 apply_peer_services(peer, connman_peer);
4802                 connman_peer_services_changed(connman_peer);
4803                 return;
4804         case G_SUPPLICANT_PEER_GROUP_CHANGED:
4805                 if (!g_supplicant_peer_is_in_a_group(peer))
4806                         p_state = CONNMAN_PEER_STATE_IDLE;
4807                 else
4808                         p_state = CONNMAN_PEER_STATE_CONFIGURATION;
4809                 break;
4810         case G_SUPPLICANT_PEER_GROUP_STARTED:
4811                 break;
4812         case G_SUPPLICANT_PEER_GROUP_FINISHED:
4813                 p_state = CONNMAN_PEER_STATE_IDLE;
4814                 break;
4815         case G_SUPPLICANT_PEER_GROUP_JOINED:
4816                 connman_peer_set_iface_address(connman_peer,
4817                                 g_supplicant_peer_get_iface_address(peer));
4818                 break;
4819         case G_SUPPLICANT_PEER_GROUP_DISCONNECTED:
4820                 p_state = CONNMAN_PEER_STATE_IDLE;
4821                 break;
4822         case G_SUPPLICANT_PEER_GROUP_FAILED:
4823                 if (g_supplicant_peer_has_requested_connection(peer))
4824                         p_state = CONNMAN_PEER_STATE_IDLE;
4825                 else
4826                         p_state = CONNMAN_PEER_STATE_FAILURE;
4827                 break;
4828         }
4829
4830         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION ||
4831                                         p_state == CONNMAN_PEER_STATE_FAILURE) {
4832                 if (wifi->p2p_connecting
4833                                 && connman_peer == wifi->pending_peer)
4834                         peer_cancel_timeout(wifi);
4835                 else
4836                         p_state = CONNMAN_PEER_STATE_UNKNOWN;
4837         }
4838
4839         if (p_state == CONNMAN_PEER_STATE_UNKNOWN)
4840                 return;
4841
4842         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION) {
4843                 GSupplicantInterface *g_iface;
4844                 struct wifi_data *g_wifi;
4845
4846                 g_iface = g_supplicant_peer_get_group_interface(peer);
4847                 if (!g_iface)
4848                         return;
4849
4850                 g_wifi = g_supplicant_interface_get_data(g_iface);
4851                 if (!g_wifi)
4852                         return;
4853
4854                 connman_peer_set_as_master(connman_peer,
4855                                         !g_supplicant_peer_is_client(peer));
4856                 connman_peer_set_sub_device(connman_peer, g_wifi->device);
4857
4858                 /*
4859                  * If wpa_supplicant didn't create a dedicated p2p-group
4860                  * interface then mark this interface as p2p_device to avoid
4861                  * scan and auto-scan are launched on it while P2P is connected.
4862                  */
4863                 if (!g_list_find(p2p_iface_list, g_wifi))
4864                         wifi->p2p_device = true;
4865         }
4866
4867         connman_peer_set_state(connman_peer, p_state);
4868 }
4869
4870 static void peer_request(GSupplicantPeer *peer)
4871 {
4872         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
4873         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
4874         struct connman_peer *connman_peer;
4875         const char *identifier;
4876
4877 #if defined TIZEN_EXT
4878         if (!wifi)
4879                 return;
4880 #endif
4881
4882         identifier = g_supplicant_peer_get_identifier(peer);
4883
4884         DBG("ident: %s", identifier);
4885
4886         connman_peer = connman_peer_get(wifi->device, identifier);
4887         if (!connman_peer)
4888                 return;
4889
4890         connman_peer_request_connection(connman_peer);
4891 }
4892
4893 #if defined TIZEN_EXT
4894 static void system_power_off(void)
4895 {
4896         GList *list;
4897         struct wifi_data *wifi;
4898         struct connman_service *service;
4899         struct connman_ipconfig *ipconfig_ipv4;
4900
4901         if (connman_setting_get_bool("WiFiDHCPRelease") == true) {
4902                 for (list = iface_list; list; list = list->next) {
4903                         wifi = list->data;
4904
4905                         if (wifi->network != NULL) {
4906                                 service = connman_service_lookup_from_network(wifi->network);
4907                                 ipconfig_ipv4 = __connman_service_get_ip4config(service);
4908                                 __connman_dhcp_stop(ipconfig_ipv4);
4909                         }
4910                 }
4911         }
4912 }
4913
4914 static void network_merged(GSupplicantNetwork *network)
4915 {
4916         GSupplicantInterface *interface;
4917         GSupplicantState state;
4918         struct wifi_data *wifi;
4919         const char *identifier;
4920         struct connman_network *connman_network;
4921         bool ishs20AP = 0;
4922         char *temp = NULL;
4923
4924         interface = g_supplicant_network_get_interface(network);
4925         if (!interface)
4926                 return;
4927
4928         state = g_supplicant_interface_get_state(interface);
4929         if (state < G_SUPPLICANT_STATE_AUTHENTICATING)
4930                 return;
4931
4932         wifi = g_supplicant_interface_get_data(interface);
4933         if (!wifi)
4934                 return;
4935
4936         identifier = g_supplicant_network_get_identifier(network);
4937
4938         connman_network = connman_device_get_network(wifi->device, identifier);
4939         if (!connman_network)
4940                 return;
4941
4942         DBG("merged identifier %s", identifier);
4943
4944         if (wifi->connected == FALSE) {
4945                 switch (state) {
4946                 case G_SUPPLICANT_STATE_AUTHENTICATING:
4947                 case G_SUPPLICANT_STATE_ASSOCIATING:
4948                 case G_SUPPLICANT_STATE_ASSOCIATED:
4949                 case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
4950                 case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
4951                         connman_network_set_associating(connman_network, TRUE);
4952                         break;
4953                 case G_SUPPLICANT_STATE_COMPLETED:
4954                         connman_network_set_connected(connman_network, TRUE);
4955                         break;
4956                 default:
4957                         DBG("Not handled the state : %d", state);
4958                         break;
4959                 }
4960         }
4961
4962         ishs20AP = g_supplicant_network_is_hs20AP(network);
4963
4964         if (ishs20AP &&
4965                 g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) {
4966                 temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1);
4967                 connman_network_set_string(connman_network, "WiFi.EAP",
4968                                 temp);
4969                 connman_network_set_string(connman_network, "WiFi.Identity",
4970                                 g_supplicant_network_get_identity(network));
4971                 connman_network_set_string(connman_network, "WiFi.Phase2",
4972                                 g_supplicant_network_get_phase2(network));
4973
4974                 g_free(temp);
4975         }
4976
4977         wifi->network = connman_network;
4978 }
4979
4980 static void assoc_failed(void *user_data)
4981 {
4982         struct connman_network *network = user_data;
4983         connman_network_set_associating(network, false);
4984 }
4985 #endif
4986
4987 static void debug(const char *str)
4988 {
4989         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
4990                 connman_debug("%s", str);
4991 }
4992
4993 static void disconnect_reasoncode(GSupplicantInterface *interface,
4994                                 int reasoncode)
4995 {
4996         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
4997
4998         if (wifi != NULL) {
4999                 wifi->disconnect_code = reasoncode;
5000         }
5001 }
5002
5003 static void assoc_status_code(GSupplicantInterface *interface, int status_code)
5004 {
5005         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
5006
5007         if (wifi != NULL) {
5008                 wifi->assoc_code = status_code;
5009         }
5010 }
5011
5012 static const GSupplicantCallbacks callbacks = {
5013         .system_ready           = system_ready,
5014         .system_killed          = system_killed,
5015         .interface_added        = interface_added,
5016         .interface_state        = interface_state,
5017         .interface_removed      = interface_removed,
5018         .p2p_support            = p2p_support,
5019         .scan_started           = scan_started,
5020         .scan_finished          = scan_finished,
5021         .ap_create_fail         = ap_create_fail,
5022         .network_added          = network_added,
5023         .network_removed        = network_removed,
5024         .network_changed        = network_changed,
5025         .network_associated     = network_associated,
5026         .add_station            = add_station,
5027         .remove_station         = remove_station,
5028         .peer_found             = peer_found,
5029         .peer_lost              = peer_lost,
5030         .peer_changed           = peer_changed,
5031         .peer_request           = peer_request,
5032 #if defined TIZEN_EXT
5033         .system_power_off       = system_power_off,
5034         .network_merged = network_merged,
5035         .assoc_failed           = assoc_failed,
5036 #endif
5037         .debug                  = debug,
5038         .disconnect_reasoncode  = disconnect_reasoncode,
5039         .assoc_status_code      = assoc_status_code,
5040 #if defined TIZEN_EXT_WIFI_MESH
5041         .mesh_support           = mesh_support,
5042         .mesh_group_started = mesh_group_started,
5043         .mesh_group_removed = mesh_group_removed,
5044         .mesh_peer_connected = mesh_peer_connected,
5045         .mesh_peer_disconnected = mesh_peer_disconnected,
5046 #endif
5047 };
5048
5049
5050 static int tech_probe(struct connman_technology *technology)
5051 {
5052         wifi_technology = technology;
5053
5054         return 0;
5055 }
5056
5057 static void tech_remove(struct connman_technology *technology)
5058 {
5059         wifi_technology = NULL;
5060 }
5061
5062 static GSupplicantSSID *ssid_ap_init(const char *ssid,
5063                 const char *passphrase)
5064 {
5065         GSupplicantSSID *ap;
5066
5067         ap = g_try_malloc0(sizeof(GSupplicantSSID));
5068         if (!ap)
5069                 return NULL;
5070
5071         ap->mode = G_SUPPLICANT_MODE_MASTER;
5072 #if defined TIZEN_EXT
5073         ap->ssid = (void *) ssid;
5074 #else
5075         ap->ssid = ssid;
5076 #endif
5077         ap->ssid_len = strlen(ssid);
5078         ap->scan_ssid = 0;
5079         ap->freq = 2412;
5080
5081         if (!passphrase || strlen(passphrase) == 0) {
5082                 ap->security = G_SUPPLICANT_SECURITY_NONE;
5083                 ap->passphrase = NULL;
5084         } else {
5085                ap->security = G_SUPPLICANT_SECURITY_PSK;
5086                ap->protocol = G_SUPPLICANT_PROTO_RSN;
5087                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
5088                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
5089                ap->passphrase = passphrase;
5090         }
5091
5092         return ap;
5093 }
5094
5095 static void ap_start_callback(int result, GSupplicantInterface *interface,
5096                                                         void *user_data)
5097 {
5098         struct wifi_tethering_info *info = user_data;
5099
5100         DBG("result %d index %d bridge %s",
5101                 result, info->wifi->index, info->wifi->bridge);
5102
5103         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
5104                 connman_inet_remove_from_bridge(info->wifi->index,
5105                                                         info->wifi->bridge);
5106
5107                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
5108                         connman_technology_tethering_notify(info->technology, false);
5109                         g_free(info->wifi->tethering_param->ssid);
5110                         g_free(info->wifi->tethering_param);
5111                         info->wifi->tethering_param = NULL;
5112                 }
5113         }
5114
5115         g_free(info->ifname);
5116         g_free(info);
5117 }
5118
5119 static void ap_create_callback(int result,
5120                                 GSupplicantInterface *interface,
5121                                         void *user_data)
5122 {
5123         struct wifi_tethering_info *info = user_data;
5124
5125         DBG("result %d ifname %s", result,
5126                                 g_supplicant_interface_get_ifname(interface));
5127
5128         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
5129                 connman_inet_remove_from_bridge(info->wifi->index,
5130                                                         info->wifi->bridge);
5131
5132                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
5133                         connman_technology_tethering_notify(info->technology, false);
5134                         g_free(info->wifi->tethering_param->ssid);
5135                         g_free(info->wifi->tethering_param);
5136                         info->wifi->tethering_param = NULL;
5137
5138                 }
5139
5140                 g_free(info->ifname);
5141                 g_free(info->ssid);
5142                 g_free(info);
5143                 return;
5144         }
5145
5146         info->wifi->interface = interface;
5147         g_supplicant_interface_set_data(interface, info->wifi);
5148
5149         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
5150                 connman_error("Failed to set interface ap_scan property");
5151
5152         g_supplicant_interface_connect(interface, info->ssid,
5153                                                 ap_start_callback, info);
5154 }
5155
5156 static void sta_remove_callback(int result,
5157                                 GSupplicantInterface *interface,
5158                                         void *user_data)
5159 {
5160         struct wifi_tethering_info *info = user_data;
5161         const char *driver = connman_option_get_string("wifi");
5162
5163         DBG("ifname %s result %d ", info->ifname, result);
5164
5165         if (result < 0 || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
5166                 info->wifi->tethering = false;
5167                 connman_technology_tethering_notify(info->technology, false);
5168
5169                 g_free(info->ifname);
5170                 g_free(info->ssid);
5171                 g_free(info);
5172
5173                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
5174                         g_free(info->wifi->tethering_param->ssid);
5175                         g_free(info->wifi->tethering_param);
5176                         info->wifi->tethering_param = NULL;
5177                 }
5178                 return;
5179         }
5180
5181         info->wifi->interface = NULL;
5182
5183         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
5184                                                 ap_create_callback,
5185                                                         info);
5186 }
5187
5188 static int enable_wifi_tethering(struct connman_technology *technology,
5189                                 const char *bridge, const char *identifier,
5190                                 const char *passphrase, bool available)
5191 {
5192         GList *list;
5193         GSupplicantInterface *interface;
5194         struct wifi_data *wifi;
5195         struct wifi_tethering_info *info;
5196         const char *ifname;
5197         unsigned int mode;
5198         int err, berr = 0;
5199
5200         for (list = iface_list; list; list = list->next) {
5201                 wifi = list->data;
5202
5203                 DBG("wifi %p network %p pending_network %p", wifi,
5204                         wifi->network, wifi->pending_network);
5205
5206                 interface = wifi->interface;
5207
5208                 if (!interface)
5209                         continue;
5210
5211                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED)
5212                         continue;
5213
5214                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
5215
5216                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED) {
5217                         DBG("%s does not support AP mode (detected)", ifname);
5218                         continue;
5219                 }
5220
5221                 mode = g_supplicant_interface_get_mode(interface);
5222                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
5223                         wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
5224                         DBG("%s does not support AP mode (capability)", ifname);
5225                         continue;
5226                 }
5227
5228                 if (wifi->network && available)
5229                         continue;
5230
5231                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
5232                 if (!info)
5233                         return -ENOMEM;
5234
5235                 wifi->tethering_param = g_try_malloc0(sizeof(struct wifi_tethering_info));
5236                 if (!wifi->tethering_param) {
5237                         g_free(info);
5238                         return -ENOMEM;
5239                 }
5240
5241                 info->wifi = wifi;
5242                 info->technology = technology;
5243                 info->wifi->bridge = bridge;
5244                 info->ssid = ssid_ap_init(identifier, passphrase);
5245                 if (!info->ssid)
5246                         goto failed;
5247
5248                 info->ifname = g_strdup(ifname);
5249                 if (!info->ifname)
5250                         goto failed;
5251
5252                 wifi->tethering_param->technology = technology;
5253                 wifi->tethering_param->ssid = ssid_ap_init(identifier, passphrase);
5254                 if (!wifi->tethering_param->ssid)
5255                         goto failed;
5256
5257                 info->wifi->tethering = true;
5258                 info->wifi->ap_supported = WIFI_AP_SUPPORTED;
5259
5260                 berr = connman_technology_tethering_notify(technology, true);
5261                 if (berr < 0)
5262                         goto failed;
5263
5264                 err = g_supplicant_interface_remove(interface,
5265                                                 sta_remove_callback,
5266                                                         info);
5267                 if (err >= 0) {
5268                         DBG("tethering wifi %p ifname %s", wifi, ifname);
5269                         return 0;
5270                 }
5271
5272         failed:
5273                 g_free(info->ifname);
5274                 g_free(info->ssid);
5275                 g_free(info);
5276                 g_free(wifi->tethering_param);
5277                 wifi->tethering_param = NULL;
5278
5279                 /*
5280                  * Remove bridge if it was correctly created but remove
5281                  * operation failed. Instead, if bridge creation failed then
5282                  * break out and do not try again on another interface,
5283                  * bridge set-up does not depend on it.
5284                  */
5285                 if (berr == 0)
5286                         connman_technology_tethering_notify(technology, false);
5287                 else
5288                         break;
5289         }
5290
5291         return -EOPNOTSUPP;
5292 }
5293
5294 static int tech_set_tethering(struct connman_technology *technology,
5295                                 const char *identifier, const char *passphrase,
5296                                 const char *bridge, bool enabled)
5297 {
5298         GList *list;
5299         struct wifi_data *wifi;
5300         int err;
5301
5302         DBG("");
5303
5304         if (!enabled) {
5305                 for (list = iface_list; list; list = list->next) {
5306                         wifi = list->data;
5307
5308                         if (wifi->tethering) {
5309                                 wifi->tethering = false;
5310
5311                                 connman_inet_remove_from_bridge(wifi->index,
5312                                                                         bridge);
5313                                 wifi->bridged = false;
5314                         }
5315                 }
5316
5317                 connman_technology_tethering_notify(technology, false);
5318
5319                 return 0;
5320         }
5321
5322         DBG("trying tethering for available devices");
5323         err = enable_wifi_tethering(technology, bridge, identifier, passphrase,
5324                                 true);
5325
5326         if (err < 0) {
5327                 DBG("trying tethering for any device");
5328                 err = enable_wifi_tethering(technology, bridge, identifier,
5329                                         passphrase, false);
5330         }
5331
5332         return err;
5333 }
5334
5335 static void regdom_callback(int result, const char *alpha2, void *user_data)
5336 {
5337         DBG("");
5338
5339         if (!wifi_technology)
5340                 return;
5341
5342         if (result != 0)
5343                 alpha2 = NULL;
5344
5345         connman_technology_regdom_notify(wifi_technology, alpha2);
5346 }
5347
5348 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
5349 {
5350         return g_supplicant_set_country(alpha2, regdom_callback, NULL);
5351 }
5352
5353 static struct connman_technology_driver tech_driver = {
5354         .name           = "wifi",
5355         .type           = CONNMAN_SERVICE_TYPE_WIFI,
5356         .probe          = tech_probe,
5357         .remove         = tech_remove,
5358         .set_tethering  = tech_set_tethering,
5359         .set_regdom     = tech_set_regdom,
5360 };
5361
5362 static int wifi_init(void)
5363 {
5364         int err;
5365
5366         err = connman_network_driver_register(&network_driver);
5367         if (err < 0)
5368                 return err;
5369
5370         err = g_supplicant_register(&callbacks);
5371         if (err < 0) {
5372                 connman_network_driver_unregister(&network_driver);
5373                 return err;
5374         }
5375
5376         err = connman_technology_driver_register(&tech_driver);
5377         if (err < 0) {
5378                 g_supplicant_unregister(&callbacks);
5379                 connman_network_driver_unregister(&network_driver);
5380                 return err;
5381         }
5382
5383         return 0;
5384 }
5385
5386 static void wifi_exit(void)
5387 {
5388         DBG();
5389
5390         connman_technology_driver_unregister(&tech_driver);
5391
5392         g_supplicant_unregister(&callbacks);
5393
5394         connman_network_driver_unregister(&network_driver);
5395 }
5396
5397 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
5398                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)