gsupplicant: Fixed invalid read issue
[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 #if defined TIZEN_EXT
2513         const void *ssid_data;
2514 #endif
2515
2516         memset(ssid, 0, sizeof(*ssid));
2517         ssid->mode = G_SUPPLICANT_MODE_INFRA;
2518 #if defined TIZEN_EXT
2519         ssid_data = connman_network_get_blob(network, "WiFi.SSID",
2520                                                 &ssid->ssid_len);
2521         ssid->ssid = g_try_malloc0(ssid->ssid_len);
2522         memcpy(ssid->ssid, ssid_data, ssid->ssid_len);
2523 #else
2524         ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
2525                                                 &ssid->ssid_len);
2526 #endif
2527         ssid->scan_ssid = 1;
2528         security = connman_network_get_string(network, "WiFi.Security");
2529         ssid->security = network_security(security);
2530         ssid->passphrase = connman_network_get_string(network,
2531                                                 "WiFi.Passphrase");
2532         ssid->eap = connman_network_get_string(network, "WiFi.EAP");
2533
2534         /*
2535          * If our private key password is unset,
2536          * we use the supplied passphrase. That is needed
2537          * for PEAP where 2 passphrases (identity and client
2538          * cert may have to be provided.
2539          */
2540         if (!connman_network_get_string(network, "WiFi.PrivateKeyPassphrase"))
2541                 connman_network_set_string(network,
2542                                                 "WiFi.PrivateKeyPassphrase",
2543                                                 ssid->passphrase);
2544         /* We must have an identity for both PEAP and TLS */
2545         ssid->identity = connman_network_get_string(network, "WiFi.Identity");
2546
2547         /* Use agent provided identity as a fallback */
2548         if (!ssid->identity || strlen(ssid->identity) == 0)
2549                 ssid->identity = connman_network_get_string(network,
2550                                                         "WiFi.AgentIdentity");
2551
2552         ssid->anonymous_identity = connman_network_get_string(network,
2553                                                 "WiFi.AnonymousIdentity");
2554         ssid->ca_cert_path = connman_network_get_string(network,
2555                                                         "WiFi.CACertFile");
2556         ssid->subject_match = connman_network_get_string(network,
2557                                                         "WiFi.SubjectMatch");
2558         ssid->altsubject_match = connman_network_get_string(network,
2559                                                         "WiFi.AltSubjectMatch");
2560         ssid->domain_suffix_match = connman_network_get_string(network,
2561                                                         "WiFi.DomainSuffixMatch");
2562         ssid->domain_match = connman_network_get_string(network,
2563                                                         "WiFi.DomainMatch");
2564         ssid->client_cert_path = connman_network_get_string(network,
2565                                                         "WiFi.ClientCertFile");
2566         ssid->private_key_path = connman_network_get_string(network,
2567                                                         "WiFi.PrivateKeyFile");
2568         ssid->private_key_passphrase = connman_network_get_string(network,
2569                                                 "WiFi.PrivateKeyPassphrase");
2570         ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
2571
2572         ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS");
2573         ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS");
2574
2575 #if defined TIZEN_EXT
2576         ssid->bssid = connman_network_get_bssid(network);
2577
2578         ssid->eap_keymgmt = network_eap_keymgmt(
2579                         connman_network_get_string(network, "WiFi.KeymgmtType"));
2580         ssid->phase1 = connman_network_get_string(network, "WiFi.Phase1");
2581
2582         if(g_strcmp0(ssid->eap, "fast") == 0)
2583                 ssid->pac_file = g_strdup(WIFI_EAP_FAST_PAC_FILE);
2584
2585         if (set_connman_bssid(CHECK_BSSID, NULL) == 6) {
2586                 ssid->bssid_for_connect_len = 6;
2587                 set_connman_bssid(GET_BSSID, (char *)ssid->bssid_for_connect);
2588                 DBG("BSSID : %02x:%02x:%02x:%02x:%02x:%02x",
2589                         ssid->bssid_for_connect[0], ssid->bssid_for_connect[1],
2590                         ssid->bssid_for_connect[2], ssid->bssid_for_connect[3],
2591                         ssid->bssid_for_connect[4], ssid->bssid_for_connect[5]);
2592         } else {
2593                 ssid->freq = connman_network_get_frequency(network);
2594         }
2595 #endif
2596
2597         if (connman_setting_get_bool("BackgroundScanning"))
2598                 ssid->bgscan = BGSCAN_DEFAULT;
2599 }
2600
2601 static int network_connect(struct connman_network *network)
2602 {
2603         struct connman_device *device = connman_network_get_device(network);
2604         struct wifi_data *wifi;
2605         GSupplicantInterface *interface;
2606         GSupplicantSSID *ssid;
2607
2608         DBG("network %p", network);
2609
2610         if (!device)
2611                 return -ENODEV;
2612
2613         wifi = connman_device_get_data(device);
2614         if (!wifi)
2615                 return -ENODEV;
2616
2617         ssid = g_try_malloc0(sizeof(GSupplicantSSID));
2618         if (!ssid)
2619                 return -ENOMEM;
2620
2621         interface = wifi->interface;
2622
2623         ssid_init(ssid, network);
2624
2625         if (wifi->disconnecting) {
2626                 wifi->pending_network = network;
2627 #if defined TIZEN_EXT
2628                 g_free(ssid->ssid);
2629 #endif
2630                 g_free(ssid);
2631         } else {
2632                 wifi->network = connman_network_ref(network);
2633                 wifi->retries = 0;
2634 #if defined TIZEN_EXT
2635                 wifi->scan_pending_network = NULL;
2636 #endif
2637
2638                 return g_supplicant_interface_connect(interface, ssid,
2639                                                 connect_callback, network);
2640         }
2641
2642         return -EINPROGRESS;
2643 }
2644
2645 static void disconnect_callback(int result, GSupplicantInterface *interface,
2646                                                                 void *user_data)
2647 {
2648 #if defined TIZEN_EXT
2649         GList *list;
2650         struct wifi_data *wifi;
2651         struct connman_network *network = user_data;
2652
2653         DBG("network %p result %d", network, result);
2654
2655         for (list = iface_list; list; list = list->next) {
2656                 wifi = list->data;
2657
2658                 if (wifi->network == NULL && wifi->disconnecting == true)
2659                         wifi->disconnecting = false;
2660
2661                 if (wifi->network == network)
2662                         goto found;
2663         }
2664
2665         /* wifi_data may be invalid because wifi is already disabled */
2666         return;
2667
2668 found:
2669 #else
2670         struct wifi_data *wifi = user_data;
2671 #endif
2672
2673         DBG("result %d supplicant interface %p wifi %p",
2674                         result, interface, wifi);
2675
2676         if (result == -ECONNABORTED) {
2677                 DBG("wifi interface no longer available");
2678                 return;
2679         }
2680
2681         if (wifi->network) {
2682                 connman_network_set_connected(wifi->network, false);
2683                 wifi->network = NULL;
2684         }
2685
2686         wifi->disconnecting = false;
2687         wifi->connected = false;
2688
2689         if (wifi->pending_network) {
2690                 network_connect(wifi->pending_network);
2691                 wifi->pending_network = NULL;
2692         }
2693
2694         start_autoscan(wifi->device);
2695 }
2696
2697 static int network_disconnect(struct connman_network *network)
2698 {
2699         struct connman_device *device = connman_network_get_device(network);
2700         struct wifi_data *wifi;
2701         int err;
2702 #if defined TIZEN_EXT
2703         struct connman_service *service;
2704 #endif
2705
2706         DBG("network %p", network);
2707
2708         wifi = connman_device_get_data(device);
2709         if (!wifi || !wifi->interface)
2710                 return -ENODEV;
2711
2712 #if defined TIZEN_EXT
2713         if (connman_network_get_associating(network) == true) {
2714                 connman_network_clear_associating(network);
2715                 connman_network_set_bool(network, "WiFi.UseWPS", false);
2716         } else {
2717                 service = connman_service_lookup_from_network(network);
2718
2719                 if (service != NULL &&
2720                         (__connman_service_is_connected_state(service,
2721                                         CONNMAN_IPCONFIG_TYPE_IPV4) == false &&
2722                         __connman_service_is_connected_state(service,
2723                                         CONNMAN_IPCONFIG_TYPE_IPV6) == false) &&
2724                         (connman_service_get_favorite(service) == false))
2725                                         __connman_service_set_passphrase(service, NULL);
2726         }
2727
2728         if (wifi->pending_network == network)
2729                 wifi->pending_network = NULL;
2730
2731         if (wifi->scan_pending_network == network)
2732                 wifi->scan_pending_network = NULL;
2733
2734 #endif
2735         connman_network_set_associating(network, false);
2736
2737         if (wifi->disconnecting)
2738                 return -EALREADY;
2739
2740         wifi->disconnecting = true;
2741
2742 #if defined TIZEN_EXT
2743         err = g_supplicant_interface_disconnect(wifi->interface,
2744                                                 disconnect_callback, network);
2745 #else
2746         err = g_supplicant_interface_disconnect(wifi->interface,
2747                                                 disconnect_callback, wifi);
2748 #endif
2749
2750         if (err < 0)
2751                 wifi->disconnecting = false;
2752
2753         return err;
2754 }
2755
2756 static struct connman_network_driver network_driver = {
2757         .name           = "wifi",
2758         .type           = CONNMAN_NETWORK_TYPE_WIFI,
2759         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
2760         .probe          = network_probe,
2761         .remove         = network_remove,
2762         .connect        = network_connect,
2763         .disconnect     = network_disconnect,
2764 };
2765
2766 static void interface_added(GSupplicantInterface *interface)
2767 {
2768         const char *ifname = g_supplicant_interface_get_ifname(interface);
2769         const char *driver = g_supplicant_interface_get_driver(interface);
2770         struct wifi_data *wifi;
2771
2772         wifi = g_supplicant_interface_get_data(interface);
2773         if (!wifi) {
2774                 wifi = get_pending_wifi_data(ifname);
2775                 if (!wifi)
2776                         return;
2777
2778                 wifi->interface = interface;
2779                 g_supplicant_interface_set_data(interface, wifi);
2780                 p2p_iface_list = g_list_append(p2p_iface_list, wifi);
2781                 wifi->p2p_device = true;
2782         }
2783
2784         DBG("ifname %s driver %s wifi %p tethering %d",
2785                         ifname, driver, wifi, wifi->tethering);
2786
2787         if (!wifi->device) {
2788                 connman_error("WiFi device not set");
2789                 return;
2790         }
2791
2792         connman_device_set_powered(wifi->device, true);
2793 }
2794
2795 static bool is_idle(struct wifi_data *wifi)
2796 {
2797         DBG("state %d", wifi->state);
2798
2799         switch (wifi->state) {
2800         case G_SUPPLICANT_STATE_UNKNOWN:
2801         case G_SUPPLICANT_STATE_DISABLED:
2802         case G_SUPPLICANT_STATE_DISCONNECTED:
2803         case G_SUPPLICANT_STATE_INACTIVE:
2804         case G_SUPPLICANT_STATE_SCANNING:
2805                 return true;
2806
2807         case G_SUPPLICANT_STATE_AUTHENTICATING:
2808         case G_SUPPLICANT_STATE_ASSOCIATING:
2809         case G_SUPPLICANT_STATE_ASSOCIATED:
2810         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2811         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2812         case G_SUPPLICANT_STATE_COMPLETED:
2813                 return false;
2814         }
2815
2816         return false;
2817 }
2818
2819 static bool is_idle_wps(GSupplicantInterface *interface,
2820                                                 struct wifi_data *wifi)
2821 {
2822         /* First, let's check if WPS processing did not went wrong */
2823         if (g_supplicant_interface_get_wps_state(interface) ==
2824                 G_SUPPLICANT_WPS_STATE_FAIL)
2825                 return false;
2826
2827         /* Unlike normal connection, being associated while processing wps
2828          * actually means that we are idling. */
2829         switch (wifi->state) {
2830         case G_SUPPLICANT_STATE_UNKNOWN:
2831         case G_SUPPLICANT_STATE_DISABLED:
2832         case G_SUPPLICANT_STATE_DISCONNECTED:
2833         case G_SUPPLICANT_STATE_INACTIVE:
2834         case G_SUPPLICANT_STATE_SCANNING:
2835         case G_SUPPLICANT_STATE_ASSOCIATED:
2836                 return true;
2837         case G_SUPPLICANT_STATE_AUTHENTICATING:
2838         case G_SUPPLICANT_STATE_ASSOCIATING:
2839         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2840         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2841         case G_SUPPLICANT_STATE_COMPLETED:
2842                 return false;
2843         }
2844
2845         return false;
2846 }
2847
2848 static bool handle_wps_completion(GSupplicantInterface *interface,
2849                                         struct connman_network *network,
2850                                         struct connman_device *device,
2851                                         struct wifi_data *wifi)
2852 {
2853         bool wps;
2854
2855         wps = connman_network_get_bool(network, "WiFi.UseWPS");
2856         if (wps) {
2857                 const unsigned char *ssid, *wps_ssid;
2858                 unsigned int ssid_len, wps_ssid_len;
2859                 const char *wps_key;
2860
2861                 /* Checking if we got associated with requested
2862                  * network */
2863                 ssid = connman_network_get_blob(network, "WiFi.SSID",
2864                                                 &ssid_len);
2865
2866                 wps_ssid = g_supplicant_interface_get_wps_ssid(
2867                         interface, &wps_ssid_len);
2868
2869                 if (!wps_ssid || wps_ssid_len != ssid_len ||
2870                                 memcmp(ssid, wps_ssid, ssid_len) != 0) {
2871                         connman_network_set_associating(network, false);
2872 #if defined TIZEN_EXT
2873                         g_supplicant_interface_disconnect(wifi->interface,
2874                                                 disconnect_callback, wifi->network);
2875
2876                         connman_network_set_bool(network, "WiFi.UseWPS", false);
2877                         connman_network_set_string(network, "WiFi.PinWPS", NULL);
2878 #else
2879                         g_supplicant_interface_disconnect(wifi->interface,
2880                                                 disconnect_callback, wifi);
2881 #endif
2882                         return false;
2883                 }
2884
2885                 wps_key = g_supplicant_interface_get_wps_key(interface);
2886 #if defined TIZEN_EXT
2887                 /* Check the passphrase and encrypt it
2888                  */
2889                  int ret;
2890                  gchar *passphrase = g_strdup(wps_key);
2891
2892                  connman_network_set_string(network, "WiFi.PinWPS", NULL);
2893
2894                  if (check_passphrase_ext(network, passphrase) < 0) {
2895                          DBG("[WPS] Invalid passphrase");
2896                          g_free(passphrase);
2897                          return true;
2898                  }
2899
2900                  ret = send_encryption_request(passphrase, network);
2901
2902                  g_free(passphrase);
2903
2904                  if (!ret)
2905                          DBG("[WPS] Encryption request succeeded");
2906                  else
2907                          DBG("[WPS] Encryption request failed %d", ret);
2908
2909 #else
2910                 connman_network_set_string(network, "WiFi.Passphrase",
2911                                         wps_key);
2912
2913                 connman_network_set_string(network, "WiFi.PinWPS", NULL);
2914 #endif
2915         }
2916
2917         return true;
2918 }
2919
2920 static bool handle_assoc_status_code(GSupplicantInterface *interface,
2921                                      struct wifi_data *wifi)
2922 {
2923         if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING &&
2924                         wifi->assoc_code == ASSOC_STATUS_NO_CLIENT &&
2925                         wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) {
2926                 wifi->load_shaping_retries ++;
2927                 return TRUE;
2928         }
2929         wifi->load_shaping_retries = 0;
2930         return FALSE;
2931 }
2932
2933 static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
2934                                         struct connman_network *network,
2935                                         struct wifi_data *wifi)
2936 {
2937 #if defined TIZEN_EXT
2938         const char *security;
2939         struct connman_service *service;
2940
2941         if (wifi->connected)
2942                 return false;
2943
2944         security = connman_network_get_string(network, "WiFi.Security");
2945
2946         if (security && g_str_equal(security, "ieee8021x") == true &&
2947                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
2948                 wifi->retries = 0;
2949                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
2950
2951                 return false;
2952         }
2953
2954         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
2955                 return false;
2956 #else
2957         struct connman_service *service;
2958
2959         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
2960                 return false;
2961
2962         if (wifi->connected)
2963                 return false;
2964 #endif
2965
2966         service = connman_service_lookup_from_network(network);
2967         if (!service)
2968                 return false;
2969
2970         wifi->retries++;
2971
2972         if (connman_service_get_favorite(service)) {
2973                 if (wifi->retries < FAVORITE_MAXIMUM_RETRIES)
2974                         return true;
2975         }
2976
2977         wifi->retries = 0;
2978         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
2979
2980         return false;
2981 }
2982
2983 #if defined TIZEN_EXT
2984 static bool handle_wifi_assoc_retry(struct connman_network *network,
2985                                         struct wifi_data *wifi)
2986 {
2987         const char *security;
2988
2989         if (!wifi->network || wifi->connected || wifi->disconnecting ||
2990                         connman_network_get_connecting(network) != true) {
2991                 wifi->assoc_retry_count = 0;
2992                 return false;
2993         }
2994
2995         if (wifi->state != G_SUPPLICANT_STATE_ASSOCIATING &&
2996                         wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) {
2997                 wifi->assoc_retry_count = 0;
2998                 return false;
2999         }
3000
3001         security = connman_network_get_string(network, "WiFi.Security");
3002         if (security && g_str_equal(security, "ieee8021x") == true &&
3003                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
3004                 wifi->assoc_retry_count = 0;
3005                 return false;
3006         }
3007
3008         if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) {
3009                 wifi->assoc_retry_count = 0;
3010
3011                 /* Honestly it's not an invalid-key error,
3012                  * however QA team recommends that the invalid-key error
3013                  * might be better to display for user experience.
3014                  */
3015                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
3016
3017                 return false;
3018         }
3019
3020         return true;
3021 }
3022 #endif
3023
3024 static void interface_state(GSupplicantInterface *interface)
3025 {
3026         struct connman_network *network;
3027         struct connman_device *device;
3028         struct wifi_data *wifi;
3029         GSupplicantState state = g_supplicant_interface_get_state(interface);
3030         bool wps;
3031         bool old_connected;
3032
3033         wifi = g_supplicant_interface_get_data(interface);
3034
3035         DBG("wifi %p interface state %d", wifi, state);
3036
3037         if (!wifi)
3038                 return;
3039
3040         if (state == G_SUPPLICANT_STATE_COMPLETED) {
3041                 if (wifi->tethering_param) {
3042                         g_free(wifi->tethering_param->ssid);
3043                         g_free(wifi->tethering_param);
3044                         wifi->tethering_param = NULL;
3045                 }
3046         }
3047
3048         device = wifi->device;
3049         if (!device)
3050                 return;
3051
3052         if (g_supplicant_interface_get_ready(interface) &&
3053                                         !wifi->interface_ready) {
3054                 wifi->interface_ready = true;
3055                 finalize_interface_creation(wifi);
3056         }
3057
3058         network = wifi->network;
3059         if (!network)
3060                 return;
3061
3062         switch (state) {
3063         case G_SUPPLICANT_STATE_SCANNING:
3064                 if (wifi->connected)
3065                         connman_network_set_connected(network, false);
3066
3067                 break;
3068
3069         case G_SUPPLICANT_STATE_AUTHENTICATING:
3070         case G_SUPPLICANT_STATE_ASSOCIATING:
3071 #if defined TIZEN_EXT
3072                 reset_autoscan(device);
3073 #else
3074                 stop_autoscan(device);
3075 #endif
3076
3077                 if (!wifi->connected)
3078                         connman_network_set_associating(network, true);
3079
3080                 break;
3081
3082         case G_SUPPLICANT_STATE_COMPLETED:
3083 #if defined TIZEN_EXT
3084                 /* though it should be already reset: */
3085                 reset_autoscan(device);
3086
3087                 wifi->assoc_retry_count = 0;
3088
3089                 wifi->scan_pending_network = NULL;
3090
3091                 /* should be cleared scanning flag */
3092                 bool scanning = connman_device_get_scanning(device);
3093                 if (scanning){
3094                         connman_device_set_scanning(device,
3095                                 CONNMAN_SERVICE_TYPE_WIFI, false);
3096                         connman_device_unref(device);
3097                 }
3098 #else
3099                 /* though it should be already stopped: */
3100                 stop_autoscan(device);
3101 #endif
3102
3103                 if (!handle_wps_completion(interface, network, device, wifi))
3104                         break;
3105
3106                 connman_network_set_connected(network, true);
3107
3108                 wifi->disconnect_code = 0;
3109                 wifi->assoc_code = 0;
3110                 wifi->load_shaping_retries = 0;
3111                 break;
3112
3113         case G_SUPPLICANT_STATE_DISCONNECTED:
3114                 /*
3115                  * If we're in one of the idle modes, we have
3116                  * not started association yet and thus setting
3117                  * those ones to FALSE could cancel an association
3118                  * in progress.
3119                  */
3120                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
3121                 if (wps)
3122                         if (is_idle_wps(interface, wifi))
3123                                 break;
3124
3125                 if (is_idle(wifi))
3126                         break;
3127
3128                 if (handle_assoc_status_code(interface, wifi))
3129                         break;
3130
3131                 /* If previous state was 4way-handshake, then
3132                  * it's either: psk was incorrect and thus we retry
3133                  * or if we reach the maximum retries we declare the
3134                  * psk as wrong */
3135                 if (handle_4way_handshake_failure(interface,
3136                                                 network, wifi))
3137                         break;
3138
3139                 /* See table 8-36 Reason codes in IEEE Std 802.11 */
3140                 switch (wifi->disconnect_code) {
3141                 case 1: /* Unspecified reason */
3142                         /* Let's assume it's because we got blocked */
3143
3144                 case 6: /* Class 2 frame received from nonauthenticated STA */
3145                         connman_network_set_error(network,
3146                                                 CONNMAN_NETWORK_ERROR_BLOCKED);
3147                         break;
3148
3149                 default:
3150                         break;
3151                 }
3152
3153 #if defined TIZEN_EXT
3154                 /* Some of Wi-Fi networks are not comply Wi-Fi specification.
3155                  * Retry association until its retry count is expired */
3156                 if (handle_wifi_assoc_retry(network, wifi) == true) {
3157                         throw_wifi_scan(wifi->device, scan_callback);
3158                         wifi->scan_pending_network = wifi->network;
3159                         break;
3160                 }
3161
3162                 if(wifi->disconnect_code > 0){
3163                         DBG("Set disconnect reason code(%d)", wifi->disconnect_code);
3164                         connman_network_set_disconnect_reason(network, wifi->disconnect_code);
3165                 }
3166 #endif
3167
3168                 connman_network_set_connected(network, false);
3169                 connman_network_set_associating(network, false);
3170                 wifi->disconnecting = false;
3171
3172                 start_autoscan(device);
3173
3174                 break;
3175
3176         case G_SUPPLICANT_STATE_INACTIVE:
3177 #if defined TIZEN_EXT
3178                 if (handle_wps_completion(interface, network, device, wifi) == false)
3179                         break;
3180 #endif
3181                 connman_network_set_associating(network, false);
3182                 start_autoscan(device);
3183
3184                 break;
3185
3186         case G_SUPPLICANT_STATE_UNKNOWN:
3187         case G_SUPPLICANT_STATE_DISABLED:
3188         case G_SUPPLICANT_STATE_ASSOCIATED:
3189         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3190         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3191                 break;
3192         }
3193
3194         old_connected = wifi->connected;
3195         wifi->state = state;
3196
3197         /* Saving wpa_s state policy:
3198          * If connected and if the state changes are roaming related:
3199          * --> We stay connected
3200          * If completed
3201          * --> We are connected
3202          * All other case:
3203          * --> We are not connected
3204          * */
3205         switch (state) {
3206         case G_SUPPLICANT_STATE_AUTHENTICATING:
3207         case G_SUPPLICANT_STATE_ASSOCIATING:
3208         case G_SUPPLICANT_STATE_ASSOCIATED:
3209         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3210         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3211                 if (wifi->connected)
3212                         connman_warn("Probably roaming right now!"
3213                                                 " Staying connected...");
3214                 break;
3215         case G_SUPPLICANT_STATE_SCANNING:
3216                 wifi->connected = false;
3217
3218                 if (old_connected)
3219                         start_autoscan(device);
3220                 break;
3221         case G_SUPPLICANT_STATE_COMPLETED:
3222                 wifi->connected = true;
3223                 break;
3224         default:
3225                 wifi->connected = false;
3226                 break;
3227         }
3228
3229         DBG("DONE");
3230 }
3231
3232 static void interface_removed(GSupplicantInterface *interface)
3233 {
3234         const char *ifname = g_supplicant_interface_get_ifname(interface);
3235         struct wifi_data *wifi;
3236
3237         DBG("ifname %s", ifname);
3238
3239         wifi = g_supplicant_interface_get_data(interface);
3240
3241         if (wifi)
3242                 wifi->interface = NULL;
3243
3244         if (wifi && wifi->tethering)
3245                 return;
3246
3247         if (!wifi || !wifi->device) {
3248                 DBG("wifi interface already removed");
3249                 return;
3250         }
3251
3252         connman_device_set_powered(wifi->device, false);
3253
3254         check_p2p_technology();
3255 }
3256
3257 static void set_device_type(const char *type, char dev_type[17])
3258 {
3259         const char *oui = "0050F204";
3260         const char *category = "0001";
3261         const char *sub_category = "0000";
3262
3263         if (!g_strcmp0(type, "handset")) {
3264                 category = "000A";
3265                 sub_category = "0005";
3266         } else if (!g_strcmp0(type, "vm") || !g_strcmp0(type, "container"))
3267                 sub_category = "0001";
3268         else if (!g_strcmp0(type, "server"))
3269                 sub_category = "0002";
3270         else if (!g_strcmp0(type, "laptop"))
3271                 sub_category = "0005";
3272         else if (!g_strcmp0(type, "desktop"))
3273                 sub_category = "0006";
3274         else if (!g_strcmp0(type, "tablet"))
3275                 sub_category = "0009";
3276         else if (!g_strcmp0(type, "watch"))
3277                 category = "00FF";
3278
3279         snprintf(dev_type, 17, "%s%s%s", category, oui, sub_category);
3280 }
3281
3282 static void p2p_support(GSupplicantInterface *interface)
3283 {
3284         char dev_type[17] = {};
3285         const char *hostname;
3286
3287         DBG("");
3288
3289         if (!interface)
3290                 return;
3291
3292         if (!g_supplicant_interface_has_p2p(interface))
3293                 return;
3294
3295         if (connman_technology_driver_register(&p2p_tech_driver) < 0) {
3296                 DBG("Could not register P2P technology driver");
3297                 return;
3298         }
3299
3300         hostname = connman_utsname_get_hostname();
3301         if (!hostname)
3302                 hostname = "ConnMan";
3303
3304         set_device_type(connman_machine_get_type(), dev_type);
3305         g_supplicant_interface_set_p2p_device_config(interface,
3306                                                         hostname, dev_type);
3307         connman_peer_driver_register(&peer_driver);
3308 }
3309
3310 static void scan_started(GSupplicantInterface *interface)
3311 {
3312         DBG("");
3313 }
3314
3315 static void scan_finished(GSupplicantInterface *interface)
3316 {
3317 #if defined TIZEN_EXT
3318         struct wifi_data *wifi;
3319         bool is_associating = false;
3320         static bool is_scanning = true;
3321 #endif
3322
3323         DBG("");
3324
3325 #if defined TIZEN_EXT
3326         wifi = g_supplicant_interface_get_data(interface);
3327         if (wifi && wifi->scan_pending_network) {
3328                 network_connect(wifi->scan_pending_network);
3329                 wifi->scan_pending_network = NULL;
3330         }
3331
3332         //service state - associating
3333         if(!wifi || !wifi->network)
3334                 return;
3335
3336         is_associating = connman_network_get_associating(wifi->network);
3337         if(is_associating && is_scanning){
3338                 is_scanning = false;
3339                 DBG("send scan for connecting");
3340                 throw_wifi_scan(wifi->device, scan_callback);
3341
3342                 return;
3343         }
3344         is_scanning = true;
3345
3346         //go scan
3347
3348 #endif
3349 }
3350
3351 static void ap_create_fail(GSupplicantInterface *interface)
3352 {
3353         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
3354         int ret;
3355
3356         if ((wifi->tethering) && (wifi->tethering_param)) {
3357                 DBG("%s create AP fail \n",
3358                                 g_supplicant_interface_get_ifname(wifi->interface));
3359
3360                 connman_inet_remove_from_bridge(wifi->index, wifi->bridge);
3361                 wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
3362                 wifi->tethering = false;
3363
3364                 ret = tech_set_tethering(wifi->tethering_param->technology,
3365                                 wifi->tethering_param->ssid->ssid,
3366                                 wifi->tethering_param->ssid->passphrase,
3367                                 wifi->bridge, true);
3368
3369                 if ((ret == -EOPNOTSUPP) && (wifi_technology)) {
3370                         connman_technology_tethering_notify(wifi_technology,false);
3371                 }
3372
3373                 g_free(wifi->tethering_param->ssid);
3374                 g_free(wifi->tethering_param);
3375                 wifi->tethering_param = NULL;
3376         }
3377
3378         return;
3379 }
3380
3381 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
3382 {
3383         unsigned char strength;
3384
3385         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
3386
3387 #if !defined TIZEN_EXT
3388         if (strength > 100)
3389                 strength = 100;
3390 #endif
3391         return strength;
3392 }
3393
3394 static void network_added(GSupplicantNetwork *supplicant_network)
3395 {
3396         struct connman_network *network;
3397         GSupplicantInterface *interface;
3398         struct wifi_data *wifi;
3399         const char *name, *identifier, *security, *group, *mode;
3400         const unsigned char *ssid;
3401         unsigned int ssid_len;
3402         bool wps;
3403         bool wps_pbc;
3404         bool wps_ready;
3405         bool wps_advertizing;
3406
3407 #if defined TIZEN_EXT
3408         GSList *vsie_list = NULL;
3409         const unsigned char *country_code;
3410 #endif
3411
3412         mode = g_supplicant_network_get_mode(supplicant_network);
3413         identifier = g_supplicant_network_get_identifier(supplicant_network);
3414
3415         DBG("%s", identifier);
3416
3417         if (!g_strcmp0(mode, "adhoc"))
3418                 return;
3419
3420         interface = g_supplicant_network_get_interface(supplicant_network);
3421         wifi = g_supplicant_interface_get_data(interface);
3422         name = g_supplicant_network_get_name(supplicant_network);
3423         security = g_supplicant_network_get_security(supplicant_network);
3424         group = g_supplicant_network_get_identifier(supplicant_network);
3425         wps = g_supplicant_network_get_wps(supplicant_network);
3426         wps_pbc = g_supplicant_network_is_wps_pbc(supplicant_network);
3427         wps_ready = g_supplicant_network_is_wps_active(supplicant_network);
3428         wps_advertizing = g_supplicant_network_is_wps_advertizing(
3429                                                         supplicant_network);
3430
3431         if (!wifi)
3432                 return;
3433
3434         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
3435
3436         network = connman_device_get_network(wifi->device, identifier);
3437
3438         if (!network) {
3439                 network = connman_network_create(identifier,
3440                                                 CONNMAN_NETWORK_TYPE_WIFI);
3441                 if (!network)
3442                         return;
3443
3444                 connman_network_set_index(network, wifi->index);
3445
3446                 if (connman_device_add_network(wifi->device, network) < 0) {
3447                         connman_network_unref(network);
3448                         return;
3449                 }
3450
3451                 wifi->networks = g_slist_prepend(wifi->networks, network);
3452         }
3453
3454         if (name && name[0] != '\0')
3455                 connman_network_set_name(network, name);
3456
3457         connman_network_set_blob(network, "WiFi.SSID",
3458                                                 ssid, ssid_len);
3459 #if defined TIZEN_EXT
3460         vsie_list = (GSList *)g_supplicant_network_get_wifi_vsie(supplicant_network);
3461         if (vsie_list)
3462                 connman_network_set_vsie_list(network, vsie_list);
3463         else
3464                 DBG("vsie_list is NULL");
3465         country_code = g_supplicant_network_get_countrycode(supplicant_network);
3466         connman_network_set_countrycode(network, country_code);
3467 #endif
3468         connman_network_set_string(network, "WiFi.Security", security);
3469         connman_network_set_strength(network,
3470                                 calculate_strength(supplicant_network));
3471         connman_network_set_bool(network, "WiFi.WPS", wps);
3472
3473         if (wps) {
3474                 /* Is AP advertizing for WPS association?
3475                  * If so, we decide to use WPS by default */
3476                 if (wps_ready && wps_pbc &&
3477                                                 wps_advertizing) {
3478 #if !defined TIZEN_EXT
3479                         connman_network_set_bool(network, "WiFi.UseWPS", true);
3480 #else
3481                         DBG("wps is activating by ap but ignore it.");
3482 #endif
3483                 }
3484         }
3485
3486         connman_network_set_frequency(network,
3487                         g_supplicant_network_get_frequency(supplicant_network));
3488 #if defined TIZEN_EXT
3489         connman_network_set_bssid(network,
3490                         g_supplicant_network_get_bssid(supplicant_network));
3491         connman_network_set_maxrate(network,
3492                         g_supplicant_network_get_maxrate(supplicant_network));
3493         connman_network_set_enc_mode(network,
3494                         g_supplicant_network_get_enc_mode(supplicant_network));
3495         connman_network_set_rsn_mode(network,
3496                         g_supplicant_network_get_rsn_mode(supplicant_network));
3497         connman_network_set_keymgmt(network,
3498                         g_supplicant_network_get_keymgmt(supplicant_network));
3499         connman_network_set_bool(network, "WiFi.HS20AP",
3500                         g_supplicant_network_is_hs20AP(supplicant_network));
3501         connman_network_set_bssid_list(network,
3502                         (GSList *)g_supplicant_network_get_bssid_list(supplicant_network));
3503 #endif
3504         connman_network_set_available(network, true);
3505         connman_network_set_string(network, "WiFi.Mode", mode);
3506
3507 #if defined TIZEN_EXT
3508         if (group)
3509 #else
3510         if (ssid)
3511 #endif
3512                 connman_network_set_group(network, group);
3513
3514 #if defined TIZEN_EXT
3515         if (wifi_first_scan == true)
3516                 found_with_first_scan = true;
3517 #endif
3518
3519         if (wifi->hidden && ssid) {
3520 #if defined TIZEN_EXT
3521                 if (network_security(wifi->hidden->security) ==
3522                         network_security(security) &&
3523 #else
3524                 if (!g_strcmp0(wifi->hidden->security, security) &&
3525 #endif
3526                                 wifi->hidden->ssid_len == ssid_len &&
3527                                 !memcmp(wifi->hidden->ssid, ssid, ssid_len)) {
3528                         connman_network_connect_hidden(network,
3529                                         wifi->hidden->identity,
3530                                         wifi->hidden->passphrase,
3531                                         wifi->hidden->user_data);
3532                         wifi->hidden->user_data = NULL;
3533                         hidden_free(wifi->hidden);
3534                         wifi->hidden = NULL;
3535                 }
3536         }
3537 }
3538
3539 static void network_removed(GSupplicantNetwork *network)
3540 {
3541         GSupplicantInterface *interface;
3542         struct wifi_data *wifi;
3543         const char *name, *identifier;
3544         struct connman_network *connman_network;
3545
3546         interface = g_supplicant_network_get_interface(network);
3547         wifi = g_supplicant_interface_get_data(interface);
3548         identifier = g_supplicant_network_get_identifier(network);
3549         name = g_supplicant_network_get_name(network);
3550
3551         DBG("name %s", name);
3552
3553         if (!wifi)
3554                 return;
3555
3556         connman_network = connman_device_get_network(wifi->device, identifier);
3557         if (!connman_network)
3558                 return;
3559
3560 #if defined TIZEN_EXT
3561         if (connman_network == wifi->scan_pending_network)
3562                 wifi->scan_pending_network = NULL;
3563
3564         if (connman_network == wifi->pending_network)
3565                 wifi->pending_network = NULL;
3566
3567         if(connman_network_get_connecting(connman_network) == true){
3568                 connman_network_set_connected(connman_network, false);
3569         }
3570 #endif
3571
3572         wifi->networks = g_slist_remove(wifi->networks, connman_network);
3573
3574         connman_device_remove_network(wifi->device, connman_network);
3575         connman_network_unref(connman_network);
3576 }
3577
3578 static void network_changed(GSupplicantNetwork *network, const char *property)
3579 {
3580         GSupplicantInterface *interface;
3581         struct wifi_data *wifi;
3582         const char *name, *identifier;
3583         struct connman_network *connman_network;
3584
3585 #if defined TIZEN_EXT
3586         const unsigned char *bssid;
3587         unsigned int maxrate;
3588         uint16_t frequency;
3589         bool wps;
3590         const unsigned char *country_code;
3591         GSList *bssid_list;
3592 #endif
3593
3594         interface = g_supplicant_network_get_interface(network);
3595         wifi = g_supplicant_interface_get_data(interface);
3596         identifier = g_supplicant_network_get_identifier(network);
3597         name = g_supplicant_network_get_name(network);
3598
3599         DBG("name %s", name);
3600
3601         if (!wifi)
3602                 return;
3603
3604         connman_network = connman_device_get_network(wifi->device, identifier);
3605         if (!connman_network)
3606                 return;
3607
3608         if (g_str_equal(property, "Signal")) {
3609                connman_network_set_strength(connman_network,
3610                                         calculate_strength(network));
3611                connman_network_update(connman_network);
3612         }
3613
3614 #if defined TIZEN_EXT
3615         bssid = g_supplicant_network_get_bssid(network);
3616         maxrate = g_supplicant_network_get_maxrate(network);
3617         frequency = g_supplicant_network_get_frequency(network);
3618         wps = g_supplicant_network_get_wps(network);
3619
3620         connman_network_set_bssid(connman_network, bssid);
3621         connman_network_set_maxrate(connman_network, maxrate);
3622         connman_network_set_frequency(connman_network, frequency);
3623         connman_network_set_bool(connman_network, "WiFi.WPS", wps);
3624         country_code = g_supplicant_network_get_countrycode(network);
3625         connman_network_set_countrycode(connman_network, country_code);
3626         bssid_list = (GSList *)g_supplicant_network_get_bssid_list(network);
3627         connman_network_set_bssid_list(connman_network, bssid_list);
3628 #endif
3629 }
3630
3631 static void network_associated(GSupplicantNetwork *network)
3632 {
3633         GSupplicantInterface *interface;
3634         struct wifi_data *wifi;
3635         struct connman_network *connman_network;
3636         const char *identifier;
3637
3638         DBG("");
3639
3640         interface = g_supplicant_network_get_interface(network);
3641         if (!interface)
3642                 return;
3643
3644         wifi = g_supplicant_interface_get_data(interface);
3645         if (!wifi)
3646                 return;
3647
3648         identifier = g_supplicant_network_get_identifier(network);
3649
3650         connman_network = connman_device_get_network(wifi->device, identifier);
3651         if (!connman_network)
3652                 return;
3653
3654         if (wifi->network) {
3655                 if (wifi->network == connman_network)
3656                         return;
3657
3658                 /*
3659                  * This should never happen, we got associated with
3660                  * a network different than the one we were expecting.
3661                  */
3662                 DBG("Associated to %p while expecting %p",
3663                                         connman_network, wifi->network);
3664
3665                 connman_network_set_associating(wifi->network, false);
3666         }
3667
3668         DBG("Reconnecting to previous network %p from wpa_s", connman_network);
3669
3670         wifi->network = connman_network_ref(connman_network);
3671         wifi->retries = 0;
3672
3673         /*
3674          * Interface state changes callback (interface_state) is always
3675          * called before network_associated callback thus we need to call
3676          * interface_state again in order to process the new state now that
3677          * we have the network properly set.
3678          */
3679         interface_state(interface);
3680 }
3681
3682 static void apply_peer_services(GSupplicantPeer *peer,
3683                                 struct connman_peer *connman_peer)
3684 {
3685         const unsigned char *data;
3686         int length;
3687
3688         DBG("");
3689
3690         connman_peer_reset_services(connman_peer);
3691
3692         data = g_supplicant_peer_get_widi_ies(peer, &length);
3693         if (data) {
3694                 connman_peer_add_service(connman_peer,
3695                         CONNMAN_PEER_SERVICE_WIFI_DISPLAY, data, length);
3696         }
3697 }
3698
3699 static void add_station(const char *mac)
3700 {
3701         connman_technology_tethering_add_station(CONNMAN_SERVICE_TYPE_WIFI,
3702                                                  mac);
3703 }
3704
3705 static void remove_station(const char *mac)
3706 {
3707         connman_technology_tethering_remove_station(mac);
3708 }
3709
3710 static void peer_found(GSupplicantPeer *peer)
3711 {
3712         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3713         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3714         struct connman_peer *connman_peer;
3715         const char *identifier, *name;
3716         int ret;
3717 #if defined TIZEN_EXT
3718         if (!wifi)
3719                 return;
3720 #endif
3721         identifier = g_supplicant_peer_get_identifier(peer);
3722         name = g_supplicant_peer_get_name(peer);
3723
3724         DBG("ident: %s", identifier);
3725
3726         connman_peer = connman_peer_get(wifi->device, identifier);
3727         if (connman_peer)
3728                 return;
3729
3730         connman_peer = connman_peer_create(identifier);
3731         connman_peer_set_name(connman_peer, name);
3732         connman_peer_set_device(connman_peer, wifi->device);
3733         apply_peer_services(peer, connman_peer);
3734
3735         ret = connman_peer_register(connman_peer);
3736         if (ret < 0 && ret != -EALREADY)
3737                 connman_peer_unref(connman_peer);
3738         else
3739                 wifi->peers = g_slist_prepend(wifi->peers, connman_peer);
3740 }
3741
3742 static void peer_lost(GSupplicantPeer *peer)
3743 {
3744         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3745         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3746         struct connman_peer *connman_peer;
3747         const char *identifier;
3748
3749         if (!wifi)
3750                 return;
3751
3752         identifier = g_supplicant_peer_get_identifier(peer);
3753
3754         DBG("ident: %s", identifier);
3755
3756         connman_peer = connman_peer_get(wifi->device, identifier);
3757         if (connman_peer) {
3758                 if (wifi->p2p_connecting &&
3759                                 wifi->pending_peer == connman_peer) {
3760                         peer_connect_timeout(wifi);
3761                 }
3762                 connman_peer_unregister(connman_peer);
3763                 connman_peer_unref(connman_peer);
3764         }
3765
3766         wifi->peers = g_slist_remove(wifi->peers, connman_peer);
3767 }
3768
3769 static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state)
3770 {
3771         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3772         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3773         enum connman_peer_state p_state = CONNMAN_PEER_STATE_UNKNOWN;
3774         struct connman_peer *connman_peer;
3775         const char *identifier;
3776
3777         identifier = g_supplicant_peer_get_identifier(peer);
3778
3779         DBG("ident: %s", identifier);
3780
3781         if (!wifi)
3782                 return;
3783
3784         connman_peer = connman_peer_get(wifi->device, identifier);
3785         if (!connman_peer)
3786                 return;
3787
3788         switch (state) {
3789         case G_SUPPLICANT_PEER_SERVICES_CHANGED:
3790                 apply_peer_services(peer, connman_peer);
3791                 connman_peer_services_changed(connman_peer);
3792                 return;
3793         case G_SUPPLICANT_PEER_GROUP_CHANGED:
3794                 if (!g_supplicant_peer_is_in_a_group(peer))
3795                         p_state = CONNMAN_PEER_STATE_IDLE;
3796                 else
3797                         p_state = CONNMAN_PEER_STATE_CONFIGURATION;
3798                 break;
3799         case G_SUPPLICANT_PEER_GROUP_STARTED:
3800                 break;
3801         case G_SUPPLICANT_PEER_GROUP_FINISHED:
3802                 p_state = CONNMAN_PEER_STATE_IDLE;
3803                 break;
3804         case G_SUPPLICANT_PEER_GROUP_JOINED:
3805                 connman_peer_set_iface_address(connman_peer,
3806                                 g_supplicant_peer_get_iface_address(peer));
3807                 break;
3808         case G_SUPPLICANT_PEER_GROUP_DISCONNECTED:
3809                 p_state = CONNMAN_PEER_STATE_IDLE;
3810                 break;
3811         case G_SUPPLICANT_PEER_GROUP_FAILED:
3812                 if (g_supplicant_peer_has_requested_connection(peer))
3813                         p_state = CONNMAN_PEER_STATE_IDLE;
3814                 else
3815                         p_state = CONNMAN_PEER_STATE_FAILURE;
3816                 break;
3817         }
3818
3819         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION ||
3820                                         p_state == CONNMAN_PEER_STATE_FAILURE) {
3821                 if (wifi->p2p_connecting
3822                                 && connman_peer == wifi->pending_peer)
3823                         peer_cancel_timeout(wifi);
3824                 else
3825                         p_state = CONNMAN_PEER_STATE_UNKNOWN;
3826         }
3827
3828         if (p_state == CONNMAN_PEER_STATE_UNKNOWN)
3829                 return;
3830
3831         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION) {
3832                 GSupplicantInterface *g_iface;
3833                 struct wifi_data *g_wifi;
3834
3835                 g_iface = g_supplicant_peer_get_group_interface(peer);
3836                 if (!g_iface)
3837                         return;
3838
3839                 g_wifi = g_supplicant_interface_get_data(g_iface);
3840                 if (!g_wifi)
3841                         return;
3842
3843                 connman_peer_set_as_master(connman_peer,
3844                                         !g_supplicant_peer_is_client(peer));
3845                 connman_peer_set_sub_device(connman_peer, g_wifi->device);
3846
3847                 /*
3848                  * If wpa_supplicant didn't create a dedicated p2p-group
3849                  * interface then mark this interface as p2p_device to avoid
3850                  * scan and auto-scan are launched on it while P2P is connected.
3851                  */
3852                 if (!g_list_find(p2p_iface_list, g_wifi))
3853                         wifi->p2p_device = true;
3854         }
3855
3856         connman_peer_set_state(connman_peer, p_state);
3857 }
3858
3859 static void peer_request(GSupplicantPeer *peer)
3860 {
3861         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3862         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3863         struct connman_peer *connman_peer;
3864         const char *identifier;
3865
3866 #if defined TIZEN_EXT
3867         if (!wifi)
3868                 return;
3869 #endif
3870
3871         identifier = g_supplicant_peer_get_identifier(peer);
3872
3873         DBG("ident: %s", identifier);
3874
3875         connman_peer = connman_peer_get(wifi->device, identifier);
3876         if (!connman_peer)
3877                 return;
3878
3879         connman_peer_request_connection(connman_peer);
3880 }
3881
3882 #if defined TIZEN_EXT
3883 static void system_power_off(void)
3884 {
3885         GList *list;
3886         struct wifi_data *wifi;
3887         struct connman_service *service;
3888         struct connman_ipconfig *ipconfig_ipv4;
3889
3890         if (connman_setting_get_bool("WiFiDHCPRelease") == true) {
3891                 for (list = iface_list; list; list = list->next) {
3892                         wifi = list->data;
3893
3894                         if (wifi->network != NULL) {
3895                                 service = connman_service_lookup_from_network(wifi->network);
3896                                 ipconfig_ipv4 = __connman_service_get_ip4config(service);
3897                                 __connman_dhcp_stop(ipconfig_ipv4);
3898                         }
3899                 }
3900         }
3901 }
3902
3903 static void network_merged(GSupplicantNetwork *network)
3904 {
3905         GSupplicantInterface *interface;
3906         GSupplicantState state;
3907         struct wifi_data *wifi;
3908         const char *identifier;
3909         struct connman_network *connman_network;
3910         bool ishs20AP = 0;
3911         char *temp = NULL;
3912
3913         interface = g_supplicant_network_get_interface(network);
3914         if (!interface)
3915                 return;
3916
3917         state = g_supplicant_interface_get_state(interface);
3918         if (state < G_SUPPLICANT_STATE_AUTHENTICATING)
3919                 return;
3920
3921         wifi = g_supplicant_interface_get_data(interface);
3922         if (!wifi)
3923                 return;
3924
3925         identifier = g_supplicant_network_get_identifier(network);
3926
3927         connman_network = connman_device_get_network(wifi->device, identifier);
3928         if (!connman_network)
3929                 return;
3930
3931         DBG("merged identifier %s", identifier);
3932
3933         if (wifi->connected == FALSE) {
3934                 switch (state) {
3935                 case G_SUPPLICANT_STATE_AUTHENTICATING:
3936                 case G_SUPPLICANT_STATE_ASSOCIATING:
3937                 case G_SUPPLICANT_STATE_ASSOCIATED:
3938                 case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3939                 case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3940                         connman_network_set_associating(connman_network, TRUE);
3941                         break;
3942                 case G_SUPPLICANT_STATE_COMPLETED:
3943                         connman_network_set_connected(connman_network, TRUE);
3944                         break;
3945                 default:
3946                         DBG("Not handled the state : %d", state);
3947                         break;
3948                 }
3949         }
3950
3951         ishs20AP = g_supplicant_network_is_hs20AP(network);
3952
3953         if (ishs20AP &&
3954                 g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) {
3955                 temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1);
3956                 connman_network_set_string(connman_network, "WiFi.EAP",
3957                                 temp);
3958                 connman_network_set_string(connman_network, "WiFi.Identity",
3959                                 g_supplicant_network_get_identity(network));
3960                 connman_network_set_string(connman_network, "WiFi.Phase2",
3961                                 g_supplicant_network_get_phase2(network));
3962
3963                 g_free(temp);
3964         }
3965
3966         wifi->network = connman_network;
3967 }
3968
3969 static void assoc_failed(void *user_data)
3970 {
3971         struct connman_network *network = user_data;
3972         connman_network_set_associating(network, false);
3973 }
3974 #endif
3975
3976 static void debug(const char *str)
3977 {
3978         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
3979                 connman_debug("%s", str);
3980 }
3981
3982 static void disconnect_reasoncode(GSupplicantInterface *interface,
3983                                 int reasoncode)
3984 {
3985         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
3986
3987         if (wifi != NULL) {
3988                 wifi->disconnect_code = reasoncode;
3989         }
3990 }
3991
3992 static void assoc_status_code(GSupplicantInterface *interface, int status_code)
3993 {
3994         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
3995
3996         if (wifi != NULL) {
3997                 wifi->assoc_code = status_code;
3998         }
3999 }
4000
4001 static const GSupplicantCallbacks callbacks = {
4002         .system_ready           = system_ready,
4003         .system_killed          = system_killed,
4004         .interface_added        = interface_added,
4005         .interface_state        = interface_state,
4006         .interface_removed      = interface_removed,
4007         .p2p_support            = p2p_support,
4008         .scan_started           = scan_started,
4009         .scan_finished          = scan_finished,
4010         .ap_create_fail         = ap_create_fail,
4011         .network_added          = network_added,
4012         .network_removed        = network_removed,
4013         .network_changed        = network_changed,
4014         .network_associated     = network_associated,
4015         .add_station            = add_station,
4016         .remove_station         = remove_station,
4017         .peer_found             = peer_found,
4018         .peer_lost              = peer_lost,
4019         .peer_changed           = peer_changed,
4020         .peer_request           = peer_request,
4021 #if defined TIZEN_EXT
4022         .system_power_off       = system_power_off,
4023         .network_merged = network_merged,
4024         .assoc_failed           = assoc_failed,
4025 #endif
4026         .debug                  = debug,
4027         .disconnect_reasoncode  = disconnect_reasoncode,
4028         .assoc_status_code      = assoc_status_code,
4029 };
4030
4031
4032 static int tech_probe(struct connman_technology *technology)
4033 {
4034         wifi_technology = technology;
4035
4036         return 0;
4037 }
4038
4039 static void tech_remove(struct connman_technology *technology)
4040 {
4041         wifi_technology = NULL;
4042 }
4043
4044 static GSupplicantSSID *ssid_ap_init(const char *ssid,
4045                 const char *passphrase)
4046 {
4047         GSupplicantSSID *ap;
4048
4049         ap = g_try_malloc0(sizeof(GSupplicantSSID));
4050         if (!ap)
4051                 return NULL;
4052
4053         ap->mode = G_SUPPLICANT_MODE_MASTER;
4054 #if defined TIZEN_EXT
4055         ap->ssid = (void *) ssid;
4056 #else
4057         ap->ssid = ssid;
4058 #endif
4059         ap->ssid_len = strlen(ssid);
4060         ap->scan_ssid = 0;
4061         ap->freq = 2412;
4062
4063         if (!passphrase || strlen(passphrase) == 0) {
4064                 ap->security = G_SUPPLICANT_SECURITY_NONE;
4065                 ap->passphrase = NULL;
4066         } else {
4067                ap->security = G_SUPPLICANT_SECURITY_PSK;
4068                ap->protocol = G_SUPPLICANT_PROTO_RSN;
4069                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
4070                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
4071                ap->passphrase = passphrase;
4072         }
4073
4074         return ap;
4075 }
4076
4077 static void ap_start_callback(int result, GSupplicantInterface *interface,
4078                                                         void *user_data)
4079 {
4080         struct wifi_tethering_info *info = user_data;
4081
4082         DBG("result %d index %d bridge %s",
4083                 result, info->wifi->index, info->wifi->bridge);
4084
4085         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
4086                 connman_inet_remove_from_bridge(info->wifi->index,
4087                                                         info->wifi->bridge);
4088
4089                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
4090                         connman_technology_tethering_notify(info->technology, false);
4091                         g_free(info->wifi->tethering_param->ssid);
4092                         g_free(info->wifi->tethering_param);
4093                         info->wifi->tethering_param = NULL;
4094                 }
4095         }
4096
4097         g_free(info->ifname);
4098         g_free(info);
4099 }
4100
4101 static void ap_create_callback(int result,
4102                                 GSupplicantInterface *interface,
4103                                         void *user_data)
4104 {
4105         struct wifi_tethering_info *info = user_data;
4106
4107         DBG("result %d ifname %s", result,
4108                                 g_supplicant_interface_get_ifname(interface));
4109
4110         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
4111                 connman_inet_remove_from_bridge(info->wifi->index,
4112                                                         info->wifi->bridge);
4113
4114                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
4115                         connman_technology_tethering_notify(info->technology, false);
4116                         g_free(info->wifi->tethering_param->ssid);
4117                         g_free(info->wifi->tethering_param);
4118                         info->wifi->tethering_param = NULL;
4119
4120                 }
4121
4122                 g_free(info->ifname);
4123                 g_free(info->ssid);
4124                 g_free(info);
4125                 return;
4126         }
4127
4128         info->wifi->interface = interface;
4129         g_supplicant_interface_set_data(interface, info->wifi);
4130
4131         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
4132                 connman_error("Failed to set interface ap_scan property");
4133
4134         g_supplicant_interface_connect(interface, info->ssid,
4135                                                 ap_start_callback, info);
4136 }
4137
4138 static void sta_remove_callback(int result,
4139                                 GSupplicantInterface *interface,
4140                                         void *user_data)
4141 {
4142         struct wifi_tethering_info *info = user_data;
4143         const char *driver = connman_option_get_string("wifi");
4144
4145         DBG("ifname %s result %d ", info->ifname, result);
4146
4147         if (result < 0 || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
4148                 info->wifi->tethering = false;
4149                 connman_technology_tethering_notify(info->technology, false);
4150
4151                 g_free(info->ifname);
4152                 g_free(info->ssid);
4153                 g_free(info);
4154
4155                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
4156                         g_free(info->wifi->tethering_param->ssid);
4157                         g_free(info->wifi->tethering_param);
4158                         info->wifi->tethering_param = NULL;
4159                 }
4160                 return;
4161         }
4162
4163         info->wifi->interface = NULL;
4164
4165         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
4166                                                 ap_create_callback,
4167                                                         info);
4168 }
4169
4170 static int enable_wifi_tethering(struct connman_technology *technology,
4171                                 const char *bridge, const char *identifier,
4172                                 const char *passphrase, bool available)
4173 {
4174         GList *list;
4175         GSupplicantInterface *interface;
4176         struct wifi_data *wifi;
4177         struct wifi_tethering_info *info;
4178         const char *ifname;
4179         unsigned int mode;
4180         int err, berr = 0;
4181
4182         for (list = iface_list; list; list = list->next) {
4183                 wifi = list->data;
4184
4185                 DBG("wifi %p network %p pending_network %p", wifi,
4186                         wifi->network, wifi->pending_network);
4187
4188                 interface = wifi->interface;
4189
4190                 if (!interface)
4191                         continue;
4192
4193                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED)
4194                         continue;
4195
4196                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
4197
4198                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED) {
4199                         DBG("%s does not support AP mode (detected)", ifname);
4200                         continue;
4201                 }
4202
4203                 mode = g_supplicant_interface_get_mode(interface);
4204                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
4205                         wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
4206                         DBG("%s does not support AP mode (capability)", ifname);
4207                         continue;
4208                 }
4209
4210                 if (wifi->network && available)
4211                         continue;
4212
4213                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
4214                 if (!info)
4215                         return -ENOMEM;
4216
4217                 wifi->tethering_param = g_try_malloc0(sizeof(struct wifi_tethering_info));
4218                 if (!wifi->tethering_param) {
4219                         g_free(info);
4220                         return -ENOMEM;
4221                 }
4222
4223                 info->wifi = wifi;
4224                 info->technology = technology;
4225                 info->wifi->bridge = bridge;
4226                 info->ssid = ssid_ap_init(identifier, passphrase);
4227                 if (!info->ssid)
4228                         goto failed;
4229
4230                 info->ifname = g_strdup(ifname);
4231                 if (!info->ifname)
4232                         goto failed;
4233
4234                 wifi->tethering_param->technology = technology;
4235                 wifi->tethering_param->ssid = ssid_ap_init(identifier, passphrase);
4236                 if (!wifi->tethering_param->ssid)
4237                         goto failed;
4238
4239                 info->wifi->tethering = true;
4240                 info->wifi->ap_supported = WIFI_AP_SUPPORTED;
4241
4242                 berr = connman_technology_tethering_notify(technology, true);
4243                 if (berr < 0)
4244                         goto failed;
4245
4246                 err = g_supplicant_interface_remove(interface,
4247                                                 sta_remove_callback,
4248                                                         info);
4249                 if (err >= 0) {
4250                         DBG("tethering wifi %p ifname %s", wifi, ifname);
4251                         return 0;
4252                 }
4253
4254         failed:
4255                 g_free(info->ifname);
4256                 g_free(info->ssid);
4257                 g_free(info);
4258                 g_free(wifi->tethering_param);
4259                 wifi->tethering_param = NULL;
4260
4261                 /*
4262                  * Remove bridge if it was correctly created but remove
4263                  * operation failed. Instead, if bridge creation failed then
4264                  * break out and do not try again on another interface,
4265                  * bridge set-up does not depend on it.
4266                  */
4267                 if (berr == 0)
4268                         connman_technology_tethering_notify(technology, false);
4269                 else
4270                         break;
4271         }
4272
4273         return -EOPNOTSUPP;
4274 }
4275
4276 static int tech_set_tethering(struct connman_technology *technology,
4277                                 const char *identifier, const char *passphrase,
4278                                 const char *bridge, bool enabled)
4279 {
4280         GList *list;
4281         struct wifi_data *wifi;
4282         int err;
4283
4284         DBG("");
4285
4286         if (!enabled) {
4287                 for (list = iface_list; list; list = list->next) {
4288                         wifi = list->data;
4289
4290                         if (wifi->tethering) {
4291                                 wifi->tethering = false;
4292
4293                                 connman_inet_remove_from_bridge(wifi->index,
4294                                                                         bridge);
4295                                 wifi->bridged = false;
4296                         }
4297                 }
4298
4299                 connman_technology_tethering_notify(technology, false);
4300
4301                 return 0;
4302         }
4303
4304         DBG("trying tethering for available devices");
4305         err = enable_wifi_tethering(technology, bridge, identifier, passphrase,
4306                                 true);
4307
4308         if (err < 0) {
4309                 DBG("trying tethering for any device");
4310                 err = enable_wifi_tethering(technology, bridge, identifier,
4311                                         passphrase, false);
4312         }
4313
4314         return err;
4315 }
4316
4317 static void regdom_callback(int result, const char *alpha2, void *user_data)
4318 {
4319         DBG("");
4320
4321         if (!wifi_technology)
4322                 return;
4323
4324         if (result != 0)
4325                 alpha2 = NULL;
4326
4327         connman_technology_regdom_notify(wifi_technology, alpha2);
4328 }
4329
4330 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
4331 {
4332         return g_supplicant_set_country(alpha2, regdom_callback, NULL);
4333 }
4334
4335 static struct connman_technology_driver tech_driver = {
4336         .name           = "wifi",
4337         .type           = CONNMAN_SERVICE_TYPE_WIFI,
4338         .probe          = tech_probe,
4339         .remove         = tech_remove,
4340         .set_tethering  = tech_set_tethering,
4341         .set_regdom     = tech_set_regdom,
4342 };
4343
4344 static int wifi_init(void)
4345 {
4346         int err;
4347
4348         err = connman_network_driver_register(&network_driver);
4349         if (err < 0)
4350                 return err;
4351
4352         err = g_supplicant_register(&callbacks);
4353         if (err < 0) {
4354                 connman_network_driver_unregister(&network_driver);
4355                 return err;
4356         }
4357
4358         err = connman_technology_driver_register(&tech_driver);
4359         if (err < 0) {
4360                 g_supplicant_unregister(&callbacks);
4361                 connman_network_driver_unregister(&network_driver);
4362                 return err;
4363         }
4364
4365         return 0;
4366 }
4367
4368 static void wifi_exit(void)
4369 {
4370         DBG();
4371
4372         connman_technology_driver_unregister(&tech_driver);
4373
4374         g_supplicant_unregister(&callbacks);
4375
4376         connman_network_driver_unregister(&network_driver);
4377 }
4378
4379 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
4380                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)