c471accf5fc549dc8bce0adac70c577b2bbf156d
[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 #endif
164         int disconnect_code;
165         int assoc_code;
166 };
167
168 #if defined TIZEN_EXT
169 #include "connman.h"
170 #include "dbus.h"
171
172 #define TIZEN_ASSOC_RETRY_COUNT         4
173
174 static gboolean wifi_first_scan = false;
175 static gboolean found_with_first_scan = false;
176 static gboolean is_wifi_notifier_registered = false;
177 #endif
178
179
180 static GList *iface_list = NULL;
181
182 static GList *pending_wifi_device = NULL;
183 static GList *p2p_iface_list = NULL;
184 bool wfd_service_registered = false;
185
186 static void start_autoscan(struct connman_device *device);
187
188 static int tech_set_tethering(struct connman_technology *technology,
189                                 const char *identifier, const char *passphrase,
190                                 const char *bridge, bool enabled);
191
192 #if defined TIZEN_EXT
193 #define NETCONFIG_SERVICE "net.netconfig"
194 #define NETCONFIG_WIFI_PATH "/net/netconfig/wifi"
195 #define NETCONFIG_WIFI_INTERFACE NETCONFIG_SERVICE ".wifi"
196
197 struct enc_method_call_data {
198         DBusConnection *connection;
199         struct connman_network *network;
200 };
201
202 static struct enc_method_call_data encrypt_request_data;
203
204 static void encryption_request_reply(DBusPendingCall *call,
205                                                 void *user_data)
206 {
207         DBusMessage *reply;
208         DBusError error;
209         DBusMessageIter args;
210         char *out_data;
211         struct connman_service *service;
212         gchar* encrypted_value = NULL;
213         struct connman_network *network = encrypt_request_data.network;
214
215         DBG("");
216
217         reply = dbus_pending_call_steal_reply(call);
218
219         dbus_error_init(&error);
220         if (dbus_set_error_from_message(&error, reply)) {
221                 DBG("send_encryption_request() %s %s", error.name, error.message);
222                 dbus_error_free(&error);
223                 goto done;
224         }
225
226         if (dbus_message_iter_init(reply, &args) == FALSE)
227                 goto done;
228
229         dbus_message_iter_get_basic(&args, &out_data);
230
231         encrypted_value = g_strdup((const gchar *)out_data);
232         service = connman_service_lookup_from_network(network);
233
234         if (!service) {
235                 DBG("encryption result: no service");
236                 goto done;
237         }
238
239         if (connman_service_get_favorite(service)) {
240                 __connman_service_set_passphrase(service, encrypted_value);
241                 __connman_service_save(service);
242         } else
243                 connman_network_set_string(network, "WiFi.Passphrase",
244                                                         encrypted_value);
245
246         DBG("encryption result: succeeded");
247
248 done:
249         dbus_message_unref(reply);
250         dbus_pending_call_unref(call);
251         dbus_connection_unref(encrypt_request_data.connection);
252         g_free(encrypted_value);
253
254         encrypt_request_data.connection = NULL;
255         encrypt_request_data.network = NULL;
256 }
257
258 static int send_encryption_request(const char *passphrase,
259                                 struct connman_network *network)
260 {
261         DBusConnection *connection = NULL;
262         DBusMessage *msg = NULL;
263         DBusPendingCall *call;
264
265         if (!passphrase) {
266                 DBG("Invalid parameter");
267                 return -EINVAL;
268         }
269
270         connection = connman_dbus_get_connection();
271         if (!connection) {
272                 DBG("dbus connection does not exist");
273                 return -EINVAL;
274         }
275
276         msg = dbus_message_new_method_call(NETCONFIG_SERVICE, NETCONFIG_WIFI_PATH,
277                         NETCONFIG_WIFI_INTERFACE, "EncryptPassphrase");
278         if (!msg) {
279                 dbus_connection_unref(connection);
280                 return -EINVAL;
281         }
282
283         dbus_message_append_args(msg, DBUS_TYPE_STRING, &passphrase,
284                                                         DBUS_TYPE_INVALID);
285
286         if (!dbus_connection_send_with_reply(connection, msg,
287                                 &call, DBUS_TIMEOUT_USE_DEFAULT)) {
288                 dbus_message_unref(msg);
289                 dbus_connection_unref(connection);
290                 return -EIO;
291         }
292
293         if (!call) {
294                 dbus_message_unref(msg);
295                 dbus_connection_unref(connection);
296                 return -EIO;
297         }
298
299         encrypt_request_data.connection = connection;
300         encrypt_request_data.network = network;
301
302         dbus_pending_call_set_notify(call, encryption_request_reply, NULL, NULL);
303         dbus_message_unref(msg);
304
305         return 0;
306 }
307 #endif
308
309 static int p2p_tech_probe(struct connman_technology *technology)
310 {
311         p2p_technology = technology;
312
313         return 0;
314 }
315
316 static void p2p_tech_remove(struct connman_technology *technology)
317 {
318         p2p_technology = NULL;
319 }
320
321 static struct connman_technology_driver p2p_tech_driver = {
322         .name           = "p2p",
323         .type           = CONNMAN_SERVICE_TYPE_P2P,
324         .probe          = p2p_tech_probe,
325         .remove         = p2p_tech_remove,
326 };
327
328 static bool is_p2p_connecting(void)
329 {
330         GList *list;
331
332         for (list = iface_list; list; list = list->next) {
333                 struct wifi_data *wifi = list->data;
334
335                 if (wifi->p2p_connecting)
336                         return true;
337         }
338
339         return false;
340 }
341
342 static void add_pending_wifi_device(struct wifi_data *wifi)
343 {
344         if (g_list_find(pending_wifi_device, wifi))
345                 return;
346
347         pending_wifi_device = g_list_append(pending_wifi_device, wifi);
348 }
349
350 static struct wifi_data *get_pending_wifi_data(const char *ifname)
351 {
352         GList *list;
353
354         for (list = pending_wifi_device; list; list = list->next) {
355                 struct wifi_data *wifi;
356                 const char *dev_name;
357
358                 wifi = list->data;
359                 if (!wifi || !wifi->device)
360                         continue;
361
362                 dev_name = connman_device_get_string(wifi->device, "Interface");
363                 if (!g_strcmp0(ifname, dev_name)) {
364                         pending_wifi_device = g_list_delete_link(
365                                                 pending_wifi_device, list);
366                         return wifi;
367                 }
368         }
369
370         return NULL;
371 }
372
373 static void remove_pending_wifi_device(struct wifi_data *wifi)
374 {
375         GList *link;
376
377         link = g_list_find(pending_wifi_device, wifi);
378
379         if (!link)
380                 return;
381
382         pending_wifi_device = g_list_delete_link(pending_wifi_device, link);
383 }
384
385 static void peer_cancel_timeout(struct wifi_data *wifi)
386 {
387         if (wifi->p2p_connection_timeout > 0)
388                 g_source_remove(wifi->p2p_connection_timeout);
389
390         wifi->p2p_connection_timeout = 0;
391         wifi->p2p_connecting = false;
392
393         if (wifi->pending_peer) {
394                 connman_peer_unref(wifi->pending_peer);
395                 wifi->pending_peer = NULL;
396         }
397 }
398
399 static gboolean peer_connect_timeout(gpointer data)
400 {
401         struct wifi_data *wifi = data;
402
403         DBG("");
404
405         if (wifi->p2p_connecting) {
406                 enum connman_peer_state state = CONNMAN_PEER_STATE_FAILURE;
407                 GSupplicantPeer *gs_peer =
408                         g_supplicant_interface_peer_lookup(wifi->interface,
409                                 connman_peer_get_identifier(wifi->pending_peer));
410
411                 if (g_supplicant_peer_has_requested_connection(gs_peer))
412                         state = CONNMAN_PEER_STATE_IDLE;
413
414                 connman_peer_set_state(wifi->pending_peer, state);
415         }
416
417         peer_cancel_timeout(wifi);
418
419         return FALSE;
420 }
421
422 static void peer_connect_callback(int result, GSupplicantInterface *interface,
423                                                         void *user_data)
424 {
425         struct wifi_data *wifi = user_data;
426         struct connman_peer *peer = wifi->pending_peer;
427
428         DBG("peer %p - %d", peer, result);
429
430         if (!peer)
431                 return;
432
433         if (result < 0) {
434                 peer_connect_timeout(wifi);
435                 return;
436         }
437
438         connman_peer_set_state(peer, CONNMAN_PEER_STATE_ASSOCIATION);
439
440         wifi->p2p_connection_timeout = g_timeout_add_seconds(
441                                                 P2P_CONNECTION_TIMEOUT,
442                                                 peer_connect_timeout, wifi);
443 }
444
445 static int peer_connect(struct connman_peer *peer,
446                         enum connman_peer_wps_method wps_method,
447                         const char *wps_pin)
448 {
449         struct connman_device *device = connman_peer_get_device(peer);
450         GSupplicantPeerParams *peer_params;
451         GSupplicantPeer *gs_peer;
452         struct wifi_data *wifi;
453         bool pbc, pin;
454         int ret;
455
456         DBG("peer %p", peer);
457
458         if (!device)
459                 return -ENODEV;
460
461         wifi = connman_device_get_data(device);
462         if (!wifi || !wifi->interface)
463                 return -ENODEV;
464
465         if (wifi->p2p_connecting)
466                 return -EBUSY;
467
468         gs_peer = g_supplicant_interface_peer_lookup(wifi->interface,
469                                         connman_peer_get_identifier(peer));
470         if (!gs_peer)
471                 return -EINVAL;
472
473         pbc = g_supplicant_peer_is_wps_pbc(gs_peer);
474         pin = g_supplicant_peer_is_wps_pin(gs_peer);
475
476         switch (wps_method) {
477         case CONNMAN_PEER_WPS_UNKNOWN:
478                 if ((pbc && pin) || pin)
479                         return -ENOKEY;
480                 break;
481         case CONNMAN_PEER_WPS_PBC:
482                 if (!pbc)
483                         return -EINVAL;
484                 wps_pin = NULL;
485                 break;
486         case CONNMAN_PEER_WPS_PIN:
487                 if (!pin || !wps_pin)
488                         return -EINVAL;
489                 break;
490         }
491
492         peer_params = g_try_malloc0(sizeof(GSupplicantPeerParams));
493         if (!peer_params)
494                 return -ENOMEM;
495
496         peer_params->path = g_strdup(g_supplicant_peer_get_path(gs_peer));
497         if (wps_pin)
498                 peer_params->wps_pin = g_strdup(wps_pin);
499
500         peer_params->master = connman_peer_service_is_master();
501
502         ret = g_supplicant_interface_p2p_connect(wifi->interface, peer_params,
503                                                 peer_connect_callback, wifi);
504         if (ret == -EINPROGRESS) {
505                 wifi->pending_peer = connman_peer_ref(peer);
506                 wifi->p2p_connecting = true;
507         } else if (ret < 0) {
508                 g_free(peer_params->path);
509                 g_free(peer_params->wps_pin);
510                 g_free(peer_params);
511         }
512
513         return ret;
514 }
515
516 static int peer_disconnect(struct connman_peer *peer)
517 {
518         struct connman_device *device = connman_peer_get_device(peer);
519         GSupplicantPeerParams peer_params = {};
520         GSupplicantPeer *gs_peer;
521         struct wifi_data *wifi;
522         int ret;
523
524         DBG("peer %p", peer);
525
526         if (!device)
527                 return -ENODEV;
528
529         wifi = connman_device_get_data(device);
530         if (!wifi)
531                 return -ENODEV;
532
533         gs_peer = g_supplicant_interface_peer_lookup(wifi->interface,
534                                         connman_peer_get_identifier(peer));
535         if (!gs_peer)
536                 return -EINVAL;
537
538         peer_params.path = g_strdup(g_supplicant_peer_get_path(gs_peer));
539
540         ret = g_supplicant_interface_p2p_disconnect(wifi->interface,
541                                                         &peer_params);
542         g_free(peer_params.path);
543
544         if (ret == -EINPROGRESS) {
545                 peer_cancel_timeout(wifi);
546                 wifi->p2p_device = false;
547         }
548
549         return ret;
550 }
551
552 struct peer_service_registration {
553         peer_service_registration_cb_t callback;
554         void *user_data;
555 };
556
557 static bool is_service_wfd(const unsigned char *specs, int length)
558 {
559         if (length < 9 || specs[0] != 0 || specs[1] != 0 || specs[2] != 6)
560                 return false;
561
562         return true;
563 }
564
565 static void apply_p2p_listen_on_iface(gpointer data, gpointer user_data)
566 {
567         struct wifi_data *wifi = data;
568
569         if (!wifi->interface ||
570                         !g_supplicant_interface_has_p2p(wifi->interface))
571                 return;
572
573         if (!wifi->servicing) {
574                 g_supplicant_interface_p2p_listen(wifi->interface,
575                                 P2P_LISTEN_PERIOD, P2P_LISTEN_INTERVAL);
576         }
577
578         wifi->servicing++;
579 }
580
581 static void register_wfd_service_cb(int result,
582                                 GSupplicantInterface *iface, void *user_data)
583 {
584         struct peer_service_registration *reg_data = user_data;
585
586         DBG("");
587
588         if (result == 0)
589                 g_list_foreach(iface_list, apply_p2p_listen_on_iface, NULL);
590
591         if (reg_data && reg_data->callback) {
592                 reg_data->callback(result, reg_data->user_data);
593                 g_free(reg_data);
594         }
595 }
596
597 static GSupplicantP2PServiceParams *fill_in_peer_service_params(
598                                 const unsigned char *spec,
599                                 int spec_length, const unsigned char *query,
600                                 int query_length, int version)
601 {
602         GSupplicantP2PServiceParams *params;
603
604         params = g_try_malloc0(sizeof(GSupplicantP2PServiceParams));
605         if (!params)
606                 return NULL;
607
608         if (version > 0) {
609                 params->version = version;
610                 params->service = g_memdup(spec, spec_length);
611         } else if (query_length > 0 && spec_length > 0) {
612                 params->query = g_memdup(query, query_length);
613                 params->query_length = query_length;
614
615                 params->response = g_memdup(spec, spec_length);
616                 params->response_length = spec_length;
617         } else {
618                 params->wfd_ies = g_memdup(spec, spec_length);
619                 params->wfd_ies_length = spec_length;
620         }
621
622         return params;
623 }
624
625 static void free_peer_service_params(GSupplicantP2PServiceParams *params)
626 {
627         if (!params)
628                 return;
629
630         g_free(params->service);
631         g_free(params->query);
632         g_free(params->response);
633         g_free(params->wfd_ies);
634
635         g_free(params);
636 }
637
638 static int peer_register_wfd_service(const unsigned char *specification,
639                                 int specification_length,
640                                 peer_service_registration_cb_t callback,
641                                 void *user_data)
642 {
643         struct peer_service_registration *reg_data = NULL;
644         static GSupplicantP2PServiceParams *params;
645         int ret;
646
647         DBG("");
648
649         if (wfd_service_registered)
650                 return -EBUSY;
651
652         params = fill_in_peer_service_params(specification,
653                                         specification_length, NULL, 0, 0);
654         if (!params)
655                 return -ENOMEM;
656
657         reg_data = g_try_malloc0(sizeof(*reg_data));
658         if (!reg_data) {
659                 ret = -ENOMEM;
660                 goto error;
661         }
662
663         reg_data->callback = callback;
664         reg_data->user_data = user_data;
665
666         ret = g_supplicant_set_widi_ies(params,
667                                         register_wfd_service_cb, reg_data);
668         if (ret < 0 && ret != -EINPROGRESS)
669                 goto error;
670
671         wfd_service_registered = true;
672
673         return ret;
674 error:
675         free_peer_service_params(params);
676         g_free(reg_data);
677
678         return ret;
679 }
680
681 static void register_peer_service_cb(int result,
682                                 GSupplicantInterface *iface, void *user_data)
683 {
684         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
685         struct peer_service_registration *reg_data = user_data;
686
687 #if defined TIZEN_EXT
688         if (!wifi)
689                 return;
690 #endif
691
692         DBG("");
693
694         if (result == 0)
695                 apply_p2p_listen_on_iface(wifi, NULL);
696
697         if (reg_data->callback)
698                 reg_data->callback(result, reg_data->user_data);
699
700         g_free(reg_data);
701 }
702
703 static int peer_register_service(const unsigned char *specification,
704                                 int specification_length,
705                                 const unsigned char *query,
706                                 int query_length, int version,
707                                 peer_service_registration_cb_t callback,
708                                 void *user_data)
709 {
710         struct peer_service_registration *reg_data;
711         GSupplicantP2PServiceParams *params;
712         bool found = false;
713         int ret, ret_f;
714         GList *list;
715
716         DBG("");
717
718         if (specification && !version && !query &&
719                         is_service_wfd(specification, specification_length)) {
720                 return peer_register_wfd_service(specification,
721                                 specification_length, callback, user_data);
722         }
723
724         reg_data = g_try_malloc0(sizeof(*reg_data));
725         if (!reg_data)
726                 return -ENOMEM;
727
728         reg_data->callback = callback;
729         reg_data->user_data = user_data;
730
731         ret_f = -EOPNOTSUPP;
732
733         for (list = iface_list; list; list = list->next) {
734                 struct wifi_data *wifi = list->data;
735                 GSupplicantInterface *iface = wifi->interface;
736
737                 if (!g_supplicant_interface_has_p2p(iface))
738                         continue;
739
740                 params = fill_in_peer_service_params(specification,
741                                                 specification_length, query,
742                                                 query_length, version);
743                 if (!params) {
744                         ret = -ENOMEM;
745                         continue;
746                 }
747
748                 if (!found) {
749                         ret_f = g_supplicant_interface_p2p_add_service(iface,
750                                 register_peer_service_cb, params, reg_data);
751                         if (ret_f == 0 || ret_f == -EINPROGRESS)
752                                 found = true;
753                         ret = ret_f;
754                 } else
755                         ret = g_supplicant_interface_p2p_add_service(iface,
756                                 register_peer_service_cb, params, NULL);
757                 if (ret != 0 && ret != -EINPROGRESS)
758                         free_peer_service_params(params);
759         }
760
761         if (ret_f != 0 && ret_f != -EINPROGRESS)
762                 g_free(reg_data);
763
764         return ret_f;
765 }
766
767 static int peer_unregister_wfd_service(void)
768 {
769         GSupplicantP2PServiceParams *params;
770         GList *list;
771
772         if (!wfd_service_registered)
773                 return -EALREADY;
774
775         params = fill_in_peer_service_params(NULL, 0, NULL, 0, 0);
776         if (!params)
777                 return -ENOMEM;
778
779         wfd_service_registered = false;
780
781         g_supplicant_set_widi_ies(params, NULL, NULL);
782
783         for (list = iface_list; list; list = list->next) {
784                 struct wifi_data *wifi = list->data;
785
786                 if (!g_supplicant_interface_has_p2p(wifi->interface))
787                         continue;
788
789                 wifi->servicing--;
790                 if (!wifi->servicing || wifi->servicing < 0) {
791                         g_supplicant_interface_p2p_listen(wifi->interface,
792                                                                         0, 0);
793                         wifi->servicing = 0;
794                 }
795         }
796
797         return 0;
798 }
799
800 static int peer_unregister_service(const unsigned char *specification,
801                                                 int specification_length,
802                                                 const unsigned char *query,
803                                                 int query_length, int version)
804 {
805         GSupplicantP2PServiceParams *params;
806         bool wfd = false;
807         GList *list;
808         int ret;
809
810         if (specification && !version && !query &&
811                         is_service_wfd(specification, specification_length)) {
812                 ret = peer_unregister_wfd_service();
813                 if (ret != 0 && ret != -EINPROGRESS)
814                         return ret;
815                 wfd = true;
816         }
817
818         for (list = iface_list; list; list = list->next) {
819                 struct wifi_data *wifi = list->data;
820                 GSupplicantInterface *iface = wifi->interface;
821
822                 if (wfd)
823                         goto stop_listening;
824
825                 if (!g_supplicant_interface_has_p2p(iface))
826                         continue;
827
828                 params = fill_in_peer_service_params(specification,
829                                                 specification_length, query,
830                                                 query_length, version);
831                 if (!params) {
832                         ret = -ENOMEM;
833                         continue;
834                 }
835
836                 ret = g_supplicant_interface_p2p_del_service(iface, params);
837                 if (ret != 0 && ret != -EINPROGRESS)
838                         free_peer_service_params(params);
839 stop_listening:
840                 wifi->servicing--;
841                 if (!wifi->servicing || wifi->servicing < 0) {
842                         g_supplicant_interface_p2p_listen(iface, 0, 0);
843                         wifi->servicing = 0;
844                 }
845         }
846
847         return 0;
848 }
849
850 static struct connman_peer_driver peer_driver = {
851         .connect    = peer_connect,
852         .disconnect = peer_disconnect,
853         .register_service = peer_register_service,
854         .unregister_service = peer_unregister_service,
855 };
856
857 static void handle_tethering(struct wifi_data *wifi)
858 {
859         if (!wifi->tethering)
860                 return;
861
862         if (!wifi->bridge)
863                 return;
864
865         if (wifi->bridged)
866                 return;
867
868         DBG("index %d bridge %s", wifi->index, wifi->bridge);
869
870         if (connman_inet_add_to_bridge(wifi->index, wifi->bridge) < 0)
871                 return;
872
873         wifi->bridged = true;
874 }
875
876 static void wifi_newlink(unsigned flags, unsigned change, void *user_data)
877 {
878         struct connman_device *device = user_data;
879         struct wifi_data *wifi = connman_device_get_data(device);
880
881         if (!wifi)
882                 return;
883
884         DBG("index %d flags %d change %d", wifi->index, flags, change);
885
886         if ((wifi->flags & IFF_UP) != (flags & IFF_UP)) {
887                 if (flags & IFF_UP)
888                         DBG("interface up");
889                 else
890                         DBG("interface down");
891         }
892
893         if ((wifi->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
894                 if (flags & IFF_LOWER_UP) {
895                         DBG("carrier on");
896
897                         handle_tethering(wifi);
898                 } else
899                         DBG("carrier off");
900         }
901
902         wifi->flags = flags;
903 }
904
905 static int wifi_probe(struct connman_device *device)
906 {
907         struct wifi_data *wifi;
908
909         DBG("device %p", device);
910
911         wifi = g_try_new0(struct wifi_data, 1);
912         if (!wifi)
913                 return -ENOMEM;
914
915         wifi->state = G_SUPPLICANT_STATE_INACTIVE;
916         wifi->ap_supported = WIFI_AP_UNKNOWN;
917         wifi->tethering_param = NULL;
918
919         connman_device_set_data(device, wifi);
920         wifi->device = connman_device_ref(device);
921
922         wifi->index = connman_device_get_index(device);
923         wifi->flags = 0;
924
925         wifi->watch = connman_rtnl_add_newlink_watch(wifi->index,
926                                                         wifi_newlink, device);
927         if (is_p2p_connecting())
928                 add_pending_wifi_device(wifi);
929         else
930                 iface_list = g_list_append(iface_list, wifi);
931
932         return 0;
933 }
934
935 static void remove_networks(struct connman_device *device,
936                                 struct wifi_data *wifi)
937 {
938         GSList *list;
939
940         for (list = wifi->networks; list; list = list->next) {
941                 struct connman_network *network = list->data;
942
943                 connman_device_remove_network(device, network);
944                 connman_network_unref(network);
945         }
946
947         g_slist_free(wifi->networks);
948         wifi->networks = NULL;
949 }
950
951 static void remove_peers(struct wifi_data *wifi)
952 {
953         GSList *list;
954
955         for (list = wifi->peers; list; list = list->next) {
956                 struct connman_peer *peer = list->data;
957
958                 connman_peer_unregister(peer);
959                 connman_peer_unref(peer);
960         }
961
962         g_slist_free(wifi->peers);
963         wifi->peers = NULL;
964 }
965
966 static void reset_autoscan(struct connman_device *device)
967 {
968         struct wifi_data *wifi = connman_device_get_data(device);
969         struct autoscan_params *autoscan;
970
971         DBG("");
972
973         if (!wifi || !wifi->autoscan)
974                 return;
975
976         autoscan = wifi->autoscan;
977
978         if (autoscan->timeout == 0 && autoscan->interval == 0)
979                 return;
980
981         g_source_remove(autoscan->timeout);
982
983         autoscan->timeout = 0;
984         autoscan->interval = 0;
985
986         connman_device_unref(device);
987 }
988
989 static void stop_autoscan(struct connman_device *device)
990 {
991         const struct wifi_data *wifi = connman_device_get_data(device);
992
993         if (!wifi || !wifi->autoscan)
994                 return;
995
996         reset_autoscan(device);
997
998         connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_WIFI, false);
999 }
1000
1001 static void check_p2p_technology(void)
1002 {
1003         bool p2p_exists = false;
1004         GList *list;
1005
1006         for (list = iface_list; list; list = list->next) {
1007                 struct wifi_data *w = list->data;
1008
1009                 if (w->interface &&
1010                                 g_supplicant_interface_has_p2p(w->interface))
1011                         p2p_exists = true;
1012         }
1013
1014         if (!p2p_exists) {
1015                 connman_technology_driver_unregister(&p2p_tech_driver);
1016                 connman_peer_driver_unregister(&peer_driver);
1017         }
1018 }
1019
1020 static void wifi_remove(struct connman_device *device)
1021 {
1022         struct wifi_data *wifi = connman_device_get_data(device);
1023
1024         DBG("device %p wifi %p", device, wifi);
1025
1026         if (!wifi)
1027                 return;
1028
1029         stop_autoscan(device);
1030
1031         if (wifi->p2p_device)
1032                 p2p_iface_list = g_list_remove(p2p_iface_list, wifi);
1033         else
1034                 iface_list = g_list_remove(iface_list, wifi);
1035
1036         check_p2p_technology();
1037
1038         remove_pending_wifi_device(wifi);
1039
1040         if (wifi->p2p_find_timeout) {
1041                 g_source_remove(wifi->p2p_find_timeout);
1042                 connman_device_unref(wifi->device);
1043         }
1044
1045         if (wifi->p2p_connection_timeout)
1046                 g_source_remove(wifi->p2p_connection_timeout);
1047
1048         remove_networks(device, wifi);
1049         remove_peers(wifi);
1050
1051         connman_device_set_powered(device, false);
1052         connman_device_set_data(device, NULL);
1053         connman_device_unref(wifi->device);
1054         connman_rtnl_remove_watch(wifi->watch);
1055
1056         g_supplicant_interface_set_data(wifi->interface, NULL);
1057
1058         g_supplicant_interface_cancel(wifi->interface);
1059
1060         if (wifi->scan_params)
1061                 g_supplicant_free_scan_params(wifi->scan_params);
1062
1063         g_free(wifi->autoscan);
1064         g_free(wifi->identifier);
1065         g_free(wifi);
1066 }
1067
1068 static bool is_duplicate(GSList *list, gchar *ssid, int ssid_len)
1069 {
1070         GSList *iter;
1071
1072         for (iter = list; iter; iter = g_slist_next(iter)) {
1073                 struct scan_ssid *scan_ssid = iter->data;
1074
1075                 if (ssid_len == scan_ssid->ssid_len &&
1076                                 memcmp(ssid, scan_ssid->ssid, ssid_len) == 0)
1077                         return true;
1078         }
1079
1080         return false;
1081 }
1082
1083 static int add_scan_param(gchar *hex_ssid, char *raw_ssid, int ssid_len,
1084                         int freq, GSupplicantScanParams *scan_data,
1085                         int driver_max_scan_ssids, char *ssid_name)
1086 {
1087         unsigned int i;
1088         struct scan_ssid *scan_ssid;
1089
1090         if ((driver_max_scan_ssids == 0 ||
1091                         driver_max_scan_ssids > scan_data->num_ssids) &&
1092                         (hex_ssid || raw_ssid)) {
1093                 gchar *ssid;
1094                 unsigned int j = 0, hex;
1095
1096                 if (hex_ssid) {
1097                         size_t hex_ssid_len = strlen(hex_ssid);
1098
1099                         ssid = g_try_malloc0(hex_ssid_len / 2);
1100                         if (!ssid)
1101                                 return -ENOMEM;
1102
1103                         for (i = 0; i < hex_ssid_len; i += 2) {
1104                                 sscanf(hex_ssid + i, "%02x", &hex);
1105                                 ssid[j++] = hex;
1106                         }
1107                 } else {
1108                         ssid = raw_ssid;
1109                         j = ssid_len;
1110                 }
1111
1112                 /*
1113                  * If we have already added hidden AP to the list,
1114                  * then do not do it again. This might happen if you have
1115                  * used or are using multiple wifi cards, so in that case
1116                  * you might have multiple service files for same AP.
1117                  */
1118                 if (is_duplicate(scan_data->ssids, ssid, j)) {
1119                         if (hex_ssid)
1120                                 g_free(ssid);
1121                         return 0;
1122                 }
1123
1124                 scan_ssid = g_try_new(struct scan_ssid, 1);
1125                 if (!scan_ssid) {
1126                         if (hex_ssid)
1127                                 g_free(ssid);
1128                         return -ENOMEM;
1129                 }
1130
1131                 memcpy(scan_ssid->ssid, ssid, j);
1132                 scan_ssid->ssid_len = j;
1133                 scan_data->ssids = g_slist_prepend(scan_data->ssids,
1134                                                                 scan_ssid);
1135
1136                 scan_data->num_ssids++;
1137
1138                 DBG("SSID %s added to scanned list of %d entries", ssid_name,
1139                                                         scan_data->num_ssids);
1140
1141                 if (hex_ssid)
1142                         g_free(ssid);
1143         } else
1144                 return -EINVAL;
1145
1146         scan_data->ssids = g_slist_reverse(scan_data->ssids);
1147
1148         if (!scan_data->freqs) {
1149                 scan_data->freqs = g_try_malloc0(sizeof(uint16_t));
1150                 if (!scan_data->freqs) {
1151                         g_slist_free_full(scan_data->ssids, g_free);
1152                         return -ENOMEM;
1153                 }
1154
1155                 scan_data->num_freqs = 1;
1156                 scan_data->freqs[0] = freq;
1157         } else {
1158                 bool duplicate = false;
1159
1160                 /* Don't add duplicate entries */
1161                 for (i = 0; i < scan_data->num_freqs; i++) {
1162                         if (scan_data->freqs[i] == freq) {
1163                                 duplicate = true;
1164                                 break;
1165                         }
1166                 }
1167
1168                 if (!duplicate) {
1169                         scan_data->num_freqs++;
1170                         scan_data->freqs = g_try_realloc(scan_data->freqs,
1171                                 sizeof(uint16_t) * scan_data->num_freqs);
1172                         if (!scan_data->freqs) {
1173                                 g_slist_free_full(scan_data->ssids, g_free);
1174                                 return -ENOMEM;
1175                         }
1176                         scan_data->freqs[scan_data->num_freqs - 1] = freq;
1177                 }
1178         }
1179
1180         return 1;
1181 }
1182
1183 static int get_hidden_connections(GSupplicantScanParams *scan_data)
1184 {
1185         struct connman_config_entry **entries;
1186         GKeyFile *keyfile;
1187         gchar **services;
1188         char *ssid, *name;
1189         int i, ret;
1190         bool value;
1191         int num_ssids = 0, add_param_failed = 0;
1192
1193         services = connman_storage_get_services();
1194         for (i = 0; services && services[i]; i++) {
1195                 if (strncmp(services[i], "wifi_", 5) != 0)
1196                         continue;
1197
1198                 keyfile = connman_storage_load_service(services[i]);
1199                 if (!keyfile)
1200                         continue;
1201
1202                 value = g_key_file_get_boolean(keyfile,
1203                                         services[i], "Hidden", NULL);
1204                 if (!value) {
1205                         g_key_file_free(keyfile);
1206                         continue;
1207                 }
1208
1209                 value = g_key_file_get_boolean(keyfile,
1210                                         services[i], "Favorite", NULL);
1211                 if (!value) {
1212                         g_key_file_free(keyfile);
1213                         continue;
1214                 }
1215
1216 #if defined TIZEN_EXT
1217                 value = g_key_file_get_boolean(keyfile,
1218                                         services[i], "AutoConnect", NULL);
1219                 if (!value) {
1220                         g_key_file_free(keyfile);
1221                         continue;
1222                 }
1223 #endif
1224
1225                 ssid = g_key_file_get_string(keyfile,
1226                                         services[i], "SSID", NULL);
1227
1228                 name = g_key_file_get_string(keyfile, services[i], "Name",
1229                                                                 NULL);
1230
1231                 ret = add_scan_param(ssid, NULL, 0, 0, scan_data, 0, name);
1232                 if (ret < 0)
1233                         add_param_failed++;
1234                 else if (ret > 0)
1235                         num_ssids++;
1236
1237                 g_free(ssid);
1238                 g_free(name);
1239                 g_key_file_free(keyfile);
1240         }
1241
1242         /*
1243          * Check if there are any hidden AP that needs to be provisioned.
1244          */
1245         entries = connman_config_get_entries("wifi");
1246         for (i = 0; entries && entries[i]; i++) {
1247                 int len;
1248
1249                 if (!entries[i]->hidden)
1250                         continue;
1251
1252                 if (!entries[i]->ssid) {
1253                         ssid = entries[i]->name;
1254                         len = strlen(ssid);
1255                 } else {
1256                         ssid = entries[i]->ssid;
1257                         len = entries[i]->ssid_len;
1258                 }
1259
1260                 if (!ssid)
1261                         continue;
1262
1263                 ret = add_scan_param(NULL, ssid, len, 0, scan_data, 0, ssid);
1264                 if (ret < 0)
1265                         add_param_failed++;
1266                 else if (ret > 0)
1267                         num_ssids++;
1268         }
1269
1270         connman_config_free_entries(entries);
1271
1272         if (add_param_failed > 0)
1273                 DBG("Unable to scan %d out of %d SSIDs",
1274                                         add_param_failed, num_ssids);
1275
1276         g_strfreev(services);
1277
1278         return num_ssids;
1279 }
1280
1281 static int get_hidden_connections_params(struct wifi_data *wifi,
1282                                         GSupplicantScanParams *scan_params)
1283 {
1284         int driver_max_ssids, i;
1285         GSupplicantScanParams *orig_params;
1286
1287         /*
1288          * Scan hidden networks so that we can autoconnect to them.
1289          * We will assume 1 as a default number of ssid to scan.
1290          */
1291         driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
1292                                                         wifi->interface);
1293         if (driver_max_ssids == 0)
1294                 driver_max_ssids = 1;
1295
1296         DBG("max ssids %d", driver_max_ssids);
1297
1298         if (!wifi->scan_params) {
1299                 wifi->scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
1300                 if (!wifi->scan_params)
1301                         return 0;
1302
1303                 if (get_hidden_connections(wifi->scan_params) == 0) {
1304                         g_supplicant_free_scan_params(wifi->scan_params);
1305                         wifi->scan_params = NULL;
1306
1307                         return 0;
1308                 }
1309         }
1310
1311         orig_params = wifi->scan_params;
1312
1313         /* Let's transfer driver_max_ssids params */
1314         for (i = 0; i < driver_max_ssids; i++) {
1315                 struct scan_ssid *ssid;
1316
1317                 if (!wifi->scan_params->ssids)
1318                         break;
1319
1320                 ssid = orig_params->ssids->data;
1321                 orig_params->ssids = g_slist_remove(orig_params->ssids, ssid);
1322                 scan_params->ssids = g_slist_prepend(scan_params->ssids, ssid);
1323         }
1324
1325         if (i > 0) {
1326                 scan_params->num_ssids = i;
1327                 scan_params->ssids = g_slist_reverse(scan_params->ssids);
1328
1329                 scan_params->freqs = g_memdup(orig_params->freqs,
1330                                 sizeof(uint16_t) * orig_params->num_freqs);
1331                 if (!scan_params->freqs)
1332                         goto err;
1333
1334                 scan_params->num_freqs = orig_params->num_freqs;
1335
1336         } else
1337                 goto err;
1338
1339         orig_params->num_ssids -= scan_params->num_ssids;
1340
1341         return scan_params->num_ssids;
1342
1343 err:
1344         g_slist_free_full(scan_params->ssids, g_free);
1345         g_supplicant_free_scan_params(wifi->scan_params);
1346         wifi->scan_params = NULL;
1347
1348         return 0;
1349 }
1350
1351 static int throw_wifi_scan(struct connman_device *device,
1352                         GSupplicantInterfaceCallback callback)
1353 {
1354         struct wifi_data *wifi = connman_device_get_data(device);
1355         int ret;
1356
1357         if (!wifi)
1358                 return -ENODEV;
1359
1360         DBG("device %p %p", device, wifi->interface);
1361
1362         if (wifi->tethering)
1363                 return -EBUSY;
1364 #if defined TIZEN_EXT
1365         if (connman_device_get_scanning(device) && !wifi->allow_full_scan)
1366 #else
1367         if (connman_device_get_scanning(device))
1368 #endif
1369                 return -EALREADY;
1370
1371         connman_device_ref(device);
1372
1373         ret = g_supplicant_interface_scan(wifi->interface, NULL,
1374                                                 callback, device);
1375         if (ret == 0) {
1376                 connman_device_set_scanning(device,
1377                                 CONNMAN_SERVICE_TYPE_WIFI, true);
1378         } else
1379                 connman_device_unref(device);
1380
1381         return ret;
1382 }
1383
1384 static void hidden_free(struct hidden_params *hidden)
1385 {
1386         if (!hidden)
1387                 return;
1388
1389         if (hidden->scan_params)
1390                 g_supplicant_free_scan_params(hidden->scan_params);
1391         g_free(hidden->identity);
1392         g_free(hidden->passphrase);
1393         g_free(hidden->security);
1394         g_free(hidden);
1395 }
1396
1397 #if defined TIZEN_EXT
1398 static void service_state_changed(struct connman_service *service,
1399                                         enum connman_service_state state);
1400
1401 static int network_connect(struct connman_network *network);
1402
1403 static struct connman_notifier notifier = {
1404         .name                   = "wifi",
1405         .priority               = CONNMAN_NOTIFIER_PRIORITY_DEFAULT,
1406         .service_state_changed  = service_state_changed,
1407 };
1408
1409 static void service_state_changed(struct connman_service *service,
1410                                         enum connman_service_state state)
1411 {
1412         enum connman_service_type type;
1413
1414         type = connman_service_get_type(service);
1415         if (type != CONNMAN_SERVICE_TYPE_WIFI)
1416                 return;
1417
1418         DBG("service %p state %d", service, state);
1419
1420         switch (state) {
1421         case CONNMAN_SERVICE_STATE_READY:
1422         case CONNMAN_SERVICE_STATE_ONLINE:
1423         case CONNMAN_SERVICE_STATE_FAILURE:
1424                 connman_notifier_unregister(&notifier);
1425                 is_wifi_notifier_registered = FALSE;
1426
1427                 __connman_device_request_scan(type);
1428                 break;
1429
1430         default:
1431                 break;
1432         }
1433 }
1434 #endif
1435
1436 static void scan_callback(int result, GSupplicantInterface *interface,
1437                                                 void *user_data)
1438 {
1439         struct connman_device *device = user_data;
1440         struct wifi_data *wifi = connman_device_get_data(device);
1441         bool scanning;
1442
1443         DBG("result %d wifi %p", result, wifi);
1444
1445         if (wifi) {
1446                 if (wifi->hidden && !wifi->postpone_hidden) {
1447                         connman_network_clear_hidden(wifi->hidden->user_data);
1448                         hidden_free(wifi->hidden);
1449                         wifi->hidden = NULL;
1450                 }
1451
1452                 if (wifi->scan_params) {
1453                         g_supplicant_free_scan_params(wifi->scan_params);
1454                         wifi->scan_params = NULL;
1455                 }
1456         }
1457
1458         if (result < 0)
1459                 connman_device_reset_scanning(device);
1460
1461         /* User is connecting to a hidden AP, let's wait for finished event */
1462         if (wifi && wifi->hidden && wifi->postpone_hidden) {
1463                 GSupplicantScanParams *scan_params;
1464                 int ret;
1465
1466                 wifi->postpone_hidden = false;
1467                 scan_params = wifi->hidden->scan_params;
1468                 wifi->hidden->scan_params = NULL;
1469
1470                 reset_autoscan(device);
1471
1472                 ret = g_supplicant_interface_scan(wifi->interface, scan_params,
1473                                                         scan_callback, device);
1474                 if (ret == 0)
1475                         return;
1476
1477                 /* On error, let's recall scan_callback, which will cleanup */
1478                 return scan_callback(ret, interface, user_data);
1479         }
1480
1481 #if defined TIZEN_EXT
1482         if (wifi && wifi->allow_full_scan) {
1483                 int ret;
1484                 DBG("Trigger Full Channel Scan");
1485                 wifi->allow_full_scan = FALSE;
1486
1487                 ret = g_supplicant_interface_scan(wifi->interface, NULL,
1488                                                         scan_callback, device);
1489                 if (ret == 0)
1490                         return;
1491
1492                 /* On error, let's recall scan_callback, which will cleanup */
1493                 return scan_callback(ret, interface, user_data);
1494         }
1495 #endif
1496
1497         scanning = connman_device_get_scanning(device);
1498         if (scanning)
1499                 connman_device_set_scanning(device,
1500                                 CONNMAN_SERVICE_TYPE_WIFI, false);
1501
1502         if (result != -ENOLINK)
1503 #if defined TIZEN_EXT
1504         if (result != -EIO)
1505 #endif
1506                 start_autoscan(device);
1507
1508         /*
1509          * If we are here then we were scanning; however, if we are
1510          * also mid-flight disabling the interface, then wifi_disable
1511          * has already cleared the device scanning state and
1512          * unreferenced the device, obviating the need to do it here.
1513          */
1514
1515         if (scanning)
1516                 connman_device_unref(device);
1517
1518 #if defined TIZEN_EXT
1519         if (wifi && wifi->scan_pending_network && result != -EIO) {
1520                 network_connect(wifi->scan_pending_network);
1521                 wifi->scan_pending_network = NULL;
1522                 connman_network_set_connecting(wifi->network);
1523         }
1524
1525         if (is_wifi_notifier_registered != true &&
1526                         wifi_first_scan == true && found_with_first_scan == true) {
1527                 wifi_first_scan = false;
1528                 found_with_first_scan = false;
1529
1530                 connman_notifier_register(&notifier);
1531                 is_wifi_notifier_registered = true;
1532         }
1533 #endif
1534 }
1535
1536 static void scan_callback_hidden(int result,
1537                         GSupplicantInterface *interface, void *user_data)
1538 {
1539         struct connman_device *device = user_data;
1540         struct wifi_data *wifi = connman_device_get_data(device);
1541         GSupplicantScanParams *scan_params;
1542         int ret;
1543
1544         DBG("result %d wifi %p", result, wifi);
1545
1546         if (!wifi)
1547                 goto out;
1548
1549         /* User is trying to connect to a hidden AP */
1550         if (wifi->hidden && wifi->postpone_hidden)
1551                 goto out;
1552
1553         scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
1554         if (!scan_params)
1555                 goto out;
1556
1557         if (get_hidden_connections_params(wifi, scan_params) > 0) {
1558                 ret = g_supplicant_interface_scan(wifi->interface,
1559                                                         scan_params,
1560                                                         scan_callback_hidden,
1561                                                         device);
1562                 if (ret == 0)
1563                         return;
1564         }
1565
1566         g_supplicant_free_scan_params(scan_params);
1567
1568 out:
1569         scan_callback(result, interface, user_data);
1570 }
1571
1572 static gboolean autoscan_timeout(gpointer data)
1573 {
1574         struct connman_device *device = data;
1575         struct wifi_data *wifi = connman_device_get_data(device);
1576         struct autoscan_params *autoscan;
1577         int interval;
1578
1579         if (!wifi)
1580                 return FALSE;
1581
1582         autoscan = wifi->autoscan;
1583
1584         if (autoscan->interval <= 0) {
1585                 interval = autoscan->base;
1586                 goto set_interval;
1587         } else
1588                 interval = autoscan->interval * autoscan->base;
1589
1590 #if defined TIZEN_EXT
1591         if (autoscan->interval >= autoscan->limit)
1592 #else
1593         if (interval > autoscan->limit)
1594 #endif
1595                 interval = autoscan->limit;
1596
1597         throw_wifi_scan(wifi->device, scan_callback_hidden);
1598
1599 set_interval:
1600         DBG("interval %d", interval);
1601
1602         autoscan->interval = interval;
1603
1604         autoscan->timeout = g_timeout_add_seconds(interval,
1605                                                 autoscan_timeout, device);
1606
1607         return FALSE;
1608 }
1609
1610 static void start_autoscan(struct connman_device *device)
1611 {
1612         struct wifi_data *wifi = connman_device_get_data(device);
1613         struct autoscan_params *autoscan;
1614
1615         DBG("");
1616
1617         if (!wifi)
1618                 return;
1619
1620         if (wifi->p2p_device)
1621                 return;
1622
1623         if (wifi->connected)
1624                 return;
1625
1626         autoscan = wifi->autoscan;
1627         if (!autoscan)
1628                 return;
1629
1630         if (autoscan->timeout > 0 || autoscan->interval > 0)
1631                 return;
1632
1633         connman_device_ref(device);
1634
1635         autoscan_timeout(device);
1636 }
1637
1638 static struct autoscan_params *parse_autoscan_params(const char *params)
1639 {
1640         struct autoscan_params *autoscan;
1641         char **list_params;
1642         int limit;
1643         int base;
1644
1645         DBG("Emulating autoscan");
1646
1647         list_params = g_strsplit(params, ":", 0);
1648         if (list_params == 0)
1649                 return NULL;
1650
1651         if (g_strv_length(list_params) < 3) {
1652                 g_strfreev(list_params);
1653                 return NULL;
1654         }
1655
1656         base = atoi(list_params[1]);
1657         limit = atoi(list_params[2]);
1658
1659         g_strfreev(list_params);
1660
1661         autoscan = g_try_malloc0(sizeof(struct autoscan_params));
1662         if (!autoscan) {
1663                 DBG("Could not allocate memory for autoscan");
1664                 return NULL;
1665         }
1666
1667         DBG("base %d - limit %d", base, limit);
1668         autoscan->base = base;
1669         autoscan->limit = limit;
1670
1671         return autoscan;
1672 }
1673
1674 static void setup_autoscan(struct wifi_data *wifi)
1675 {
1676         if (!wifi->autoscan)
1677                 wifi->autoscan = parse_autoscan_params(AUTOSCAN_DEFAULT);
1678
1679         start_autoscan(wifi->device);
1680 }
1681
1682 static void finalize_interface_creation(struct wifi_data *wifi)
1683 {
1684         DBG("interface is ready wifi %p tethering %d", wifi, wifi->tethering);
1685
1686         if (!wifi->device) {
1687                 connman_error("WiFi device not set");
1688                 return;
1689         }
1690
1691         connman_device_set_powered(wifi->device, true);
1692
1693         if (!connman_setting_get_bool("BackgroundScanning"))
1694                 return;
1695
1696         if (wifi->p2p_device)
1697                 return;
1698
1699         setup_autoscan(wifi);
1700 }
1701
1702 static void interface_create_callback(int result,
1703                                         GSupplicantInterface *interface,
1704                                                         void *user_data)
1705 {
1706         struct wifi_data *wifi = user_data;
1707
1708         DBG("result %d ifname %s, wifi %p", result,
1709                                 g_supplicant_interface_get_ifname(interface),
1710                                 wifi);
1711
1712         if (result < 0 || !wifi)
1713                 return;
1714
1715         wifi->interface = interface;
1716         g_supplicant_interface_set_data(interface, wifi);
1717
1718         if (g_supplicant_interface_get_ready(interface)) {
1719                 wifi->interface_ready = true;
1720                 finalize_interface_creation(wifi);
1721         }
1722 }
1723
1724 static int wifi_enable(struct connman_device *device)
1725 {
1726         struct wifi_data *wifi = connman_device_get_data(device);
1727         int index;
1728         char *interface;
1729         const char *driver = connman_option_get_string("wifi");
1730         int ret;
1731
1732         DBG("device %p %p", device, wifi);
1733
1734         index = connman_device_get_index(device);
1735         if (!wifi || index < 0)
1736                 return -ENODEV;
1737
1738         if (is_p2p_connecting())
1739                 return -EINPROGRESS;
1740
1741         interface = connman_inet_ifname(index);
1742         ret = g_supplicant_interface_create(interface, driver, NULL,
1743                                                 interface_create_callback,
1744                                                         wifi);
1745         g_free(interface);
1746
1747         if (ret < 0)
1748                 return ret;
1749
1750         return -EINPROGRESS;
1751 }
1752
1753 static int wifi_disable(struct connman_device *device)
1754 {
1755         struct wifi_data *wifi = connman_device_get_data(device);
1756         int ret;
1757
1758         DBG("device %p wifi %p", device, wifi);
1759
1760         if (!wifi)
1761                 return -ENODEV;
1762
1763         wifi->connected = false;
1764         wifi->disconnecting = false;
1765
1766         if (wifi->pending_network)
1767                 wifi->pending_network = NULL;
1768
1769         stop_autoscan(device);
1770
1771         if (wifi->p2p_find_timeout) {
1772                 g_source_remove(wifi->p2p_find_timeout);
1773                 wifi->p2p_find_timeout = 0;
1774                 connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_P2P, false);
1775                 connman_device_unref(wifi->device);
1776         }
1777
1778         /* In case of a user scan, device is still referenced */
1779         if (connman_device_get_scanning(device)) {
1780                 connman_device_set_scanning(device,
1781                                 CONNMAN_SERVICE_TYPE_WIFI, false);
1782                 connman_device_unref(wifi->device);
1783         }
1784
1785         remove_networks(device, wifi);
1786         remove_peers(wifi);
1787
1788 #if defined TIZEN_EXT
1789         wifi->scan_pending_network = NULL;
1790
1791         if (is_wifi_notifier_registered == true) {
1792                 connman_notifier_unregister(&notifier);
1793                 is_wifi_notifier_registered = false;
1794         }
1795 #endif
1796
1797         ret = g_supplicant_interface_remove(wifi->interface, NULL, NULL);
1798         if (ret < 0)
1799                 return ret;
1800
1801         return -EINPROGRESS;
1802 }
1803
1804 struct last_connected {
1805         GTimeVal modified;
1806         gchar *ssid;
1807         int freq;
1808 };
1809
1810 static gint sort_entry(gconstpointer a, gconstpointer b, gpointer user_data)
1811 {
1812         GTimeVal *aval = (GTimeVal *)a;
1813         GTimeVal *bval = (GTimeVal *)b;
1814
1815         /* Note that the sort order is descending */
1816         if (aval->tv_sec < bval->tv_sec)
1817                 return 1;
1818
1819         if (aval->tv_sec > bval->tv_sec)
1820                 return -1;
1821
1822         return 0;
1823 }
1824
1825 static void free_entry(gpointer data)
1826 {
1827         struct last_connected *entry = data;
1828
1829         g_free(entry->ssid);
1830         g_free(entry);
1831 }
1832
1833 static int get_latest_connections(int max_ssids,
1834                                 GSupplicantScanParams *scan_data)
1835 {
1836         GSequenceIter *iter;
1837         GSequence *latest_list;
1838         struct last_connected *entry;
1839         GKeyFile *keyfile;
1840         GTimeVal modified;
1841         gchar **services;
1842         gchar *str;
1843         char *ssid;
1844         int i, freq;
1845         int num_ssids = 0;
1846
1847         latest_list = g_sequence_new(free_entry);
1848         if (!latest_list)
1849                 return -ENOMEM;
1850
1851         services = connman_storage_get_services();
1852         for (i = 0; services && services[i]; i++) {
1853                 if (strncmp(services[i], "wifi_", 5) != 0)
1854                         continue;
1855
1856                 keyfile = connman_storage_load_service(services[i]);
1857                 if (!keyfile)
1858                         continue;
1859
1860                 str = g_key_file_get_string(keyfile,
1861                                         services[i], "Favorite", NULL);
1862                 if (!str || g_strcmp0(str, "true")) {
1863                         g_free(str);
1864                         g_key_file_free(keyfile);
1865                         continue;
1866                 }
1867                 g_free(str);
1868
1869                 str = g_key_file_get_string(keyfile,
1870                                         services[i], "AutoConnect", NULL);
1871                 if (!str || g_strcmp0(str, "true")) {
1872                         g_free(str);
1873                         g_key_file_free(keyfile);
1874                         continue;
1875                 }
1876                 g_free(str);
1877
1878                 str = g_key_file_get_string(keyfile,
1879                                         services[i], "Modified", NULL);
1880                 if (!str) {
1881                         g_key_file_free(keyfile);
1882                         continue;
1883                 }
1884                 g_time_val_from_iso8601(str, &modified);
1885                 g_free(str);
1886
1887                 ssid = g_key_file_get_string(keyfile,
1888                                         services[i], "SSID", NULL);
1889
1890                 freq = g_key_file_get_integer(keyfile, services[i],
1891                                         "Frequency", NULL);
1892                 if (freq) {
1893                         entry = g_try_new(struct last_connected, 1);
1894                         if (!entry) {
1895                                 g_sequence_free(latest_list);
1896                                 g_key_file_free(keyfile);
1897                                 g_free(ssid);
1898                                 return -ENOMEM;
1899                         }
1900
1901                         entry->ssid = ssid;
1902                         entry->modified = modified;
1903                         entry->freq = freq;
1904
1905                         g_sequence_insert_sorted(latest_list, entry,
1906                                                 sort_entry, NULL);
1907                         num_ssids++;
1908                 } else
1909                         g_free(ssid);
1910
1911                 g_key_file_free(keyfile);
1912         }
1913
1914         g_strfreev(services);
1915
1916         num_ssids = num_ssids > max_ssids ? max_ssids : num_ssids;
1917
1918         iter = g_sequence_get_begin_iter(latest_list);
1919
1920         for (i = 0; i < num_ssids; i++) {
1921                 entry = g_sequence_get(iter);
1922
1923                 DBG("ssid %s freq %d modified %lu", entry->ssid, entry->freq,
1924                                                 entry->modified.tv_sec);
1925
1926                 add_scan_param(entry->ssid, NULL, 0, entry->freq, scan_data,
1927                                                 max_ssids, entry->ssid);
1928
1929                 iter = g_sequence_iter_next(iter);
1930         }
1931
1932         g_sequence_free(latest_list);
1933         return num_ssids;
1934 }
1935
1936 static int wifi_scan_simple(struct connman_device *device)
1937 {
1938         reset_autoscan(device);
1939
1940         return throw_wifi_scan(device, scan_callback_hidden);
1941 }
1942
1943 static gboolean p2p_find_stop(gpointer data)
1944 {
1945         struct connman_device *device = data;
1946         struct wifi_data *wifi = connman_device_get_data(device);
1947
1948         DBG("");
1949
1950         if (wifi) {
1951                 wifi->p2p_find_timeout = 0;
1952
1953                 g_supplicant_interface_p2p_stop_find(wifi->interface);
1954         }
1955
1956         connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_P2P, false);
1957
1958         connman_device_unref(device);
1959         reset_autoscan(device);
1960
1961         return FALSE;
1962 }
1963
1964 static void p2p_find_callback(int result, GSupplicantInterface *interface,
1965                                                         void *user_data)
1966 {
1967         struct connman_device *device = user_data;
1968         struct wifi_data *wifi = connman_device_get_data(device);
1969
1970         DBG("result %d wifi %p", result, wifi);
1971
1972         if (!wifi)
1973                 goto error;
1974
1975         if (wifi->p2p_find_timeout) {
1976                 g_source_remove(wifi->p2p_find_timeout);
1977                 wifi->p2p_find_timeout = 0;
1978         }
1979
1980         if (result)
1981                 goto error;
1982
1983         wifi->p2p_find_timeout = g_timeout_add_seconds(P2P_FIND_TIMEOUT,
1984                                                         p2p_find_stop, device);
1985         if (!wifi->p2p_find_timeout)
1986                 goto error;
1987
1988         return;
1989 error:
1990         p2p_find_stop(device);
1991 }
1992
1993 static int p2p_find(struct connman_device *device)
1994 {
1995         struct wifi_data *wifi;
1996         int ret;
1997
1998         DBG("");
1999
2000         if (!p2p_technology)
2001                 return -ENOTSUP;
2002
2003         wifi = connman_device_get_data(device);
2004
2005         if (g_supplicant_interface_is_p2p_finding(wifi->interface))
2006                 return -EALREADY;
2007
2008         reset_autoscan(device);
2009         connman_device_ref(device);
2010
2011         ret = g_supplicant_interface_p2p_find(wifi->interface,
2012                                                 p2p_find_callback, device);
2013         if (ret) {
2014                 connman_device_unref(device);
2015                 start_autoscan(device);
2016         } else {
2017                 connman_device_set_scanning(device,
2018                                 CONNMAN_SERVICE_TYPE_P2P, true);
2019         }
2020
2021         return ret;
2022 }
2023
2024 #if defined TIZEN_EXT
2025 static void specific_scan_callback(int result, GSupplicantInterface *interface,
2026                                                 void *user_data)
2027 {
2028         struct connman_device *device = user_data;
2029         struct wifi_data *wifi = connman_device_get_data(device);
2030         bool scanning;
2031
2032         DBG("result %d wifi %p", result, wifi);
2033
2034         if (wifi && wifi->scan_params) {
2035                 g_supplicant_free_scan_params(wifi->scan_params);
2036                 wifi->scan_params = NULL;
2037         }
2038
2039         scanning = connman_device_get_scanning(device);
2040         if (scanning) {
2041                 connman_device_set_scanning(device,
2042                                 CONNMAN_SERVICE_TYPE_WIFI, false);
2043                 connman_device_unref(device);
2044         }
2045 }
2046
2047 static int wifi_specific_scan(enum connman_service_type type,
2048                         struct connman_device *device, int scan_type,
2049                         GSList *specific_scan_list, void *user_data)
2050 {
2051         GSList *list = NULL;
2052         char *ssid = NULL;
2053         struct wifi_data *wifi = connman_device_get_data(device);
2054         GSupplicantScanParams *scan_params = NULL;
2055         struct scan_ssid *scan_ssid = NULL;
2056         bool scanning;
2057         int ret;
2058         int freq;
2059         int count = 0;
2060
2061         if (!wifi)
2062                 return -ENODEV;
2063
2064         if (wifi->p2p_device)
2065                 return 0;
2066
2067         if (type == CONNMAN_SERVICE_TYPE_P2P)
2068                 return p2p_find(device);
2069
2070         if (wifi->tethering)
2071                 return 0;
2072
2073         scanning = connman_device_get_scanning(device);
2074         if (scanning)
2075                 return -EALREADY;
2076
2077         DBG("scan_type: %d", scan_type);
2078         if (scan_type == CONNMAN_MULTI_SCAN_SSID) { /* ssid based scan */
2079                 scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
2080                 if (!scan_params) {
2081                         DBG("Failed to allocate memory.");
2082                         return -ENOMEM;
2083                 }
2084
2085                 for (list = specific_scan_list; list; list = list->next) {
2086                         ssid = (char *)list->data;
2087                         int ssid_len = strlen(ssid);
2088
2089                         scan_ssid = g_try_new0(struct scan_ssid, 1);
2090                         if (!scan_ssid) {
2091                                 DBG("Failed to allocate memory.");
2092                                 g_supplicant_free_scan_params(scan_params);
2093                                 return -ENOMEM;
2094                         }
2095
2096                         memcpy(scan_ssid->ssid, ssid, (ssid_len + 1));
2097                         DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len);
2098                         scan_ssid->ssid_len = ssid_len;
2099                         scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid);
2100                         count++;
2101                 }
2102                 scan_params->num_ssids = count;
2103
2104         } else if (scan_type == CONNMAN_MULTI_SCAN_FREQ) { /* frequency based scan */
2105
2106                 scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
2107                 if (!scan_params) {
2108                         DBG("Failed to allocate memory.");
2109                         return -ENOMEM;
2110                 }
2111
2112                 guint num_freqs = g_slist_length(specific_scan_list);
2113                 DBG("num_freqs: %d", num_freqs);
2114
2115                 scan_params->freqs = g_try_new0(uint16_t, num_freqs);
2116                 if (!scan_params->freqs) {
2117                         DBG("Failed to allocate memory.");
2118                         g_free(scan_params);
2119                         return -ENOMEM;
2120                 }
2121
2122                 count = 0;
2123                 for (list = specific_scan_list; list; list = list->next) {
2124                         freq = (int)list->data;
2125
2126                         scan_params->freqs[count] = freq;
2127                         DBG("scan_params->freqs[%d]: %d", count, scan_params->freqs[count]);
2128                         count++;
2129                 }
2130                 scan_params->num_freqs = count;
2131
2132         } else if (scan_type == CONNMAN_MULTI_SCAN_SSID_FREQ) { /* SSID & Frequency mixed scan */
2133                 int freq_count, ap_count;
2134                 scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
2135                 if (!scan_params) {
2136                         DBG("Failed to allocate memory.");
2137                         return -ENOMEM;
2138                 }
2139
2140                 guint size = g_slist_length(specific_scan_list);
2141
2142                 scan_params->freqs = g_try_new0(uint16_t, size/2);
2143                 if (!scan_params->freqs) {
2144                         DBG("Failed to allocate memory.");
2145                         g_free(scan_params);
2146                         return -ENOMEM;
2147                 }
2148
2149                 ap_count = freq_count = 0;
2150                 for (list = specific_scan_list; list; list = list->next) {
2151                         if (((connman_multi_scan_ap_s *)list->data)->flag == true) { /** ssid */
2152                                 ssid = ((connman_multi_scan_ap_s *)list->data)->str;
2153                                 int ssid_len = strlen(ssid);
2154
2155                                 scan_ssid = g_try_new0(struct scan_ssid, 1);
2156                                 if (!scan_ssid) {
2157                                         DBG("Failed to allocate memory.");
2158                                         g_supplicant_free_scan_params(scan_params);
2159                                         return -ENOMEM;
2160                                 }
2161
2162                                 memcpy(scan_ssid->ssid, ssid, (ssid_len + 1));
2163                                 DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len);
2164                                 scan_ssid->ssid_len = ssid_len;
2165                                 scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid);
2166                                 ap_count++;
2167
2168                         } else { /* freq */
2169                                 freq = atoi(((connman_multi_scan_ap_s *)list->data)->str);
2170                                 scan_params->freqs[freq_count] = freq;
2171                                 DBG("scan_params->freqs[%d]: %d", freq_count, scan_params->freqs[freq_count]);
2172                                 freq_count++;
2173                         }
2174                 }
2175                 scan_params->num_ssids = ap_count;
2176                 scan_params->num_freqs = freq_count;
2177         } else {
2178                 DBG("Invalid scan");
2179                 return -EINVAL;
2180         }
2181
2182         reset_autoscan(device);
2183         connman_device_ref(device);
2184
2185         ret = g_supplicant_interface_scan(wifi->interface, scan_params,
2186                                                 specific_scan_callback, device);
2187
2188         if (ret == 0) {
2189                 connman_device_set_scanning(device,
2190                                 CONNMAN_SERVICE_TYPE_WIFI, true);
2191         } else {
2192                 g_supplicant_free_scan_params(scan_params);
2193                 connman_device_unref(device);
2194         }
2195
2196         return ret;
2197 }
2198 #endif
2199
2200 /*
2201  * Note that the hidden scan is only used when connecting to this specific
2202  * hidden AP first time. It is not used when system autoconnects to hidden AP.
2203  */
2204 static int wifi_scan(enum connman_service_type type,
2205                         struct connman_device *device,
2206                         const char *ssid, unsigned int ssid_len,
2207                         const char *identity, const char* passphrase,
2208                         const char *security, void *user_data)
2209 {
2210         struct wifi_data *wifi = connman_device_get_data(device);
2211         GSupplicantScanParams *scan_params = NULL;
2212         struct scan_ssid *scan_ssid;
2213         struct hidden_params *hidden;
2214         int ret;
2215         int driver_max_ssids = 0;
2216         bool do_hidden;
2217         bool scanning;
2218
2219         if (!wifi)
2220                 return -ENODEV;
2221
2222         if (wifi->p2p_device)
2223                 return -EBUSY;
2224
2225         if (wifi->tethering)
2226                 return -EBUSY;
2227
2228         if (type == CONNMAN_SERVICE_TYPE_P2P)
2229                 return p2p_find(device);
2230
2231         DBG("device %p wifi %p hidden ssid %s", device, wifi->interface, ssid);
2232
2233         scanning = connman_device_get_scanning(device);
2234
2235         if (!ssid || ssid_len == 0 || ssid_len > 32) {
2236                 if (scanning)
2237                         return -EALREADY;
2238
2239                 driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
2240                                                         wifi->interface);
2241                 DBG("max ssids %d", driver_max_ssids);
2242                 if (driver_max_ssids == 0)
2243                         return wifi_scan_simple(device);
2244
2245                 do_hidden = false;
2246         } else {
2247                 if (scanning && wifi->hidden && wifi->postpone_hidden)
2248                         return -EALREADY;
2249
2250                 do_hidden = true;
2251         }
2252
2253         scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
2254         if (!scan_params)
2255                 return -ENOMEM;
2256
2257         if (do_hidden) {
2258                 scan_ssid = g_try_new(struct scan_ssid, 1);
2259                 if (!scan_ssid) {
2260                         g_free(scan_params);
2261                         return -ENOMEM;
2262                 }
2263
2264                 memcpy(scan_ssid->ssid, ssid, ssid_len);
2265                 scan_ssid->ssid_len = ssid_len;
2266                 scan_params->ssids = g_slist_prepend(scan_params->ssids,
2267                                                                 scan_ssid);
2268                 scan_params->num_ssids = 1;
2269
2270                 hidden = g_try_new0(struct hidden_params, 1);
2271                 if (!hidden) {
2272                         g_supplicant_free_scan_params(scan_params);
2273                         return -ENOMEM;
2274                 }
2275
2276                 if (wifi->hidden) {
2277                         hidden_free(wifi->hidden);
2278                         wifi->hidden = NULL;
2279                 }
2280
2281                 memcpy(hidden->ssid, ssid, ssid_len);
2282                 hidden->ssid_len = ssid_len;
2283                 hidden->identity = g_strdup(identity);
2284                 hidden->passphrase = g_strdup(passphrase);
2285                 hidden->security = g_strdup(security);
2286                 hidden->user_data = user_data;
2287                 wifi->hidden = hidden;
2288
2289                 if (scanning) {
2290                         /* Let's keep this active scan for later,
2291                          * when current scan will be over. */
2292                         wifi->postpone_hidden = TRUE;
2293                         hidden->scan_params = scan_params;
2294
2295                         return 0;
2296                 }
2297         } else if (wifi->connected) {
2298                 g_supplicant_free_scan_params(scan_params);
2299                 return wifi_scan_simple(device);
2300         } else {
2301                 ret = get_latest_connections(driver_max_ssids, scan_params);
2302                 if (ret <= 0) {
2303                         g_supplicant_free_scan_params(scan_params);
2304                         return wifi_scan_simple(device);
2305                 }
2306         }
2307
2308         connman_device_ref(device);
2309
2310         reset_autoscan(device);
2311
2312         ret = g_supplicant_interface_scan(wifi->interface, scan_params,
2313                                                 scan_callback, device);
2314
2315         if (ret == 0) {
2316                 connman_device_set_scanning(device,
2317                                 CONNMAN_SERVICE_TYPE_WIFI, true);
2318 #if defined TIZEN_EXT
2319                 /*To allow the Full Scan after ssid based scan, set the flag here
2320                   It is required because Tizen does not use the ConnMan specific
2321                   backgroung Scan feature.Tizen has added the BG Scan feature in
2322                   net-config. To sync with up ConnMan, we need to issue the Full Scan
2323                   after SSID specific scan.*/
2324                 wifi->allow_full_scan = TRUE;
2325 #endif
2326         } else {
2327                 g_supplicant_free_scan_params(scan_params);
2328                 connman_device_unref(device);
2329
2330                 if (do_hidden) {
2331                         hidden_free(wifi->hidden);
2332                         wifi->hidden = NULL;
2333                 }
2334         }
2335
2336         return ret;
2337 }
2338
2339 static void wifi_regdom_callback(int result,
2340                                         const char *alpha2,
2341                                                 void *user_data)
2342 {
2343         struct connman_device *device = user_data;
2344
2345         connman_device_regdom_notify(device, result, alpha2);
2346
2347         connman_device_unref(device);
2348 }
2349
2350 static int wifi_set_regdom(struct connman_device *device, const char *alpha2)
2351 {
2352         struct wifi_data *wifi = connman_device_get_data(device);
2353         int ret;
2354
2355         if (!wifi)
2356                 return -EINVAL;
2357
2358         connman_device_ref(device);
2359
2360         ret = g_supplicant_interface_set_country(wifi->interface,
2361                                                 wifi_regdom_callback,
2362                                                         alpha2, device);
2363         if (ret != 0)
2364                 connman_device_unref(device);
2365
2366         return ret;
2367 }
2368
2369 static struct connman_device_driver wifi_ng_driver = {
2370         .name           = "wifi",
2371         .type           = CONNMAN_DEVICE_TYPE_WIFI,
2372         .priority       = CONNMAN_DEVICE_PRIORITY_LOW,
2373         .probe          = wifi_probe,
2374         .remove         = wifi_remove,
2375         .enable         = wifi_enable,
2376         .disable        = wifi_disable,
2377         .scan           = wifi_scan,
2378         .set_regdom     = wifi_set_regdom,
2379 #if defined TIZEN_EXT
2380         .specific_scan  = wifi_specific_scan,
2381 #endif
2382 };
2383
2384 static void system_ready(void)
2385 {
2386         DBG("");
2387
2388         if (connman_device_driver_register(&wifi_ng_driver) < 0)
2389                 connman_error("Failed to register WiFi driver");
2390 }
2391
2392 static void system_killed(void)
2393 {
2394         DBG("");
2395
2396         connman_device_driver_unregister(&wifi_ng_driver);
2397 }
2398
2399 static int network_probe(struct connman_network *network)
2400 {
2401         DBG("network %p", network);
2402
2403         return 0;
2404 }
2405
2406 static void network_remove(struct connman_network *network)
2407 {
2408         struct connman_device *device = connman_network_get_device(network);
2409         struct wifi_data *wifi;
2410
2411         DBG("network %p", network);
2412
2413         wifi = connman_device_get_data(device);
2414         if (!wifi)
2415                 return;
2416
2417         if (wifi->network != network)
2418                 return;
2419
2420         wifi->network = NULL;
2421
2422 #if defined TIZEN_EXT
2423         wifi->disconnecting = false;
2424
2425         if (wifi->pending_network == network)
2426                 wifi->pending_network = NULL;
2427
2428         if (wifi->scan_pending_network == network)
2429                 wifi->scan_pending_network = NULL;
2430 #endif
2431 }
2432
2433 static void connect_callback(int result, GSupplicantInterface *interface,
2434                                                         void *user_data)
2435 {
2436 #if defined TIZEN_EXT
2437         GList *list;
2438         struct wifi_data *wifi;
2439 #endif
2440         struct connman_network *network = user_data;
2441
2442         DBG("network %p result %d", network, result);
2443
2444 #if defined TIZEN_EXT
2445         set_connman_bssid(RESET_BSSID, NULL);
2446
2447         for (list = iface_list; list; list = list->next) {
2448                 wifi = list->data;
2449
2450                 if (wifi && wifi->network == network)
2451                         goto found;
2452         }
2453
2454         /* wifi_data may be invalid because wifi is already disabled */
2455         return;
2456
2457 found:
2458 #endif
2459         if (result == -ENOKEY) {
2460                 connman_network_set_error(network,
2461                                         CONNMAN_NETWORK_ERROR_INVALID_KEY);
2462         } else if (result < 0) {
2463                 connman_network_set_error(network,
2464                                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
2465         }
2466
2467         connman_network_unref(network);
2468 }
2469
2470 static GSupplicantSecurity network_security(const char *security)
2471 {
2472         if (g_str_equal(security, "none"))
2473                 return G_SUPPLICANT_SECURITY_NONE;
2474         else if (g_str_equal(security, "wep"))
2475                 return G_SUPPLICANT_SECURITY_WEP;
2476         else if (g_str_equal(security, "psk"))
2477                 return G_SUPPLICANT_SECURITY_PSK;
2478         else if (g_str_equal(security, "wpa"))
2479                 return G_SUPPLICANT_SECURITY_PSK;
2480         else if (g_str_equal(security, "rsn"))
2481                 return G_SUPPLICANT_SECURITY_PSK;
2482         else if (g_str_equal(security, "ieee8021x"))
2483                 return G_SUPPLICANT_SECURITY_IEEE8021X;
2484 #if defined TIZEN_EXT
2485         else if (g_str_equal(security, "ft_psk") == TRUE)
2486                 return G_SUPPLICANT_SECURITY_FT_PSK;
2487         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
2488                 return G_SUPPLICANT_SECURITY_FT_IEEE8021X;
2489 #endif
2490
2491         return G_SUPPLICANT_SECURITY_UNKNOWN;
2492 }
2493
2494 #if defined TIZEN_EXT
2495 static GSupplicantEapKeymgmt network_eap_keymgmt(const char *security)
2496 {
2497         if (security == NULL)
2498                 return G_SUPPLICANT_EAP_KEYMGMT_NONE;
2499
2500         if (g_str_equal(security, "FT") == TRUE)
2501                 return G_SUPPLICANT_EAP_KEYMGMT_FT;
2502         else if (g_str_equal(security, "CCKM") == TRUE)
2503                 return G_SUPPLICANT_EAP_KEYMGMT_CCKM;
2504
2505         return G_SUPPLICANT_EAP_KEYMGMT_NONE;
2506 }
2507 #endif
2508
2509 static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
2510 {
2511         const char *security;
2512
2513         memset(ssid, 0, sizeof(*ssid));
2514         ssid->mode = G_SUPPLICANT_MODE_INFRA;
2515         ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
2516                                                 &ssid->ssid_len);
2517         ssid->scan_ssid = 1;
2518         security = connman_network_get_string(network, "WiFi.Security");
2519         ssid->security = network_security(security);
2520         ssid->passphrase = connman_network_get_string(network,
2521                                                 "WiFi.Passphrase");
2522         ssid->eap = connman_network_get_string(network, "WiFi.EAP");
2523
2524         /*
2525          * If our private key password is unset,
2526          * we use the supplied passphrase. That is needed
2527          * for PEAP where 2 passphrases (identity and client
2528          * cert may have to be provided.
2529          */
2530         if (!connman_network_get_string(network, "WiFi.PrivateKeyPassphrase"))
2531                 connman_network_set_string(network,
2532                                                 "WiFi.PrivateKeyPassphrase",
2533                                                 ssid->passphrase);
2534         /* We must have an identity for both PEAP and TLS */
2535         ssid->identity = connman_network_get_string(network, "WiFi.Identity");
2536
2537         /* Use agent provided identity as a fallback */
2538         if (!ssid->identity || strlen(ssid->identity) == 0)
2539                 ssid->identity = connman_network_get_string(network,
2540                                                         "WiFi.AgentIdentity");
2541
2542         ssid->anonymous_identity = connman_network_get_string(network,
2543                                                 "WiFi.AnonymousIdentity");
2544         ssid->ca_cert_path = connman_network_get_string(network,
2545                                                         "WiFi.CACertFile");
2546         ssid->subject_match = connman_network_get_string(network,
2547                                                         "WiFi.SubjectMatch");
2548         ssid->altsubject_match = connman_network_get_string(network,
2549                                                         "WiFi.AltSubjectMatch");
2550         ssid->domain_suffix_match = connman_network_get_string(network,
2551                                                         "WiFi.DomainSuffixMatch");
2552         ssid->domain_match = connman_network_get_string(network,
2553                                                         "WiFi.DomainMatch");
2554         ssid->client_cert_path = connman_network_get_string(network,
2555                                                         "WiFi.ClientCertFile");
2556         ssid->private_key_path = connman_network_get_string(network,
2557                                                         "WiFi.PrivateKeyFile");
2558         ssid->private_key_passphrase = connman_network_get_string(network,
2559                                                 "WiFi.PrivateKeyPassphrase");
2560         ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
2561
2562         ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS");
2563         ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS");
2564
2565 #if defined TIZEN_EXT
2566         ssid->bssid = connman_network_get_bssid(network);
2567
2568         ssid->eap_keymgmt = network_eap_keymgmt(
2569                         connman_network_get_string(network, "WiFi.KeymgmtType"));
2570         ssid->phase1 = connman_network_get_string(network, "WiFi.Phase1");
2571
2572         if(g_strcmp0(ssid->eap, "fast") == 0)
2573                 ssid->pac_file = g_strdup(WIFI_EAP_FAST_PAC_FILE);
2574
2575         if (set_connman_bssid(CHECK_BSSID, NULL) == 6) {
2576                 ssid->bssid_for_connect_len = 6;
2577                 set_connman_bssid(GET_BSSID, (char *)ssid->bssid_for_connect);
2578                 DBG("BSSID : %02x:%02x:%02x:%02x:%02x:%02x",
2579                         ssid->bssid_for_connect[0], ssid->bssid_for_connect[1],
2580                         ssid->bssid_for_connect[2], ssid->bssid_for_connect[3],
2581                         ssid->bssid_for_connect[4], ssid->bssid_for_connect[5]);
2582         } else {
2583                 ssid->freq = connman_network_get_frequency(network);
2584         }
2585 #endif
2586
2587         if (connman_setting_get_bool("BackgroundScanning"))
2588                 ssid->bgscan = BGSCAN_DEFAULT;
2589 }
2590
2591 static int network_connect(struct connman_network *network)
2592 {
2593         struct connman_device *device = connman_network_get_device(network);
2594         struct wifi_data *wifi;
2595         GSupplicantInterface *interface;
2596         GSupplicantSSID *ssid;
2597
2598         DBG("network %p", network);
2599
2600         if (!device)
2601                 return -ENODEV;
2602
2603         wifi = connman_device_get_data(device);
2604         if (!wifi)
2605                 return -ENODEV;
2606
2607         ssid = g_try_malloc0(sizeof(GSupplicantSSID));
2608         if (!ssid)
2609                 return -ENOMEM;
2610
2611         interface = wifi->interface;
2612
2613         ssid_init(ssid, network);
2614
2615         if (wifi->disconnecting) {
2616                 wifi->pending_network = network;
2617                 g_free(ssid);
2618         } else {
2619                 wifi->network = connman_network_ref(network);
2620                 wifi->retries = 0;
2621 #if defined TIZEN_EXT
2622                 wifi->scan_pending_network = NULL;
2623 #endif
2624
2625                 return g_supplicant_interface_connect(interface, ssid,
2626                                                 connect_callback, network);
2627         }
2628
2629         return -EINPROGRESS;
2630 }
2631
2632 static void disconnect_callback(int result, GSupplicantInterface *interface,
2633                                                                 void *user_data)
2634 {
2635 #if defined TIZEN_EXT
2636         GList *list;
2637         struct wifi_data *wifi;
2638         struct connman_network *network = user_data;
2639
2640         DBG("network %p result %d", network, result);
2641
2642         for (list = iface_list; list; list = list->next) {
2643                 wifi = list->data;
2644
2645                 if (wifi->network == NULL && wifi->disconnecting == true)
2646                         wifi->disconnecting = false;
2647
2648                 if (wifi->network == network)
2649                         goto found;
2650         }
2651
2652         /* wifi_data may be invalid because wifi is already disabled */
2653         return;
2654
2655 found:
2656 #else
2657         struct wifi_data *wifi = user_data;
2658 #endif
2659
2660         DBG("result %d supplicant interface %p wifi %p",
2661                         result, interface, wifi);
2662
2663         if (result == -ECONNABORTED) {
2664                 DBG("wifi interface no longer available");
2665                 return;
2666         }
2667
2668         if (wifi->network) {
2669                 connman_network_set_connected(wifi->network, false);
2670                 wifi->network = NULL;
2671         }
2672
2673         wifi->disconnecting = false;
2674         wifi->connected = false;
2675
2676         if (wifi->pending_network) {
2677                 network_connect(wifi->pending_network);
2678                 wifi->pending_network = NULL;
2679         }
2680
2681         start_autoscan(wifi->device);
2682 }
2683
2684 static int network_disconnect(struct connman_network *network)
2685 {
2686         struct connman_device *device = connman_network_get_device(network);
2687         struct wifi_data *wifi;
2688         int err;
2689 #if defined TIZEN_EXT
2690         struct connman_service *service;
2691 #endif
2692
2693         DBG("network %p", network);
2694
2695         wifi = connman_device_get_data(device);
2696         if (!wifi || !wifi->interface)
2697                 return -ENODEV;
2698
2699 #if defined TIZEN_EXT
2700         if (connman_network_get_associating(network) == true) {
2701                 connman_network_clear_associating(network);
2702                 connman_network_set_bool(network, "WiFi.UseWPS", false);
2703         } else {
2704                 service = connman_service_lookup_from_network(network);
2705
2706                 if (service != NULL &&
2707                         (__connman_service_is_connected_state(service,
2708                                         CONNMAN_IPCONFIG_TYPE_IPV4) == false &&
2709                         __connman_service_is_connected_state(service,
2710                                         CONNMAN_IPCONFIG_TYPE_IPV6) == false) &&
2711                         (connman_service_get_favorite(service) == false))
2712                                         __connman_service_set_passphrase(service, NULL);
2713         }
2714
2715         if (wifi->pending_network == network)
2716                 wifi->pending_network = NULL;
2717
2718         if (wifi->scan_pending_network == network)
2719                 wifi->scan_pending_network = NULL;
2720
2721 #endif
2722         connman_network_set_associating(network, false);
2723
2724         if (wifi->disconnecting)
2725                 return -EALREADY;
2726
2727         wifi->disconnecting = true;
2728
2729 #if defined TIZEN_EXT
2730         err = g_supplicant_interface_disconnect(wifi->interface,
2731                                                 disconnect_callback, network);
2732 #else
2733         err = g_supplicant_interface_disconnect(wifi->interface,
2734                                                 disconnect_callback, wifi);
2735 #endif
2736
2737         if (err < 0)
2738                 wifi->disconnecting = false;
2739
2740         return err;
2741 }
2742
2743 static struct connman_network_driver network_driver = {
2744         .name           = "wifi",
2745         .type           = CONNMAN_NETWORK_TYPE_WIFI,
2746         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
2747         .probe          = network_probe,
2748         .remove         = network_remove,
2749         .connect        = network_connect,
2750         .disconnect     = network_disconnect,
2751 };
2752
2753 static void interface_added(GSupplicantInterface *interface)
2754 {
2755         const char *ifname = g_supplicant_interface_get_ifname(interface);
2756         const char *driver = g_supplicant_interface_get_driver(interface);
2757         struct wifi_data *wifi;
2758
2759         wifi = g_supplicant_interface_get_data(interface);
2760         if (!wifi) {
2761                 wifi = get_pending_wifi_data(ifname);
2762                 if (!wifi)
2763                         return;
2764
2765                 wifi->interface = interface;
2766                 g_supplicant_interface_set_data(interface, wifi);
2767                 p2p_iface_list = g_list_append(p2p_iface_list, wifi);
2768                 wifi->p2p_device = true;
2769         }
2770
2771         DBG("ifname %s driver %s wifi %p tethering %d",
2772                         ifname, driver, wifi, wifi->tethering);
2773
2774         if (!wifi->device) {
2775                 connman_error("WiFi device not set");
2776                 return;
2777         }
2778
2779         connman_device_set_powered(wifi->device, true);
2780 }
2781
2782 static bool is_idle(struct wifi_data *wifi)
2783 {
2784         DBG("state %d", wifi->state);
2785
2786         switch (wifi->state) {
2787         case G_SUPPLICANT_STATE_UNKNOWN:
2788         case G_SUPPLICANT_STATE_DISABLED:
2789         case G_SUPPLICANT_STATE_DISCONNECTED:
2790         case G_SUPPLICANT_STATE_INACTIVE:
2791         case G_SUPPLICANT_STATE_SCANNING:
2792                 return true;
2793
2794         case G_SUPPLICANT_STATE_AUTHENTICATING:
2795         case G_SUPPLICANT_STATE_ASSOCIATING:
2796         case G_SUPPLICANT_STATE_ASSOCIATED:
2797         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2798         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2799         case G_SUPPLICANT_STATE_COMPLETED:
2800                 return false;
2801         }
2802
2803         return false;
2804 }
2805
2806 static bool is_idle_wps(GSupplicantInterface *interface,
2807                                                 struct wifi_data *wifi)
2808 {
2809         /* First, let's check if WPS processing did not went wrong */
2810         if (g_supplicant_interface_get_wps_state(interface) ==
2811                 G_SUPPLICANT_WPS_STATE_FAIL)
2812                 return false;
2813
2814         /* Unlike normal connection, being associated while processing wps
2815          * actually means that we are idling. */
2816         switch (wifi->state) {
2817         case G_SUPPLICANT_STATE_UNKNOWN:
2818         case G_SUPPLICANT_STATE_DISABLED:
2819         case G_SUPPLICANT_STATE_DISCONNECTED:
2820         case G_SUPPLICANT_STATE_INACTIVE:
2821         case G_SUPPLICANT_STATE_SCANNING:
2822         case G_SUPPLICANT_STATE_ASSOCIATED:
2823                 return true;
2824         case G_SUPPLICANT_STATE_AUTHENTICATING:
2825         case G_SUPPLICANT_STATE_ASSOCIATING:
2826         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2827         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2828         case G_SUPPLICANT_STATE_COMPLETED:
2829                 return false;
2830         }
2831
2832         return false;
2833 }
2834
2835 static bool handle_wps_completion(GSupplicantInterface *interface,
2836                                         struct connman_network *network,
2837                                         struct connman_device *device,
2838                                         struct wifi_data *wifi)
2839 {
2840         bool wps;
2841
2842         wps = connman_network_get_bool(network, "WiFi.UseWPS");
2843         if (wps) {
2844                 const unsigned char *ssid, *wps_ssid;
2845                 unsigned int ssid_len, wps_ssid_len;
2846                 const char *wps_key;
2847
2848                 /* Checking if we got associated with requested
2849                  * network */
2850                 ssid = connman_network_get_blob(network, "WiFi.SSID",
2851                                                 &ssid_len);
2852
2853                 wps_ssid = g_supplicant_interface_get_wps_ssid(
2854                         interface, &wps_ssid_len);
2855
2856                 if (!wps_ssid || wps_ssid_len != ssid_len ||
2857                                 memcmp(ssid, wps_ssid, ssid_len) != 0) {
2858                         connman_network_set_associating(network, false);
2859 #if defined TIZEN_EXT
2860                         g_supplicant_interface_disconnect(wifi->interface,
2861                                                 disconnect_callback, wifi->network);
2862
2863                         connman_network_set_bool(network, "WiFi.UseWPS", false);
2864                         connman_network_set_string(network, "WiFi.PinWPS", NULL);
2865 #else
2866                         g_supplicant_interface_disconnect(wifi->interface,
2867                                                 disconnect_callback, wifi);
2868 #endif
2869                         return false;
2870                 }
2871
2872                 wps_key = g_supplicant_interface_get_wps_key(interface);
2873 #if defined TIZEN_EXT
2874                 /* Check the passphrase and encrypt it
2875                  */
2876                  int ret;
2877                  gchar *passphrase = g_strdup(wps_key);
2878
2879                  connman_network_set_string(network, "WiFi.PinWPS", NULL);
2880
2881                  if (check_passphrase_ext(network, passphrase) < 0) {
2882                          DBG("[WPS] Invalid passphrase");
2883                          g_free(passphrase);
2884                          return true;
2885                  }
2886
2887                  ret = send_encryption_request(passphrase, network);
2888
2889                  g_free(passphrase);
2890
2891                  if (!ret)
2892                          DBG("[WPS] Encryption request succeeded");
2893                  else
2894                          DBG("[WPS] Encryption request failed %d", ret);
2895
2896 #else
2897                 connman_network_set_string(network, "WiFi.Passphrase",
2898                                         wps_key);
2899
2900                 connman_network_set_string(network, "WiFi.PinWPS", NULL);
2901 #endif
2902         }
2903
2904         return true;
2905 }
2906
2907 static bool handle_assoc_status_code(GSupplicantInterface *interface,
2908                                      struct wifi_data *wifi)
2909 {
2910         if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING &&
2911                         wifi->assoc_code == ASSOC_STATUS_NO_CLIENT &&
2912                         wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) {
2913                 wifi->load_shaping_retries ++;
2914                 return TRUE;
2915         }
2916         wifi->load_shaping_retries = 0;
2917         return FALSE;
2918 }
2919
2920 static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
2921                                         struct connman_network *network,
2922                                         struct wifi_data *wifi)
2923 {
2924 #if defined TIZEN_EXT
2925         const char *security;
2926         struct connman_service *service;
2927
2928         if (wifi->connected)
2929                 return false;
2930
2931         security = connman_network_get_string(network, "WiFi.Security");
2932
2933         if (security && g_str_equal(security, "ieee8021x") == true &&
2934                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
2935                 wifi->retries = 0;
2936                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
2937
2938                 return false;
2939         }
2940
2941         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
2942                 return false;
2943 #else
2944         struct connman_service *service;
2945
2946         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
2947                 return false;
2948
2949         if (wifi->connected)
2950                 return false;
2951 #endif
2952
2953         service = connman_service_lookup_from_network(network);
2954         if (!service)
2955                 return false;
2956
2957         wifi->retries++;
2958
2959         if (connman_service_get_favorite(service)) {
2960                 if (wifi->retries < FAVORITE_MAXIMUM_RETRIES)
2961                         return true;
2962         }
2963
2964         wifi->retries = 0;
2965         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
2966
2967         return false;
2968 }
2969
2970 #if defined TIZEN_EXT
2971 static bool handle_wifi_assoc_retry(struct connman_network *network,
2972                                         struct wifi_data *wifi)
2973 {
2974         const char *security;
2975
2976         if (!wifi->network || wifi->connected || wifi->disconnecting ||
2977                         connman_network_get_connecting(network) != true) {
2978                 wifi->assoc_retry_count = 0;
2979                 return false;
2980         }
2981
2982         if (wifi->state != G_SUPPLICANT_STATE_ASSOCIATING &&
2983                         wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) {
2984                 wifi->assoc_retry_count = 0;
2985                 return false;
2986         }
2987
2988         security = connman_network_get_string(network, "WiFi.Security");
2989         if (security && g_str_equal(security, "ieee8021x") == true &&
2990                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
2991                 wifi->assoc_retry_count = 0;
2992                 return false;
2993         }
2994
2995         if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) {
2996                 wifi->assoc_retry_count = 0;
2997
2998                 /* Honestly it's not an invalid-key error,
2999                  * however QA team recommends that the invalid-key error
3000                  * might be better to display for user experience.
3001                  */
3002                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
3003
3004                 return false;
3005         }
3006
3007         return true;
3008 }
3009 #endif
3010
3011 static void interface_state(GSupplicantInterface *interface)
3012 {
3013         struct connman_network *network;
3014         struct connman_device *device;
3015         struct wifi_data *wifi;
3016         GSupplicantState state = g_supplicant_interface_get_state(interface);
3017         bool wps;
3018         bool old_connected;
3019
3020         wifi = g_supplicant_interface_get_data(interface);
3021
3022         DBG("wifi %p interface state %d", wifi, state);
3023
3024         if (!wifi)
3025                 return;
3026
3027         if (state == G_SUPPLICANT_STATE_COMPLETED) {
3028                 if (wifi->tethering_param) {
3029                         g_free(wifi->tethering_param->ssid);
3030                         g_free(wifi->tethering_param);
3031                         wifi->tethering_param = NULL;
3032                 }
3033         }
3034
3035         device = wifi->device;
3036         if (!device)
3037                 return;
3038
3039         if (g_supplicant_interface_get_ready(interface) &&
3040                                         !wifi->interface_ready) {
3041                 wifi->interface_ready = true;
3042                 finalize_interface_creation(wifi);
3043         }
3044
3045         network = wifi->network;
3046         if (!network)
3047                 return;
3048
3049         switch (state) {
3050         case G_SUPPLICANT_STATE_SCANNING:
3051                 if (wifi->connected)
3052                         connman_network_set_connected(network, false);
3053
3054                 break;
3055
3056         case G_SUPPLICANT_STATE_AUTHENTICATING:
3057         case G_SUPPLICANT_STATE_ASSOCIATING:
3058 #if defined TIZEN_EXT
3059                 reset_autoscan(device);
3060 #else
3061                 stop_autoscan(device);
3062 #endif
3063
3064                 if (!wifi->connected)
3065                         connman_network_set_associating(network, true);
3066
3067                 break;
3068
3069         case G_SUPPLICANT_STATE_COMPLETED:
3070 #if defined TIZEN_EXT
3071                 /* though it should be already reset: */
3072                 reset_autoscan(device);
3073
3074                 wifi->assoc_retry_count = 0;
3075
3076                 wifi->scan_pending_network = NULL;
3077
3078                 /* should be cleared scanning flag */
3079                 bool scanning = connman_device_get_scanning(device);
3080                 if (scanning){
3081                         connman_device_set_scanning(device,
3082                                 CONNMAN_SERVICE_TYPE_WIFI, false);
3083                         connman_device_unref(device);
3084                 }
3085 #else
3086                 /* though it should be already stopped: */
3087                 stop_autoscan(device);
3088 #endif
3089
3090                 if (!handle_wps_completion(interface, network, device, wifi))
3091                         break;
3092
3093                 connman_network_set_connected(network, true);
3094
3095                 wifi->disconnect_code = 0;
3096                 wifi->assoc_code = 0;
3097                 wifi->load_shaping_retries = 0;
3098                 break;
3099
3100         case G_SUPPLICANT_STATE_DISCONNECTED:
3101                 /*
3102                  * If we're in one of the idle modes, we have
3103                  * not started association yet and thus setting
3104                  * those ones to FALSE could cancel an association
3105                  * in progress.
3106                  */
3107                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
3108                 if (wps)
3109                         if (is_idle_wps(interface, wifi))
3110                                 break;
3111
3112                 if (is_idle(wifi))
3113                         break;
3114
3115                 if (handle_assoc_status_code(interface, wifi))
3116                         break;
3117
3118                 /* If previous state was 4way-handshake, then
3119                  * it's either: psk was incorrect and thus we retry
3120                  * or if we reach the maximum retries we declare the
3121                  * psk as wrong */
3122                 if (handle_4way_handshake_failure(interface,
3123                                                 network, wifi))
3124                         break;
3125
3126                 /* See table 8-36 Reason codes in IEEE Std 802.11 */
3127                 switch (wifi->disconnect_code) {
3128                 case 1: /* Unspecified reason */
3129                         /* Let's assume it's because we got blocked */
3130
3131                 case 6: /* Class 2 frame received from nonauthenticated STA */
3132                         connman_network_set_error(network,
3133                                                 CONNMAN_NETWORK_ERROR_BLOCKED);
3134                         break;
3135
3136                 default:
3137                         break;
3138                 }
3139
3140 #if defined TIZEN_EXT
3141                 /* Some of Wi-Fi networks are not comply Wi-Fi specification.
3142                  * Retry association until its retry count is expired */
3143                 if (handle_wifi_assoc_retry(network, wifi) == true) {
3144                         throw_wifi_scan(wifi->device, scan_callback);
3145                         wifi->scan_pending_network = wifi->network;
3146                         break;
3147                 }
3148
3149                 if(wifi->disconnect_code > 0){
3150                         DBG("Set disconnect reason code(%d)", wifi->disconnect_code);
3151                         connman_network_set_disconnect_reason(network, wifi->disconnect_code);
3152                 }
3153 #endif
3154
3155                 connman_network_set_connected(network, false);
3156                 connman_network_set_associating(network, false);
3157                 wifi->disconnecting = false;
3158
3159                 start_autoscan(device);
3160
3161                 break;
3162
3163         case G_SUPPLICANT_STATE_INACTIVE:
3164 #if defined TIZEN_EXT
3165                 if (handle_wps_completion(interface, network, device, wifi) == false)
3166                         break;
3167 #endif
3168                 connman_network_set_associating(network, false);
3169                 start_autoscan(device);
3170
3171                 break;
3172
3173         case G_SUPPLICANT_STATE_UNKNOWN:
3174         case G_SUPPLICANT_STATE_DISABLED:
3175         case G_SUPPLICANT_STATE_ASSOCIATED:
3176         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3177         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3178                 break;
3179         }
3180
3181         old_connected = wifi->connected;
3182         wifi->state = state;
3183
3184         /* Saving wpa_s state policy:
3185          * If connected and if the state changes are roaming related:
3186          * --> We stay connected
3187          * If completed
3188          * --> We are connected
3189          * All other case:
3190          * --> We are not connected
3191          * */
3192         switch (state) {
3193         case G_SUPPLICANT_STATE_AUTHENTICATING:
3194         case G_SUPPLICANT_STATE_ASSOCIATING:
3195         case G_SUPPLICANT_STATE_ASSOCIATED:
3196         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3197         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3198                 if (wifi->connected)
3199                         connman_warn("Probably roaming right now!"
3200                                                 " Staying connected...");
3201                 break;
3202         case G_SUPPLICANT_STATE_SCANNING:
3203                 wifi->connected = false;
3204
3205                 if (old_connected)
3206                         start_autoscan(device);
3207                 break;
3208         case G_SUPPLICANT_STATE_COMPLETED:
3209                 wifi->connected = true;
3210                 break;
3211         default:
3212                 wifi->connected = false;
3213                 break;
3214         }
3215
3216         DBG("DONE");
3217 }
3218
3219 static void interface_removed(GSupplicantInterface *interface)
3220 {
3221         const char *ifname = g_supplicant_interface_get_ifname(interface);
3222         struct wifi_data *wifi;
3223
3224         DBG("ifname %s", ifname);
3225
3226         wifi = g_supplicant_interface_get_data(interface);
3227
3228         if (wifi)
3229                 wifi->interface = NULL;
3230
3231         if (wifi && wifi->tethering)
3232                 return;
3233
3234         if (!wifi || !wifi->device) {
3235                 DBG("wifi interface already removed");
3236                 return;
3237         }
3238
3239         connman_device_set_powered(wifi->device, false);
3240
3241         check_p2p_technology();
3242 }
3243
3244 static void set_device_type(const char *type, char dev_type[17])
3245 {
3246         const char *oui = "0050F204";
3247         const char *category = "0001";
3248         const char *sub_category = "0000";
3249
3250         if (!g_strcmp0(type, "handset")) {
3251                 category = "000A";
3252                 sub_category = "0005";
3253         } else if (!g_strcmp0(type, "vm") || !g_strcmp0(type, "container"))
3254                 sub_category = "0001";
3255         else if (!g_strcmp0(type, "server"))
3256                 sub_category = "0002";
3257         else if (!g_strcmp0(type, "laptop"))
3258                 sub_category = "0005";
3259         else if (!g_strcmp0(type, "desktop"))
3260                 sub_category = "0006";
3261         else if (!g_strcmp0(type, "tablet"))
3262                 sub_category = "0009";
3263         else if (!g_strcmp0(type, "watch"))
3264                 category = "00FF";
3265
3266         snprintf(dev_type, 17, "%s%s%s", category, oui, sub_category);
3267 }
3268
3269 static void p2p_support(GSupplicantInterface *interface)
3270 {
3271         char dev_type[17] = {};
3272         const char *hostname;
3273
3274         DBG("");
3275
3276         if (!interface)
3277                 return;
3278
3279         if (!g_supplicant_interface_has_p2p(interface))
3280                 return;
3281
3282         if (connman_technology_driver_register(&p2p_tech_driver) < 0) {
3283                 DBG("Could not register P2P technology driver");
3284                 return;
3285         }
3286
3287         hostname = connman_utsname_get_hostname();
3288         if (!hostname)
3289                 hostname = "ConnMan";
3290
3291         set_device_type(connman_machine_get_type(), dev_type);
3292         g_supplicant_interface_set_p2p_device_config(interface,
3293                                                         hostname, dev_type);
3294         connman_peer_driver_register(&peer_driver);
3295 }
3296
3297 static void scan_started(GSupplicantInterface *interface)
3298 {
3299         DBG("");
3300 }
3301
3302 static void scan_finished(GSupplicantInterface *interface)
3303 {
3304 #if defined TIZEN_EXT
3305         struct wifi_data *wifi;
3306         bool is_associating = false;
3307         static bool is_scanning = true;
3308 #endif
3309
3310         DBG("");
3311
3312 #if defined TIZEN_EXT
3313         wifi = g_supplicant_interface_get_data(interface);
3314         if (wifi && wifi->scan_pending_network) {
3315                 network_connect(wifi->scan_pending_network);
3316                 wifi->scan_pending_network = NULL;
3317         }
3318
3319         //service state - associating
3320         if(!wifi || !wifi->network)
3321                 return;
3322
3323         is_associating = connman_network_get_associating(wifi->network);
3324         if(is_associating && is_scanning){
3325                 is_scanning = false;
3326                 DBG("send scan for connecting");
3327                 throw_wifi_scan(wifi->device, scan_callback);
3328
3329                 return;
3330         }
3331         is_scanning = true;
3332
3333         //go scan
3334
3335 #endif
3336 }
3337
3338 static void ap_create_fail(GSupplicantInterface *interface)
3339 {
3340         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
3341         int ret;
3342
3343         if ((wifi->tethering) && (wifi->tethering_param)) {
3344                 DBG("%s create AP fail \n",
3345                                 g_supplicant_interface_get_ifname(wifi->interface));
3346
3347                 connman_inet_remove_from_bridge(wifi->index, wifi->bridge);
3348                 wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
3349                 wifi->tethering = false;
3350
3351                 ret = tech_set_tethering(wifi->tethering_param->technology,
3352                                 wifi->tethering_param->ssid->ssid,
3353                                 wifi->tethering_param->ssid->passphrase,
3354                                 wifi->bridge, true);
3355
3356                 if ((ret == -EOPNOTSUPP) && (wifi_technology)) {
3357                         connman_technology_tethering_notify(wifi_technology,false);
3358                 }
3359
3360                 g_free(wifi->tethering_param->ssid);
3361                 g_free(wifi->tethering_param);
3362                 wifi->tethering_param = NULL;
3363         }
3364
3365         return;
3366 }
3367
3368 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
3369 {
3370         unsigned char strength;
3371
3372         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
3373
3374 #if !defined TIZEN_EXT
3375         if (strength > 100)
3376                 strength = 100;
3377 #endif
3378         return strength;
3379 }
3380
3381 static void network_added(GSupplicantNetwork *supplicant_network)
3382 {
3383         struct connman_network *network;
3384         GSupplicantInterface *interface;
3385         struct wifi_data *wifi;
3386         const char *name, *identifier, *security, *group, *mode;
3387         const unsigned char *ssid;
3388         unsigned int ssid_len;
3389         bool wps;
3390         bool wps_pbc;
3391         bool wps_ready;
3392         bool wps_advertizing;
3393
3394 #if defined TIZEN_EXT
3395         GSList *vsie_list = NULL;
3396         const unsigned char *country_code;
3397 #endif
3398
3399         mode = g_supplicant_network_get_mode(supplicant_network);
3400         identifier = g_supplicant_network_get_identifier(supplicant_network);
3401
3402         DBG("%s", identifier);
3403
3404         if (!g_strcmp0(mode, "adhoc"))
3405                 return;
3406
3407         interface = g_supplicant_network_get_interface(supplicant_network);
3408         wifi = g_supplicant_interface_get_data(interface);
3409         name = g_supplicant_network_get_name(supplicant_network);
3410         security = g_supplicant_network_get_security(supplicant_network);
3411         group = g_supplicant_network_get_identifier(supplicant_network);
3412         wps = g_supplicant_network_get_wps(supplicant_network);
3413         wps_pbc = g_supplicant_network_is_wps_pbc(supplicant_network);
3414         wps_ready = g_supplicant_network_is_wps_active(supplicant_network);
3415         wps_advertizing = g_supplicant_network_is_wps_advertizing(
3416                                                         supplicant_network);
3417
3418         if (!wifi)
3419                 return;
3420
3421         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
3422
3423         network = connman_device_get_network(wifi->device, identifier);
3424
3425         if (!network) {
3426                 network = connman_network_create(identifier,
3427                                                 CONNMAN_NETWORK_TYPE_WIFI);
3428                 if (!network)
3429                         return;
3430
3431                 connman_network_set_index(network, wifi->index);
3432
3433                 if (connman_device_add_network(wifi->device, network) < 0) {
3434                         connman_network_unref(network);
3435                         return;
3436                 }
3437
3438                 wifi->networks = g_slist_prepend(wifi->networks, network);
3439         }
3440
3441         if (name && name[0] != '\0')
3442                 connman_network_set_name(network, name);
3443
3444         connman_network_set_blob(network, "WiFi.SSID",
3445                                                 ssid, ssid_len);
3446 #if defined TIZEN_EXT
3447         vsie_list = (GSList *)g_supplicant_network_get_wifi_vsie(supplicant_network);
3448         if (vsie_list)
3449                 connman_network_set_vsie_list(network, vsie_list);
3450         else
3451                 DBG("vsie_list is NULL");
3452         country_code = g_supplicant_network_get_countrycode(supplicant_network);
3453         connman_network_set_countrycode(network, country_code);
3454 #endif
3455         connman_network_set_string(network, "WiFi.Security", security);
3456         connman_network_set_strength(network,
3457                                 calculate_strength(supplicant_network));
3458         connman_network_set_bool(network, "WiFi.WPS", wps);
3459
3460         if (wps) {
3461                 /* Is AP advertizing for WPS association?
3462                  * If so, we decide to use WPS by default */
3463                 if (wps_ready && wps_pbc &&
3464                                                 wps_advertizing) {
3465 #if !defined TIZEN_EXT
3466                         connman_network_set_bool(network, "WiFi.UseWPS", true);
3467 #else
3468                         DBG("wps is activating by ap but ignore it.");
3469 #endif
3470                 }
3471         }
3472
3473         connman_network_set_frequency(network,
3474                         g_supplicant_network_get_frequency(supplicant_network));
3475 #if defined TIZEN_EXT
3476         connman_network_set_bssid(network,
3477                         g_supplicant_network_get_bssid(supplicant_network));
3478         connman_network_set_maxrate(network,
3479                         g_supplicant_network_get_maxrate(supplicant_network));
3480         connman_network_set_enc_mode(network,
3481                         g_supplicant_network_get_enc_mode(supplicant_network));
3482         connman_network_set_rsn_mode(network,
3483                         g_supplicant_network_get_rsn_mode(supplicant_network));
3484         connman_network_set_keymgmt(network,
3485                         g_supplicant_network_get_keymgmt(supplicant_network));
3486         connman_network_set_bool(network, "WiFi.HS20AP",
3487                         g_supplicant_network_is_hs20AP(supplicant_network));
3488         connman_network_set_bssid_list(network,
3489                         (GSList *)g_supplicant_network_get_bssid_list(supplicant_network));
3490 #endif
3491         connman_network_set_available(network, true);
3492         connman_network_set_string(network, "WiFi.Mode", mode);
3493
3494 #if defined TIZEN_EXT
3495         if (group)
3496 #else
3497         if (ssid)
3498 #endif
3499                 connman_network_set_group(network, group);
3500
3501 #if defined TIZEN_EXT
3502         if (wifi_first_scan == true)
3503                 found_with_first_scan = true;
3504 #endif
3505
3506         if (wifi->hidden && ssid) {
3507 #if defined TIZEN_EXT
3508                 if (network_security(wifi->hidden->security) ==
3509                         network_security(security) &&
3510 #else
3511                 if (!g_strcmp0(wifi->hidden->security, security) &&
3512 #endif
3513                                 wifi->hidden->ssid_len == ssid_len &&
3514                                 !memcmp(wifi->hidden->ssid, ssid, ssid_len)) {
3515                         connman_network_connect_hidden(network,
3516                                         wifi->hidden->identity,
3517                                         wifi->hidden->passphrase,
3518                                         wifi->hidden->user_data);
3519                         wifi->hidden->user_data = NULL;
3520                         hidden_free(wifi->hidden);
3521                         wifi->hidden = NULL;
3522                 }
3523         }
3524 }
3525
3526 static void network_removed(GSupplicantNetwork *network)
3527 {
3528         GSupplicantInterface *interface;
3529         struct wifi_data *wifi;
3530         const char *name, *identifier;
3531         struct connman_network *connman_network;
3532
3533         interface = g_supplicant_network_get_interface(network);
3534         wifi = g_supplicant_interface_get_data(interface);
3535         identifier = g_supplicant_network_get_identifier(network);
3536         name = g_supplicant_network_get_name(network);
3537
3538         DBG("name %s", name);
3539
3540         if (!wifi)
3541                 return;
3542
3543         connman_network = connman_device_get_network(wifi->device, identifier);
3544         if (!connman_network)
3545                 return;
3546
3547 #if defined TIZEN_EXT
3548         if (connman_network == wifi->scan_pending_network)
3549                 wifi->scan_pending_network = NULL;
3550
3551         if (connman_network == wifi->pending_network)
3552                 wifi->pending_network = NULL;
3553
3554         if(connman_network_get_connecting(connman_network) == true){
3555                 connman_network_set_connected(connman_network, false);
3556         }
3557 #endif
3558
3559         wifi->networks = g_slist_remove(wifi->networks, connman_network);
3560
3561         connman_device_remove_network(wifi->device, connman_network);
3562         connman_network_unref(connman_network);
3563 }
3564
3565 static void network_changed(GSupplicantNetwork *network, const char *property)
3566 {
3567         GSupplicantInterface *interface;
3568         struct wifi_data *wifi;
3569         const char *name, *identifier;
3570         struct connman_network *connman_network;
3571
3572 #if defined TIZEN_EXT
3573         const unsigned char *bssid;
3574         unsigned int maxrate;
3575         uint16_t frequency;
3576         bool wps;
3577         const unsigned char *country_code;
3578         GSList *bssid_list;
3579 #endif
3580
3581         interface = g_supplicant_network_get_interface(network);
3582         wifi = g_supplicant_interface_get_data(interface);
3583         identifier = g_supplicant_network_get_identifier(network);
3584         name = g_supplicant_network_get_name(network);
3585
3586         DBG("name %s", name);
3587
3588         if (!wifi)
3589                 return;
3590
3591         connman_network = connman_device_get_network(wifi->device, identifier);
3592         if (!connman_network)
3593                 return;
3594
3595         if (g_str_equal(property, "Signal")) {
3596                connman_network_set_strength(connman_network,
3597                                         calculate_strength(network));
3598                connman_network_update(connman_network);
3599         }
3600
3601 #if defined TIZEN_EXT
3602         bssid = g_supplicant_network_get_bssid(network);
3603         maxrate = g_supplicant_network_get_maxrate(network);
3604         frequency = g_supplicant_network_get_frequency(network);
3605         wps = g_supplicant_network_get_wps(network);
3606
3607         connman_network_set_bssid(connman_network, bssid);
3608         connman_network_set_maxrate(connman_network, maxrate);
3609         connman_network_set_frequency(connman_network, frequency);
3610         connman_network_set_bool(connman_network, "WiFi.WPS", wps);
3611         country_code = g_supplicant_network_get_countrycode(network);
3612         connman_network_set_countrycode(connman_network, country_code);
3613         bssid_list = (GSList *)g_supplicant_network_get_bssid_list(network);
3614         connman_network_set_bssid_list(connman_network, bssid_list);
3615 #endif
3616 }
3617
3618 static void network_associated(GSupplicantNetwork *network)
3619 {
3620         GSupplicantInterface *interface;
3621         struct wifi_data *wifi;
3622         struct connman_network *connman_network;
3623         const char *identifier;
3624
3625         DBG("");
3626
3627         interface = g_supplicant_network_get_interface(network);
3628         if (!interface)
3629                 return;
3630
3631         wifi = g_supplicant_interface_get_data(interface);
3632         if (!wifi)
3633                 return;
3634
3635         identifier = g_supplicant_network_get_identifier(network);
3636
3637         connman_network = connman_device_get_network(wifi->device, identifier);
3638         if (!connman_network)
3639                 return;
3640
3641         if (wifi->network) {
3642                 if (wifi->network == connman_network)
3643                         return;
3644
3645                 /*
3646                  * This should never happen, we got associated with
3647                  * a network different than the one we were expecting.
3648                  */
3649                 DBG("Associated to %p while expecting %p",
3650                                         connman_network, wifi->network);
3651
3652                 connman_network_set_associating(wifi->network, false);
3653         }
3654
3655         DBG("Reconnecting to previous network %p from wpa_s", connman_network);
3656
3657         wifi->network = connman_network_ref(connman_network);
3658         wifi->retries = 0;
3659
3660         /*
3661          * Interface state changes callback (interface_state) is always
3662          * called before network_associated callback thus we need to call
3663          * interface_state again in order to process the new state now that
3664          * we have the network properly set.
3665          */
3666         interface_state(interface);
3667 }
3668
3669 static void apply_peer_services(GSupplicantPeer *peer,
3670                                 struct connman_peer *connman_peer)
3671 {
3672         const unsigned char *data;
3673         int length;
3674
3675         DBG("");
3676
3677         connman_peer_reset_services(connman_peer);
3678
3679         data = g_supplicant_peer_get_widi_ies(peer, &length);
3680         if (data) {
3681                 connman_peer_add_service(connman_peer,
3682                         CONNMAN_PEER_SERVICE_WIFI_DISPLAY, data, length);
3683         }
3684 }
3685
3686 static void add_station(const char *mac)
3687 {
3688         connman_technology_tethering_add_station(CONNMAN_SERVICE_TYPE_WIFI,
3689                                                  mac);
3690 }
3691
3692 static void remove_station(const char *mac)
3693 {
3694         connman_technology_tethering_remove_station(mac);
3695 }
3696
3697 static void peer_found(GSupplicantPeer *peer)
3698 {
3699         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3700         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3701         struct connman_peer *connman_peer;
3702         const char *identifier, *name;
3703         int ret;
3704 #if defined TIZEN_EXT
3705         if (!wifi)
3706                 return;
3707 #endif
3708         identifier = g_supplicant_peer_get_identifier(peer);
3709         name = g_supplicant_peer_get_name(peer);
3710
3711         DBG("ident: %s", identifier);
3712
3713         connman_peer = connman_peer_get(wifi->device, identifier);
3714         if (connman_peer)
3715                 return;
3716
3717         connman_peer = connman_peer_create(identifier);
3718         connman_peer_set_name(connman_peer, name);
3719         connman_peer_set_device(connman_peer, wifi->device);
3720         apply_peer_services(peer, connman_peer);
3721
3722         ret = connman_peer_register(connman_peer);
3723         if (ret < 0 && ret != -EALREADY)
3724                 connman_peer_unref(connman_peer);
3725         else
3726                 wifi->peers = g_slist_prepend(wifi->peers, connman_peer);
3727 }
3728
3729 static void peer_lost(GSupplicantPeer *peer)
3730 {
3731         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3732         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3733         struct connman_peer *connman_peer;
3734         const char *identifier;
3735
3736         if (!wifi)
3737                 return;
3738
3739         identifier = g_supplicant_peer_get_identifier(peer);
3740
3741         DBG("ident: %s", identifier);
3742
3743         connman_peer = connman_peer_get(wifi->device, identifier);
3744         if (connman_peer) {
3745                 if (wifi->p2p_connecting &&
3746                                 wifi->pending_peer == connman_peer) {
3747                         peer_connect_timeout(wifi);
3748                 }
3749                 connman_peer_unregister(connman_peer);
3750                 connman_peer_unref(connman_peer);
3751         }
3752
3753         wifi->peers = g_slist_remove(wifi->peers, connman_peer);
3754 }
3755
3756 static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state)
3757 {
3758         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3759         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3760         enum connman_peer_state p_state = CONNMAN_PEER_STATE_UNKNOWN;
3761         struct connman_peer *connman_peer;
3762         const char *identifier;
3763
3764         identifier = g_supplicant_peer_get_identifier(peer);
3765
3766         DBG("ident: %s", identifier);
3767
3768         if (!wifi)
3769                 return;
3770
3771         connman_peer = connman_peer_get(wifi->device, identifier);
3772         if (!connman_peer)
3773                 return;
3774
3775         switch (state) {
3776         case G_SUPPLICANT_PEER_SERVICES_CHANGED:
3777                 apply_peer_services(peer, connman_peer);
3778                 connman_peer_services_changed(connman_peer);
3779                 return;
3780         case G_SUPPLICANT_PEER_GROUP_CHANGED:
3781                 if (!g_supplicant_peer_is_in_a_group(peer))
3782                         p_state = CONNMAN_PEER_STATE_IDLE;
3783                 else
3784                         p_state = CONNMAN_PEER_STATE_CONFIGURATION;
3785                 break;
3786         case G_SUPPLICANT_PEER_GROUP_STARTED:
3787                 break;
3788         case G_SUPPLICANT_PEER_GROUP_FINISHED:
3789                 p_state = CONNMAN_PEER_STATE_IDLE;
3790                 break;
3791         case G_SUPPLICANT_PEER_GROUP_JOINED:
3792                 connman_peer_set_iface_address(connman_peer,
3793                                 g_supplicant_peer_get_iface_address(peer));
3794                 break;
3795         case G_SUPPLICANT_PEER_GROUP_DISCONNECTED:
3796                 p_state = CONNMAN_PEER_STATE_IDLE;
3797                 break;
3798         case G_SUPPLICANT_PEER_GROUP_FAILED:
3799                 if (g_supplicant_peer_has_requested_connection(peer))
3800                         p_state = CONNMAN_PEER_STATE_IDLE;
3801                 else
3802                         p_state = CONNMAN_PEER_STATE_FAILURE;
3803                 break;
3804         }
3805
3806         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION ||
3807                                         p_state == CONNMAN_PEER_STATE_FAILURE) {
3808                 if (wifi->p2p_connecting
3809                                 && connman_peer == wifi->pending_peer)
3810                         peer_cancel_timeout(wifi);
3811                 else
3812                         p_state = CONNMAN_PEER_STATE_UNKNOWN;
3813         }
3814
3815         if (p_state == CONNMAN_PEER_STATE_UNKNOWN)
3816                 return;
3817
3818         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION) {
3819                 GSupplicantInterface *g_iface;
3820                 struct wifi_data *g_wifi;
3821
3822                 g_iface = g_supplicant_peer_get_group_interface(peer);
3823                 if (!g_iface)
3824                         return;
3825
3826                 g_wifi = g_supplicant_interface_get_data(g_iface);
3827                 if (!g_wifi)
3828                         return;
3829
3830                 connman_peer_set_as_master(connman_peer,
3831                                         !g_supplicant_peer_is_client(peer));
3832                 connman_peer_set_sub_device(connman_peer, g_wifi->device);
3833
3834                 /*
3835                  * If wpa_supplicant didn't create a dedicated p2p-group
3836                  * interface then mark this interface as p2p_device to avoid
3837                  * scan and auto-scan are launched on it while P2P is connected.
3838                  */
3839                 if (!g_list_find(p2p_iface_list, g_wifi))
3840                         wifi->p2p_device = true;
3841         }
3842
3843         connman_peer_set_state(connman_peer, p_state);
3844 }
3845
3846 static void peer_request(GSupplicantPeer *peer)
3847 {
3848         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3849         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3850         struct connman_peer *connman_peer;
3851         const char *identifier;
3852
3853 #if defined TIZEN_EXT
3854         if (!wifi)
3855                 return;
3856 #endif
3857
3858         identifier = g_supplicant_peer_get_identifier(peer);
3859
3860         DBG("ident: %s", identifier);
3861
3862         connman_peer = connman_peer_get(wifi->device, identifier);
3863         if (!connman_peer)
3864                 return;
3865
3866         connman_peer_request_connection(connman_peer);
3867 }
3868
3869 #if defined TIZEN_EXT
3870 static void system_power_off(void)
3871 {
3872         GList *list;
3873         struct wifi_data *wifi;
3874         struct connman_service *service;
3875         struct connman_ipconfig *ipconfig_ipv4;
3876
3877         if (connman_setting_get_bool("WiFiDHCPRelease") == true) {
3878                 for (list = iface_list; list; list = list->next) {
3879                         wifi = list->data;
3880
3881                         if (wifi->network != NULL) {
3882                                 service = connman_service_lookup_from_network(wifi->network);
3883                                 ipconfig_ipv4 = __connman_service_get_ip4config(service);
3884                                 __connman_dhcp_stop(ipconfig_ipv4);
3885                         }
3886                 }
3887         }
3888 }
3889
3890 static void network_merged(GSupplicantNetwork *network)
3891 {
3892         GSupplicantInterface *interface;
3893         GSupplicantState state;
3894         struct wifi_data *wifi;
3895         const char *identifier;
3896         struct connman_network *connman_network;
3897         bool ishs20AP = 0;
3898         char *temp = NULL;
3899
3900         interface = g_supplicant_network_get_interface(network);
3901         if (!interface)
3902                 return;
3903
3904         state = g_supplicant_interface_get_state(interface);
3905         if (state < G_SUPPLICANT_STATE_AUTHENTICATING)
3906                 return;
3907
3908         wifi = g_supplicant_interface_get_data(interface);
3909         if (!wifi)
3910                 return;
3911
3912         identifier = g_supplicant_network_get_identifier(network);
3913
3914         connman_network = connman_device_get_network(wifi->device, identifier);
3915         if (!connman_network)
3916                 return;
3917
3918         DBG("merged identifier %s", identifier);
3919
3920         if (wifi->connected == FALSE) {
3921                 switch (state) {
3922                 case G_SUPPLICANT_STATE_AUTHENTICATING:
3923                 case G_SUPPLICANT_STATE_ASSOCIATING:
3924                 case G_SUPPLICANT_STATE_ASSOCIATED:
3925                 case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3926                 case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3927                         connman_network_set_associating(connman_network, TRUE);
3928                         break;
3929                 case G_SUPPLICANT_STATE_COMPLETED:
3930                         connman_network_set_connected(connman_network, TRUE);
3931                         break;
3932                 default:
3933                         DBG("Not handled the state : %d", state);
3934                         break;
3935                 }
3936         }
3937
3938         ishs20AP = g_supplicant_network_is_hs20AP(network);
3939
3940         if (ishs20AP &&
3941                 g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) {
3942                 temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1);
3943                 connman_network_set_string(connman_network, "WiFi.EAP",
3944                                 temp);
3945                 connman_network_set_string(connman_network, "WiFi.Identity",
3946                                 g_supplicant_network_get_identity(network));
3947                 connman_network_set_string(connman_network, "WiFi.Phase2",
3948                                 g_supplicant_network_get_phase2(network));
3949
3950                 g_free(temp);
3951         }
3952
3953         wifi->network = connman_network;
3954 }
3955
3956 static void assoc_failed(void *user_data)
3957 {
3958         struct connman_network *network = user_data;
3959         connman_network_set_associating(network, false);
3960 }
3961 #endif
3962
3963 static void debug(const char *str)
3964 {
3965         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
3966                 connman_debug("%s", str);
3967 }
3968
3969 static void disconnect_reasoncode(GSupplicantInterface *interface,
3970                                 int reasoncode)
3971 {
3972         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
3973
3974         if (wifi != NULL) {
3975                 wifi->disconnect_code = reasoncode;
3976         }
3977 }
3978
3979 static void assoc_status_code(GSupplicantInterface *interface, int status_code)
3980 {
3981         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
3982
3983         if (wifi != NULL) {
3984                 wifi->assoc_code = status_code;
3985         }
3986 }
3987
3988 static const GSupplicantCallbacks callbacks = {
3989         .system_ready           = system_ready,
3990         .system_killed          = system_killed,
3991         .interface_added        = interface_added,
3992         .interface_state        = interface_state,
3993         .interface_removed      = interface_removed,
3994         .p2p_support            = p2p_support,
3995         .scan_started           = scan_started,
3996         .scan_finished          = scan_finished,
3997         .ap_create_fail         = ap_create_fail,
3998         .network_added          = network_added,
3999         .network_removed        = network_removed,
4000         .network_changed        = network_changed,
4001         .network_associated     = network_associated,
4002         .add_station            = add_station,
4003         .remove_station         = remove_station,
4004         .peer_found             = peer_found,
4005         .peer_lost              = peer_lost,
4006         .peer_changed           = peer_changed,
4007         .peer_request           = peer_request,
4008 #if defined TIZEN_EXT
4009         .system_power_off       = system_power_off,
4010         .network_merged = network_merged,
4011         .assoc_failed           = assoc_failed,
4012 #endif
4013         .debug                  = debug,
4014         .disconnect_reasoncode  = disconnect_reasoncode,
4015         .assoc_status_code      = assoc_status_code,
4016 };
4017
4018
4019 static int tech_probe(struct connman_technology *technology)
4020 {
4021         wifi_technology = technology;
4022
4023         return 0;
4024 }
4025
4026 static void tech_remove(struct connman_technology *technology)
4027 {
4028         wifi_technology = NULL;
4029 }
4030
4031 static GSupplicantSSID *ssid_ap_init(const char *ssid,
4032                 const char *passphrase)
4033 {
4034         GSupplicantSSID *ap;
4035
4036         ap = g_try_malloc0(sizeof(GSupplicantSSID));
4037         if (!ap)
4038                 return NULL;
4039
4040         ap->mode = G_SUPPLICANT_MODE_MASTER;
4041         ap->ssid = ssid;
4042         ap->ssid_len = strlen(ssid);
4043         ap->scan_ssid = 0;
4044         ap->freq = 2412;
4045
4046         if (!passphrase || strlen(passphrase) == 0) {
4047                 ap->security = G_SUPPLICANT_SECURITY_NONE;
4048                 ap->passphrase = NULL;
4049         } else {
4050                ap->security = G_SUPPLICANT_SECURITY_PSK;
4051                ap->protocol = G_SUPPLICANT_PROTO_RSN;
4052                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
4053                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
4054                ap->passphrase = passphrase;
4055         }
4056
4057         return ap;
4058 }
4059
4060 static void ap_start_callback(int result, GSupplicantInterface *interface,
4061                                                         void *user_data)
4062 {
4063         struct wifi_tethering_info *info = user_data;
4064
4065         DBG("result %d index %d bridge %s",
4066                 result, info->wifi->index, info->wifi->bridge);
4067
4068         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
4069                 connman_inet_remove_from_bridge(info->wifi->index,
4070                                                         info->wifi->bridge);
4071
4072                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
4073                         connman_technology_tethering_notify(info->technology, false);
4074                         g_free(info->wifi->tethering_param->ssid);
4075                         g_free(info->wifi->tethering_param);
4076                         info->wifi->tethering_param = NULL;
4077                 }
4078         }
4079
4080         g_free(info->ifname);
4081         g_free(info);
4082 }
4083
4084 static void ap_create_callback(int result,
4085                                 GSupplicantInterface *interface,
4086                                         void *user_data)
4087 {
4088         struct wifi_tethering_info *info = user_data;
4089
4090         DBG("result %d ifname %s", result,
4091                                 g_supplicant_interface_get_ifname(interface));
4092
4093         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
4094                 connman_inet_remove_from_bridge(info->wifi->index,
4095                                                         info->wifi->bridge);
4096
4097                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
4098                         connman_technology_tethering_notify(info->technology, false);
4099                         g_free(info->wifi->tethering_param->ssid);
4100                         g_free(info->wifi->tethering_param);
4101                         info->wifi->tethering_param = NULL;
4102
4103                 }
4104
4105                 g_free(info->ifname);
4106                 g_free(info->ssid);
4107                 g_free(info);
4108                 return;
4109         }
4110
4111         info->wifi->interface = interface;
4112         g_supplicant_interface_set_data(interface, info->wifi);
4113
4114         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
4115                 connman_error("Failed to set interface ap_scan property");
4116
4117         g_supplicant_interface_connect(interface, info->ssid,
4118                                                 ap_start_callback, info);
4119 }
4120
4121 static void sta_remove_callback(int result,
4122                                 GSupplicantInterface *interface,
4123                                         void *user_data)
4124 {
4125         struct wifi_tethering_info *info = user_data;
4126         const char *driver = connman_option_get_string("wifi");
4127
4128         DBG("ifname %s result %d ", info->ifname, result);
4129
4130         if (result < 0 || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
4131                 info->wifi->tethering = false;
4132                 connman_technology_tethering_notify(info->technology, false);
4133
4134                 g_free(info->ifname);
4135                 g_free(info->ssid);
4136                 g_free(info);
4137
4138                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
4139                         g_free(info->wifi->tethering_param->ssid);
4140                         g_free(info->wifi->tethering_param);
4141                         info->wifi->tethering_param = NULL;
4142                 }
4143                 return;
4144         }
4145
4146         info->wifi->interface = NULL;
4147
4148         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
4149                                                 ap_create_callback,
4150                                                         info);
4151 }
4152
4153 static int enable_wifi_tethering(struct connman_technology *technology,
4154                                 const char *bridge, const char *identifier,
4155                                 const char *passphrase, bool available)
4156 {
4157         GList *list;
4158         GSupplicantInterface *interface;
4159         struct wifi_data *wifi;
4160         struct wifi_tethering_info *info;
4161         const char *ifname;
4162         unsigned int mode;
4163         int err, berr = 0;
4164
4165         for (list = iface_list; list; list = list->next) {
4166                 wifi = list->data;
4167
4168                 DBG("wifi %p network %p pending_network %p", wifi,
4169                         wifi->network, wifi->pending_network);
4170
4171                 interface = wifi->interface;
4172
4173                 if (!interface)
4174                         continue;
4175
4176                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED)
4177                         continue;
4178
4179                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
4180
4181                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED) {
4182                         DBG("%s does not support AP mode (detected)", ifname);
4183                         continue;
4184                 }
4185
4186                 mode = g_supplicant_interface_get_mode(interface);
4187                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
4188                         wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
4189                         DBG("%s does not support AP mode (capability)", ifname);
4190                         continue;
4191                 }
4192
4193                 if (wifi->network && available)
4194                         continue;
4195
4196                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
4197                 if (!info)
4198                         return -ENOMEM;
4199
4200                 wifi->tethering_param = g_try_malloc0(sizeof(struct wifi_tethering_info));
4201                 if (!wifi->tethering_param) {
4202                         g_free(info);
4203                         return -ENOMEM;
4204                 }
4205
4206                 info->wifi = wifi;
4207                 info->technology = technology;
4208                 info->wifi->bridge = bridge;
4209                 info->ssid = ssid_ap_init(identifier, passphrase);
4210                 if (!info->ssid)
4211                         goto failed;
4212
4213                 info->ifname = g_strdup(ifname);
4214                 if (!info->ifname)
4215                         goto failed;
4216
4217                 wifi->tethering_param->technology = technology;
4218                 wifi->tethering_param->ssid = ssid_ap_init(identifier, passphrase);
4219                 if (!wifi->tethering_param->ssid)
4220                         goto failed;
4221
4222                 info->wifi->tethering = true;
4223                 info->wifi->ap_supported = WIFI_AP_SUPPORTED;
4224
4225                 berr = connman_technology_tethering_notify(technology, true);
4226                 if (berr < 0)
4227                         goto failed;
4228
4229                 err = g_supplicant_interface_remove(interface,
4230                                                 sta_remove_callback,
4231                                                         info);
4232                 if (err >= 0) {
4233                         DBG("tethering wifi %p ifname %s", wifi, ifname);
4234                         return 0;
4235                 }
4236
4237         failed:
4238                 g_free(info->ifname);
4239                 g_free(info->ssid);
4240                 g_free(info);
4241                 g_free(wifi->tethering_param);
4242                 wifi->tethering_param = NULL;
4243
4244                 /*
4245                  * Remove bridge if it was correctly created but remove
4246                  * operation failed. Instead, if bridge creation failed then
4247                  * break out and do not try again on another interface,
4248                  * bridge set-up does not depend on it.
4249                  */
4250                 if (berr == 0)
4251                         connman_technology_tethering_notify(technology, false);
4252                 else
4253                         break;
4254         }
4255
4256         return -EOPNOTSUPP;
4257 }
4258
4259 static int tech_set_tethering(struct connman_technology *technology,
4260                                 const char *identifier, const char *passphrase,
4261                                 const char *bridge, bool enabled)
4262 {
4263         GList *list;
4264         struct wifi_data *wifi;
4265         int err;
4266
4267         DBG("");
4268
4269         if (!enabled) {
4270                 for (list = iface_list; list; list = list->next) {
4271                         wifi = list->data;
4272
4273                         if (wifi->tethering) {
4274                                 wifi->tethering = false;
4275
4276                                 connman_inet_remove_from_bridge(wifi->index,
4277                                                                         bridge);
4278                                 wifi->bridged = false;
4279                         }
4280                 }
4281
4282                 connman_technology_tethering_notify(technology, false);
4283
4284                 return 0;
4285         }
4286
4287         DBG("trying tethering for available devices");
4288         err = enable_wifi_tethering(technology, bridge, identifier, passphrase,
4289                                 true);
4290
4291         if (err < 0) {
4292                 DBG("trying tethering for any device");
4293                 err = enable_wifi_tethering(technology, bridge, identifier,
4294                                         passphrase, false);
4295         }
4296
4297         return err;
4298 }
4299
4300 static void regdom_callback(int result, const char *alpha2, void *user_data)
4301 {
4302         DBG("");
4303
4304         if (!wifi_technology)
4305                 return;
4306
4307         if (result != 0)
4308                 alpha2 = NULL;
4309
4310         connman_technology_regdom_notify(wifi_technology, alpha2);
4311 }
4312
4313 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
4314 {
4315         return g_supplicant_set_country(alpha2, regdom_callback, NULL);
4316 }
4317
4318 static struct connman_technology_driver tech_driver = {
4319         .name           = "wifi",
4320         .type           = CONNMAN_SERVICE_TYPE_WIFI,
4321         .probe          = tech_probe,
4322         .remove         = tech_remove,
4323         .set_tethering  = tech_set_tethering,
4324         .set_regdom     = tech_set_regdom,
4325 };
4326
4327 static int wifi_init(void)
4328 {
4329         int err;
4330
4331         err = connman_network_driver_register(&network_driver);
4332         if (err < 0)
4333                 return err;
4334
4335         err = g_supplicant_register(&callbacks);
4336         if (err < 0) {
4337                 connman_network_driver_unregister(&network_driver);
4338                 return err;
4339         }
4340
4341         err = connman_technology_driver_register(&tech_driver);
4342         if (err < 0) {
4343                 g_supplicant_unregister(&callbacks);
4344                 connman_network_driver_unregister(&network_driver);
4345                 return err;
4346         }
4347
4348         return 0;
4349 }
4350
4351 static void wifi_exit(void)
4352 {
4353         DBG();
4354
4355         connman_technology_driver_unregister(&tech_driver);
4356
4357         g_supplicant_unregister(&callbacks);
4358
4359         connman_network_driver_unregister(&network_driver);
4360 }
4361
4362 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
4363                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)