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