Remove Tizen specific hidden connection logic
[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
1187         if (connman_device_get_scanning(device))
1188                 return -EALREADY;
1189
1190         connman_device_ref(device);
1191
1192         ret = g_supplicant_interface_scan(wifi->interface, NULL,
1193                                                 callback, device);
1194         if (ret == 0) {
1195                 connman_device_set_scanning(device,
1196                                 CONNMAN_SERVICE_TYPE_WIFI, true);
1197         } else
1198                 connman_device_unref(device);
1199
1200         return ret;
1201 }
1202
1203 static void hidden_free(struct hidden_params *hidden)
1204 {
1205         if (!hidden)
1206                 return;
1207
1208         if (hidden->scan_params)
1209                 g_supplicant_free_scan_params(hidden->scan_params);
1210         g_free(hidden->identity);
1211         g_free(hidden->passphrase);
1212         g_free(hidden->security);
1213         g_free(hidden);
1214 }
1215
1216 #if defined TIZEN_EXT
1217 static void service_state_changed(struct connman_service *service,
1218                                         enum connman_service_state state);
1219
1220 static int network_connect(struct connman_network *network);
1221
1222 static struct connman_notifier notifier = {
1223         .name                   = "wifi",
1224         .priority               = CONNMAN_NOTIFIER_PRIORITY_DEFAULT,
1225         .service_state_changed  = service_state_changed,
1226 };
1227
1228 static void service_state_changed(struct connman_service *service,
1229                                         enum connman_service_state state)
1230 {
1231         enum connman_service_type type;
1232
1233         type = connman_service_get_type(service);
1234         if (type != CONNMAN_SERVICE_TYPE_WIFI)
1235                 return;
1236
1237         DBG("service %p state %d", service, state);
1238
1239         switch (state) {
1240         case CONNMAN_SERVICE_STATE_READY:
1241         case CONNMAN_SERVICE_STATE_ONLINE:
1242         case CONNMAN_SERVICE_STATE_FAILURE:
1243                 connman_notifier_unregister(&notifier);
1244                 is_wifi_notifier_registered = FALSE;
1245
1246                 __connman_device_request_scan(type);
1247                 break;
1248
1249         default:
1250                 break;
1251         }
1252 }
1253 #endif
1254
1255 static void scan_callback(int result, GSupplicantInterface *interface,
1256                                                 void *user_data)
1257 {
1258         struct connman_device *device = user_data;
1259         struct wifi_data *wifi = connman_device_get_data(device);
1260         bool scanning;
1261
1262         DBG("result %d wifi %p", result, wifi);
1263
1264         if (wifi) {
1265                 if (wifi->hidden && !wifi->postpone_hidden) {
1266                         connman_network_clear_hidden(wifi->hidden->user_data);
1267                         hidden_free(wifi->hidden);
1268                         wifi->hidden = NULL;
1269                 }
1270
1271                 if (wifi->scan_params) {
1272                         g_supplicant_free_scan_params(wifi->scan_params);
1273                         wifi->scan_params = NULL;
1274                 }
1275         }
1276
1277         if (result < 0)
1278                 connman_device_reset_scanning(device);
1279
1280         /* User is connecting to a hidden AP, let's wait for finished event */
1281         if (wifi && wifi->hidden && wifi->postpone_hidden) {
1282                 GSupplicantScanParams *scan_params;
1283                 int ret;
1284
1285                 wifi->postpone_hidden = false;
1286                 scan_params = wifi->hidden->scan_params;
1287                 wifi->hidden->scan_params = NULL;
1288
1289                 reset_autoscan(device);
1290
1291                 ret = g_supplicant_interface_scan(wifi->interface, scan_params,
1292                                                         scan_callback, device);
1293                 if (ret == 0)
1294                         return;
1295
1296                 /* On error, let's recall scan_callback, which will cleanup */
1297                 return scan_callback(ret, interface, user_data);
1298         }
1299
1300         scanning = connman_device_get_scanning(device);
1301
1302         if (scanning) {
1303                 connman_device_set_scanning(device,
1304                                 CONNMAN_SERVICE_TYPE_WIFI, false);
1305         }
1306
1307         if (result != -ENOLINK)
1308 #if defined TIZEN_EXT
1309         if (result != -EIO)
1310 #endif
1311                 start_autoscan(device);
1312
1313         /*
1314          * If we are here then we were scanning; however, if we are
1315          * also mid-flight disabling the interface, then wifi_disable
1316          * has already cleared the device scanning state and
1317          * unreferenced the device, obviating the need to do it here.
1318          */
1319
1320         if (scanning)
1321                 connman_device_unref(device);
1322
1323 #if defined TIZEN_EXT
1324         if (wifi && wifi->allow_full_scan) {
1325                 DBG("Trigger Full Channel Scan");
1326                 throw_wifi_scan(device, scan_callback);
1327                 wifi->allow_full_scan = FALSE;
1328         }
1329         if (wifi && wifi->scan_pending_network && result != -EIO) {
1330                 network_connect(wifi->scan_pending_network);
1331                 wifi->scan_pending_network = NULL;
1332                 connman_network_set_connecting(wifi->network);
1333         }
1334
1335         if (is_wifi_notifier_registered != true &&
1336                         wifi_first_scan == true && found_with_first_scan == true) {
1337                 wifi_first_scan = false;
1338                 found_with_first_scan = false;
1339
1340                 connman_notifier_register(&notifier);
1341                 is_wifi_notifier_registered = true;
1342         }
1343 #endif
1344 }
1345
1346 static void scan_callback_hidden(int result,
1347                         GSupplicantInterface *interface, void *user_data)
1348 {
1349         struct connman_device *device = user_data;
1350         struct wifi_data *wifi = connman_device_get_data(device);
1351         GSupplicantScanParams *scan_params;
1352         int ret;
1353
1354         DBG("result %d wifi %p", result, wifi);
1355
1356         if (!wifi)
1357                 goto out;
1358
1359         /* User is trying to connect to a hidden AP */
1360         if (wifi->hidden && wifi->postpone_hidden)
1361                 goto out;
1362
1363         scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
1364         if (!scan_params)
1365                 goto out;
1366
1367         if (get_hidden_connections_params(wifi, scan_params) > 0) {
1368                 ret = g_supplicant_interface_scan(wifi->interface,
1369                                                         scan_params,
1370                                                         scan_callback_hidden,
1371                                                         device);
1372                 if (ret == 0)
1373                         return;
1374         }
1375
1376         g_supplicant_free_scan_params(scan_params);
1377
1378 out:
1379         scan_callback(result, interface, user_data);
1380 }
1381
1382 static gboolean autoscan_timeout(gpointer data)
1383 {
1384         struct connman_device *device = data;
1385         struct wifi_data *wifi = connman_device_get_data(device);
1386         struct autoscan_params *autoscan;
1387         int interval;
1388
1389         if (!wifi)
1390                 return FALSE;
1391
1392         autoscan = wifi->autoscan;
1393
1394         if (autoscan->interval <= 0) {
1395                 interval = autoscan->base;
1396                 goto set_interval;
1397         } else
1398                 interval = autoscan->interval * autoscan->base;
1399
1400 #if defined TIZEN_EXT
1401         if (autoscan->interval >= autoscan->limit)
1402 #else
1403         if (interval > autoscan->limit)
1404 #endif
1405                 interval = autoscan->limit;
1406
1407         throw_wifi_scan(wifi->device, scan_callback_hidden);
1408
1409 set_interval:
1410         DBG("interval %d", interval);
1411
1412         autoscan->interval = interval;
1413
1414         autoscan->timeout = g_timeout_add_seconds(interval,
1415                                                 autoscan_timeout, device);
1416
1417         return FALSE;
1418 }
1419
1420 static void start_autoscan(struct connman_device *device)
1421 {
1422         struct wifi_data *wifi = connman_device_get_data(device);
1423         struct autoscan_params *autoscan;
1424
1425         DBG("");
1426
1427         if (!wifi)
1428                 return;
1429
1430         if (wifi->p2p_device)
1431                 return;
1432
1433         if (wifi->connected)
1434                 return;
1435
1436         autoscan = wifi->autoscan;
1437         if (!autoscan)
1438                 return;
1439
1440         if (autoscan->timeout > 0 || autoscan->interval > 0)
1441                 return;
1442
1443         connman_device_ref(device);
1444
1445         autoscan_timeout(device);
1446 }
1447
1448 static struct autoscan_params *parse_autoscan_params(const char *params)
1449 {
1450         struct autoscan_params *autoscan;
1451         char **list_params;
1452         int limit;
1453         int base;
1454
1455         DBG("Emulating autoscan");
1456
1457         list_params = g_strsplit(params, ":", 0);
1458         if (list_params == 0)
1459                 return NULL;
1460
1461         if (g_strv_length(list_params) < 3) {
1462                 g_strfreev(list_params);
1463                 return NULL;
1464         }
1465
1466         base = atoi(list_params[1]);
1467         limit = atoi(list_params[2]);
1468
1469         g_strfreev(list_params);
1470
1471         autoscan = g_try_malloc0(sizeof(struct autoscan_params));
1472         if (!autoscan) {
1473                 DBG("Could not allocate memory for autoscan");
1474                 return NULL;
1475         }
1476
1477         DBG("base %d - limit %d", base, limit);
1478         autoscan->base = base;
1479         autoscan->limit = limit;
1480
1481         return autoscan;
1482 }
1483
1484 static void setup_autoscan(struct wifi_data *wifi)
1485 {
1486         if (!wifi->autoscan)
1487                 wifi->autoscan = parse_autoscan_params(AUTOSCAN_DEFAULT);
1488
1489         start_autoscan(wifi->device);
1490 }
1491
1492 static void finalize_interface_creation(struct wifi_data *wifi)
1493 {
1494         DBG("interface is ready wifi %p tethering %d", wifi, wifi->tethering);
1495
1496         if (!wifi->device) {
1497                 connman_error("WiFi device not set");
1498                 return;
1499         }
1500
1501         connman_device_set_powered(wifi->device, true);
1502
1503         if (!connman_setting_get_bool("BackgroundScanning"))
1504                 return;
1505
1506         if (wifi->p2p_device)
1507                 return;
1508
1509         setup_autoscan(wifi);
1510 }
1511
1512 static void interface_create_callback(int result,
1513                                         GSupplicantInterface *interface,
1514                                                         void *user_data)
1515 {
1516         struct wifi_data *wifi = user_data;
1517
1518         DBG("result %d ifname %s, wifi %p", result,
1519                                 g_supplicant_interface_get_ifname(interface),
1520                                 wifi);
1521
1522         if (result < 0 || !wifi)
1523                 return;
1524
1525         wifi->interface = interface;
1526         g_supplicant_interface_set_data(interface, wifi);
1527
1528         if (g_supplicant_interface_get_ready(interface)) {
1529                 wifi->interface_ready = true;
1530                 finalize_interface_creation(wifi);
1531         }
1532 }
1533
1534 static int wifi_enable(struct connman_device *device)
1535 {
1536         struct wifi_data *wifi = connman_device_get_data(device);
1537         int index;
1538         char *interface;
1539         const char *driver = connman_option_get_string("wifi");
1540         int ret;
1541
1542         DBG("device %p %p", device, wifi);
1543
1544         index = connman_device_get_index(device);
1545         if (!wifi || index < 0)
1546                 return -ENODEV;
1547
1548         if (is_p2p_connecting())
1549                 return -EINPROGRESS;
1550
1551         interface = connman_inet_ifname(index);
1552         ret = g_supplicant_interface_create(interface, driver, NULL,
1553                                                 interface_create_callback,
1554                                                         wifi);
1555         g_free(interface);
1556
1557         if (ret < 0)
1558                 return ret;
1559
1560         return -EINPROGRESS;
1561 }
1562
1563 static int wifi_disable(struct connman_device *device)
1564 {
1565         struct wifi_data *wifi = connman_device_get_data(device);
1566         int ret;
1567
1568         DBG("device %p wifi %p", device, wifi);
1569
1570         if (!wifi)
1571                 return -ENODEV;
1572
1573         wifi->connected = false;
1574         wifi->disconnecting = false;
1575
1576         if (wifi->pending_network)
1577                 wifi->pending_network = NULL;
1578
1579         stop_autoscan(device);
1580
1581         if (wifi->p2p_find_timeout) {
1582                 g_source_remove(wifi->p2p_find_timeout);
1583                 wifi->p2p_find_timeout = 0;
1584                 connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_P2P, false);
1585                 connman_device_unref(wifi->device);
1586         }
1587
1588         /* In case of a user scan, device is still referenced */
1589         if (connman_device_get_scanning(device)) {
1590                 connman_device_set_scanning(device,
1591                                 CONNMAN_SERVICE_TYPE_WIFI, false);
1592                 connman_device_unref(wifi->device);
1593         }
1594
1595         remove_networks(device, wifi);
1596
1597 #if defined TIZEN_EXT
1598         wifi->scan_pending_network = NULL;
1599
1600         if (is_wifi_notifier_registered == true) {
1601                 connman_notifier_unregister(&notifier);
1602                 is_wifi_notifier_registered = false;
1603         }
1604 #endif
1605
1606         ret = g_supplicant_interface_remove(wifi->interface, NULL, NULL);
1607         if (ret < 0)
1608                 return ret;
1609
1610         return -EINPROGRESS;
1611 }
1612
1613 struct last_connected {
1614         GTimeVal modified;
1615         gchar *ssid;
1616         int freq;
1617 };
1618
1619 static gint sort_entry(gconstpointer a, gconstpointer b, gpointer user_data)
1620 {
1621         GTimeVal *aval = (GTimeVal *)a;
1622         GTimeVal *bval = (GTimeVal *)b;
1623
1624         /* Note that the sort order is descending */
1625         if (aval->tv_sec < bval->tv_sec)
1626                 return 1;
1627
1628         if (aval->tv_sec > bval->tv_sec)
1629                 return -1;
1630
1631         return 0;
1632 }
1633
1634 static void free_entry(gpointer data)
1635 {
1636         struct last_connected *entry = data;
1637
1638         g_free(entry->ssid);
1639         g_free(entry);
1640 }
1641
1642 static int get_latest_connections(int max_ssids,
1643                                 GSupplicantScanParams *scan_data)
1644 {
1645         GSequenceIter *iter;
1646         GSequence *latest_list;
1647         struct last_connected *entry;
1648         GKeyFile *keyfile;
1649         GTimeVal modified;
1650         gchar **services;
1651         gchar *str;
1652         char *ssid;
1653         int i, freq;
1654         int num_ssids = 0;
1655
1656         latest_list = g_sequence_new(free_entry);
1657         if (!latest_list)
1658                 return -ENOMEM;
1659
1660         services = connman_storage_get_services();
1661         for (i = 0; services && services[i]; i++) {
1662                 if (strncmp(services[i], "wifi_", 5) != 0)
1663                         continue;
1664
1665                 keyfile = connman_storage_load_service(services[i]);
1666                 if (!keyfile)
1667                         continue;
1668
1669                 str = g_key_file_get_string(keyfile,
1670                                         services[i], "Favorite", NULL);
1671                 if (!str || g_strcmp0(str, "true")) {
1672                         g_free(str);
1673                         g_key_file_free(keyfile);
1674                         continue;
1675                 }
1676                 g_free(str);
1677
1678                 str = g_key_file_get_string(keyfile,
1679                                         services[i], "AutoConnect", NULL);
1680                 if (!str || g_strcmp0(str, "true")) {
1681                         g_free(str);
1682                         g_key_file_free(keyfile);
1683                         continue;
1684                 }
1685                 g_free(str);
1686
1687                 str = g_key_file_get_string(keyfile,
1688                                         services[i], "Modified", NULL);
1689                 if (!str) {
1690                         g_key_file_free(keyfile);
1691                         continue;
1692                 }
1693                 g_time_val_from_iso8601(str, &modified);
1694                 g_free(str);
1695
1696                 ssid = g_key_file_get_string(keyfile,
1697                                         services[i], "SSID", NULL);
1698
1699                 freq = g_key_file_get_integer(keyfile, services[i],
1700                                         "Frequency", NULL);
1701                 if (freq) {
1702                         entry = g_try_new(struct last_connected, 1);
1703                         if (!entry) {
1704                                 g_sequence_free(latest_list);
1705                                 g_key_file_free(keyfile);
1706                                 g_free(ssid);
1707                                 return -ENOMEM;
1708                         }
1709
1710                         entry->ssid = ssid;
1711                         entry->modified = modified;
1712                         entry->freq = freq;
1713
1714                         g_sequence_insert_sorted(latest_list, entry,
1715                                                 sort_entry, NULL);
1716                         num_ssids++;
1717                 } else
1718                         g_free(ssid);
1719
1720                 g_key_file_free(keyfile);
1721         }
1722
1723         g_strfreev(services);
1724
1725         num_ssids = num_ssids > max_ssids ? max_ssids : num_ssids;
1726
1727         iter = g_sequence_get_begin_iter(latest_list);
1728
1729         for (i = 0; i < num_ssids; i++) {
1730                 entry = g_sequence_get(iter);
1731
1732                 DBG("ssid %s freq %d modified %lu", entry->ssid, entry->freq,
1733                                                 entry->modified.tv_sec);
1734
1735                 add_scan_param(entry->ssid, NULL, 0, entry->freq, scan_data,
1736                                                 max_ssids, entry->ssid);
1737
1738                 iter = g_sequence_iter_next(iter);
1739         }
1740
1741         g_sequence_free(latest_list);
1742         return num_ssids;
1743 }
1744
1745 static int wifi_scan_simple(struct connman_device *device)
1746 {
1747         reset_autoscan(device);
1748
1749         return throw_wifi_scan(device, scan_callback_hidden);
1750 }
1751
1752 static gboolean p2p_find_stop(gpointer data)
1753 {
1754         struct connman_device *device = data;
1755         struct wifi_data *wifi = connman_device_get_data(device);
1756
1757         DBG("");
1758
1759         wifi->p2p_find_timeout = 0;
1760
1761         connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_P2P, false);
1762
1763         g_supplicant_interface_p2p_stop_find(wifi->interface);
1764
1765         connman_device_unref(device);
1766         reset_autoscan(device);
1767
1768         return FALSE;
1769 }
1770
1771 static void p2p_find_callback(int result, GSupplicantInterface *interface,
1772                                                         void *user_data)
1773 {
1774         struct connman_device *device = user_data;
1775         struct wifi_data *wifi = connman_device_get_data(device);
1776
1777         DBG("result %d wifi %p", result, wifi);
1778
1779         if (wifi->p2p_find_timeout) {
1780                 g_source_remove(wifi->p2p_find_timeout);
1781                 wifi->p2p_find_timeout = 0;
1782         }
1783
1784         if (result)
1785                 goto error;
1786
1787         wifi->p2p_find_timeout = g_timeout_add_seconds(P2P_FIND_TIMEOUT,
1788                                                         p2p_find_stop, device);
1789         if (!wifi->p2p_find_timeout)
1790                 goto error;
1791
1792         return;
1793 error:
1794         p2p_find_stop(device);
1795 }
1796
1797 static int p2p_find(struct connman_device *device)
1798 {
1799         struct wifi_data *wifi;
1800         int ret;
1801
1802         DBG("");
1803
1804         if (!p2p_technology)
1805                 return -ENOTSUP;
1806
1807         wifi = connman_device_get_data(device);
1808
1809         if (g_supplicant_interface_is_p2p_finding(wifi->interface))
1810                 return -EALREADY;
1811
1812         reset_autoscan(device);
1813         connman_device_ref(device);
1814
1815         ret = g_supplicant_interface_p2p_find(wifi->interface,
1816                                                 p2p_find_callback, device);
1817         if (ret) {
1818                 connman_device_unref(device);
1819                 start_autoscan(device);
1820         } else {
1821                 connman_device_set_scanning(device,
1822                                 CONNMAN_SERVICE_TYPE_P2P, true);
1823         }
1824
1825         return ret;
1826 }
1827
1828 /*
1829  * Note that the hidden scan is only used when connecting to this specific
1830  * hidden AP first time. It is not used when system autoconnects to hidden AP.
1831  */
1832 static int wifi_scan(enum connman_service_type type,
1833                         struct connman_device *device,
1834                         const char *ssid, unsigned int ssid_len,
1835                         const char *identity, const char* passphrase,
1836                         const char *security, void *user_data)
1837 {
1838         struct wifi_data *wifi = connman_device_get_data(device);
1839         GSupplicantScanParams *scan_params = NULL;
1840         struct scan_ssid *scan_ssid;
1841         struct hidden_params *hidden;
1842         int ret;
1843         int driver_max_ssids = 0;
1844         bool do_hidden;
1845         bool scanning;
1846
1847         if (!wifi)
1848                 return -ENODEV;
1849
1850         if (wifi->p2p_device)
1851                 return 0;
1852
1853         if (type == CONNMAN_SERVICE_TYPE_P2P)
1854                 return p2p_find(device);
1855
1856         DBG("device %p wifi %p hidden ssid %s", device, wifi->interface, ssid);
1857
1858         if (wifi->tethering)
1859                 return 0;
1860
1861         scanning = connman_device_get_scanning(device);
1862
1863         if (!ssid || ssid_len == 0 || ssid_len > 32) {
1864                 if (scanning)
1865                         return -EALREADY;
1866
1867                 driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
1868                                                         wifi->interface);
1869                 DBG("max ssids %d", driver_max_ssids);
1870                 if (driver_max_ssids == 0)
1871                         return wifi_scan_simple(device);
1872
1873                 do_hidden = false;
1874         } else {
1875                 if (scanning && wifi->hidden && wifi->postpone_hidden)
1876                         return -EALREADY;
1877
1878                 do_hidden = true;
1879         }
1880
1881         scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
1882         if (!scan_params)
1883                 return -ENOMEM;
1884
1885         if (do_hidden) {
1886                 scan_ssid = g_try_new(struct scan_ssid, 1);
1887                 if (!scan_ssid) {
1888                         g_free(scan_params);
1889                         return -ENOMEM;
1890                 }
1891
1892                 memcpy(scan_ssid->ssid, ssid, ssid_len);
1893                 scan_ssid->ssid_len = ssid_len;
1894                 scan_params->ssids = g_slist_prepend(scan_params->ssids,
1895                                                                 scan_ssid);
1896                 scan_params->num_ssids = 1;
1897
1898                 hidden = g_try_new0(struct hidden_params, 1);
1899                 if (!hidden) {
1900                         g_supplicant_free_scan_params(scan_params);
1901                         return -ENOMEM;
1902                 }
1903
1904                 if (wifi->hidden) {
1905                         hidden_free(wifi->hidden);
1906                         wifi->hidden = NULL;
1907                 }
1908
1909                 memcpy(hidden->ssid, ssid, ssid_len);
1910                 hidden->ssid_len = ssid_len;
1911                 hidden->identity = g_strdup(identity);
1912                 hidden->passphrase = g_strdup(passphrase);
1913                 hidden->security = g_strdup(security);
1914                 hidden->user_data = user_data;
1915                 wifi->hidden = hidden;
1916
1917                 if (scanning) {
1918                         /* Let's keep this active scan for later,
1919                          * when current scan will be over. */
1920                         wifi->postpone_hidden = TRUE;
1921                         hidden->scan_params = scan_params;
1922
1923                         return 0;
1924                 }
1925         } else if (wifi->connected) {
1926                 g_supplicant_free_scan_params(scan_params);
1927                 return wifi_scan_simple(device);
1928         } else {
1929                 ret = get_latest_connections(driver_max_ssids, scan_params);
1930                 if (ret <= 0) {
1931                         g_supplicant_free_scan_params(scan_params);
1932                         return wifi_scan_simple(device);
1933                 }
1934         }
1935
1936         connman_device_ref(device);
1937
1938 #if defined TIZEN_EXT
1939         /*To allow the Full Scan after ssid based scan, set the flag here
1940      It is required because Tizen does not use the ConnMan specific
1941      backgroung Scan feature.Tizen has added the BG Scan feature in net-config
1942      To sync with up ConnMan, we need to issue the Full Scan after SSID specific scan.*/
1943          wifi->allow_full_scan = TRUE;
1944 #endif
1945         reset_autoscan(device);
1946
1947         ret = g_supplicant_interface_scan(wifi->interface, scan_params,
1948                                                 scan_callback, device);
1949
1950         if (ret == 0) {
1951                 connman_device_set_scanning(device,
1952                                 CONNMAN_SERVICE_TYPE_WIFI, true);
1953         } else {
1954                 g_supplicant_free_scan_params(scan_params);
1955                 connman_device_unref(device);
1956
1957                 if (do_hidden) {
1958                         hidden_free(wifi->hidden);
1959                         wifi->hidden = NULL;
1960                 }
1961         }
1962
1963         return ret;
1964 }
1965
1966 static void wifi_regdom_callback(int result,
1967                                         const char *alpha2,
1968                                                 void *user_data)
1969 {
1970         struct connman_device *device = user_data;
1971
1972         connman_device_regdom_notify(device, result, alpha2);
1973
1974         connman_device_unref(device);
1975 }
1976
1977 static int wifi_set_regdom(struct connman_device *device, const char *alpha2)
1978 {
1979         struct wifi_data *wifi = connman_device_get_data(device);
1980         int ret;
1981
1982         if (!wifi)
1983                 return -EINVAL;
1984
1985         connman_device_ref(device);
1986
1987         ret = g_supplicant_interface_set_country(wifi->interface,
1988                                                 wifi_regdom_callback,
1989                                                         alpha2, device);
1990         if (ret != 0)
1991                 connman_device_unref(device);
1992
1993         return ret;
1994 }
1995
1996 static struct connman_device_driver wifi_ng_driver = {
1997         .name           = "wifi",
1998         .type           = CONNMAN_DEVICE_TYPE_WIFI,
1999         .priority       = CONNMAN_DEVICE_PRIORITY_LOW,
2000         .probe          = wifi_probe,
2001         .remove         = wifi_remove,
2002         .enable         = wifi_enable,
2003         .disable        = wifi_disable,
2004         .scan           = wifi_scan,
2005         .set_regdom     = wifi_set_regdom,
2006 };
2007
2008 static void system_ready(void)
2009 {
2010         DBG("");
2011
2012         if (connman_device_driver_register(&wifi_ng_driver) < 0)
2013                 connman_error("Failed to register WiFi driver");
2014 }
2015
2016 static void system_killed(void)
2017 {
2018         DBG("");
2019
2020         connman_device_driver_unregister(&wifi_ng_driver);
2021 }
2022
2023 static int network_probe(struct connman_network *network)
2024 {
2025         DBG("network %p", network);
2026
2027         return 0;
2028 }
2029
2030 static void network_remove(struct connman_network *network)
2031 {
2032         struct connman_device *device = connman_network_get_device(network);
2033         struct wifi_data *wifi;
2034
2035         DBG("network %p", network);
2036
2037         wifi = connman_device_get_data(device);
2038         if (!wifi)
2039                 return;
2040
2041         if (wifi->network != network)
2042                 return;
2043
2044         wifi->network = NULL;
2045
2046 #if defined TIZEN_EXT
2047         wifi->disconnecting = false;
2048
2049         if (wifi->pending_network == network)
2050                 wifi->pending_network = NULL;
2051
2052         if (wifi->scan_pending_network == network)
2053                 wifi->scan_pending_network = NULL;
2054 #endif
2055 }
2056
2057 static void connect_callback(int result, GSupplicantInterface *interface,
2058                                                         void *user_data)
2059 {
2060 #if defined TIZEN_EXT
2061         GList *list;
2062         struct wifi_data *wifi;
2063 #endif
2064         struct connman_network *network = user_data;
2065
2066         DBG("network %p result %d", network, result);
2067
2068 #if defined TIZEN_EXT
2069         for (list = iface_list; list; list = list->next) {
2070                 wifi = list->data;
2071
2072                 if (wifi && wifi->network == network)
2073                         goto found;
2074         }
2075
2076         /* wifi_data may be invalid because wifi is already disabled */
2077         return;
2078
2079 found:
2080 #endif
2081         if (result == -ENOKEY) {
2082                 connman_network_set_error(network,
2083                                         CONNMAN_NETWORK_ERROR_INVALID_KEY);
2084         } else if (result < 0) {
2085                 connman_network_set_error(network,
2086                                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
2087         }
2088
2089         connman_network_unref(network);
2090 }
2091
2092 static GSupplicantSecurity network_security(const char *security)
2093 {
2094         if (g_str_equal(security, "none"))
2095                 return G_SUPPLICANT_SECURITY_NONE;
2096         else if (g_str_equal(security, "wep"))
2097                 return G_SUPPLICANT_SECURITY_WEP;
2098         else if (g_str_equal(security, "psk"))
2099                 return G_SUPPLICANT_SECURITY_PSK;
2100         else if (g_str_equal(security, "wpa"))
2101                 return G_SUPPLICANT_SECURITY_PSK;
2102         else if (g_str_equal(security, "rsn"))
2103                 return G_SUPPLICANT_SECURITY_PSK;
2104         else if (g_str_equal(security, "ieee8021x"))
2105                 return G_SUPPLICANT_SECURITY_IEEE8021X;
2106 #if defined TIZEN_EXT
2107         else if (g_str_equal(security, "ft_psk") == TRUE)
2108                 return G_SUPPLICANT_SECURITY_FT_PSK;
2109         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
2110                 return G_SUPPLICANT_SECURITY_FT_IEEE8021X;
2111 #endif
2112
2113         return G_SUPPLICANT_SECURITY_UNKNOWN;
2114 }
2115
2116 static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
2117 {
2118         const char *security;
2119
2120         memset(ssid, 0, sizeof(*ssid));
2121         ssid->mode = G_SUPPLICANT_MODE_INFRA;
2122         ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
2123                                                 &ssid->ssid_len);
2124         ssid->scan_ssid = 1;
2125         security = connman_network_get_string(network, "WiFi.Security");
2126         ssid->security = network_security(security);
2127         ssid->passphrase = connman_network_get_string(network,
2128                                                 "WiFi.Passphrase");
2129
2130         ssid->eap = connman_network_get_string(network, "WiFi.EAP");
2131
2132         /*
2133          * If our private key password is unset,
2134          * we use the supplied passphrase. That is needed
2135          * for PEAP where 2 passphrases (identity and client
2136          * cert may have to be provided.
2137          */
2138         if (!connman_network_get_string(network, "WiFi.PrivateKeyPassphrase"))
2139                 connman_network_set_string(network,
2140                                                 "WiFi.PrivateKeyPassphrase",
2141                                                 ssid->passphrase);
2142         /* We must have an identity for both PEAP and TLS */
2143         ssid->identity = connman_network_get_string(network, "WiFi.Identity");
2144
2145         /* Use agent provided identity as a fallback */
2146         if (!ssid->identity || strlen(ssid->identity) == 0)
2147                 ssid->identity = connman_network_get_string(network,
2148                                                         "WiFi.AgentIdentity");
2149
2150         ssid->ca_cert_path = connman_network_get_string(network,
2151                                                         "WiFi.CACertFile");
2152         ssid->client_cert_path = connman_network_get_string(network,
2153                                                         "WiFi.ClientCertFile");
2154         ssid->private_key_path = connman_network_get_string(network,
2155                                                         "WiFi.PrivateKeyFile");
2156         ssid->private_key_passphrase = connman_network_get_string(network,
2157                                                 "WiFi.PrivateKeyPassphrase");
2158         ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
2159
2160         ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS");
2161         ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS");
2162
2163 #if defined TIZEN_EXT
2164         ssid->bssid = connman_network_get_bssid(network);
2165 #endif
2166
2167         if (connman_setting_get_bool("BackgroundScanning"))
2168                 ssid->bgscan = BGSCAN_DEFAULT;
2169 }
2170
2171 static int network_connect(struct connman_network *network)
2172 {
2173         struct connman_device *device = connman_network_get_device(network);
2174         struct wifi_data *wifi;
2175         GSupplicantInterface *interface;
2176         GSupplicantSSID *ssid;
2177
2178         DBG("network %p", network);
2179
2180         if (!device)
2181                 return -ENODEV;
2182
2183         wifi = connman_device_get_data(device);
2184         if (!wifi)
2185                 return -ENODEV;
2186
2187         ssid = g_try_malloc0(sizeof(GSupplicantSSID));
2188         if (!ssid)
2189                 return -ENOMEM;
2190
2191         interface = wifi->interface;
2192
2193         ssid_init(ssid, network);
2194
2195         if (wifi->disconnecting) {
2196                 wifi->pending_network = network;
2197                 g_free(ssid);
2198         } else {
2199                 wifi->network = connman_network_ref(network);
2200                 wifi->retries = 0;
2201 #if defined TIZEN_EXT
2202                 wifi->scan_pending_network = NULL;
2203 #endif
2204
2205                 return g_supplicant_interface_connect(interface, ssid,
2206                                                 connect_callback, network);
2207         }
2208
2209         return -EINPROGRESS;
2210 }
2211
2212 static void disconnect_callback(int result, GSupplicantInterface *interface,
2213                                                                 void *user_data)
2214 {
2215 #if defined TIZEN_EXT
2216         GList *list;
2217         struct wifi_data *wifi;
2218         struct connman_network *network = user_data;
2219
2220         DBG("network %p result %d", network, result);
2221
2222         for (list = iface_list; list; list = list->next) {
2223                 wifi = list->data;
2224
2225                 if (wifi->network == NULL && wifi->disconnecting == true)
2226                         wifi->disconnecting = false;
2227
2228                 if (wifi->network == network)
2229                         goto found;
2230         }
2231
2232         /* wifi_data may be invalid because wifi is already disabled */
2233         return;
2234
2235 found:
2236 #else
2237         struct wifi_data *wifi = user_data;
2238 #endif
2239
2240         DBG("result %d supplicant interface %p wifi %p",
2241                         result, interface, wifi);
2242
2243         if (result == -ECONNABORTED) {
2244                 DBG("wifi interface no longer available");
2245                 return;
2246         }
2247
2248         if (wifi->network) {
2249                 /*
2250                  * if result < 0 supplican return an error because
2251                  * the network is not current.
2252                  * we wont receive G_SUPPLICANT_STATE_DISCONNECTED since it
2253                  * failed, call connman_network_set_connected to report
2254                  * disconnect is completed.
2255                  */
2256                 if (result < 0)
2257                         connman_network_set_connected(wifi->network, false);
2258         }
2259
2260         wifi->network = NULL;
2261
2262         wifi->disconnecting = false;
2263
2264         if (wifi->pending_network) {
2265                 network_connect(wifi->pending_network);
2266                 wifi->pending_network = NULL;
2267         }
2268
2269         start_autoscan(wifi->device);
2270 }
2271
2272 static int network_disconnect(struct connman_network *network)
2273 {
2274         struct connman_device *device = connman_network_get_device(network);
2275         struct wifi_data *wifi;
2276         int err;
2277 #if defined TIZEN_EXT
2278         struct connman_service *service;
2279 #endif
2280
2281         DBG("network %p", network);
2282
2283         wifi = connman_device_get_data(device);
2284         if (!wifi || !wifi->interface)
2285                 return -ENODEV;
2286
2287 #if defined TIZEN_EXT
2288         if (connman_network_get_associating(network) == true) {
2289                 connman_network_clear_associating(network);
2290                 connman_network_set_bool(network, "WiFi.UseWPS", false);
2291         } else {
2292                 service = connman_service_lookup_from_network(network);
2293
2294                 if (service != NULL &&
2295                         (__connman_service_is_connected_state(service,
2296                                         CONNMAN_IPCONFIG_TYPE_IPV4) == false &&
2297                         __connman_service_is_connected_state(service,
2298                                         CONNMAN_IPCONFIG_TYPE_IPV6) == false) &&
2299                         (connman_service_get_favorite(service) == false))
2300                                         __connman_service_set_passphrase(service, NULL);
2301         }
2302
2303         if (wifi->pending_network == network)
2304                 wifi->pending_network = NULL;
2305
2306         if (wifi->scan_pending_network == network)
2307                 wifi->scan_pending_network = NULL;
2308
2309 #endif
2310         connman_network_set_associating(network, false);
2311
2312         if (wifi->disconnecting)
2313                 return -EALREADY;
2314
2315         wifi->disconnecting = true;
2316
2317 #if defined TIZEN_EXT
2318         err = g_supplicant_interface_disconnect(wifi->interface,
2319                                                 disconnect_callback, network);
2320 #else
2321         err = g_supplicant_interface_disconnect(wifi->interface,
2322                                                 disconnect_callback, wifi);
2323 #endif
2324
2325         if (err < 0)
2326                 wifi->disconnecting = false;
2327
2328         return err;
2329 }
2330
2331 static struct connman_network_driver network_driver = {
2332         .name           = "wifi",
2333         .type           = CONNMAN_NETWORK_TYPE_WIFI,
2334         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
2335         .probe          = network_probe,
2336         .remove         = network_remove,
2337         .connect        = network_connect,
2338         .disconnect     = network_disconnect,
2339 };
2340
2341 static void interface_added(GSupplicantInterface *interface)
2342 {
2343         const char *ifname = g_supplicant_interface_get_ifname(interface);
2344         const char *driver = g_supplicant_interface_get_driver(interface);
2345         struct wifi_data *wifi;
2346
2347         wifi = g_supplicant_interface_get_data(interface);
2348         if (!wifi) {
2349                 wifi = get_pending_wifi_data(ifname);
2350                 if (!wifi)
2351                         return;
2352
2353                 g_supplicant_interface_set_data(interface, wifi);
2354                 p2p_iface_list = g_list_append(p2p_iface_list, wifi);
2355                 wifi->p2p_device = true;
2356         }
2357
2358         DBG("ifname %s driver %s wifi %p tethering %d",
2359                         ifname, driver, wifi, wifi->tethering);
2360
2361         if (!wifi->device) {
2362                 connman_error("WiFi device not set");
2363                 return;
2364         }
2365
2366         connman_device_set_powered(wifi->device, true);
2367 }
2368
2369 static bool is_idle(struct wifi_data *wifi)
2370 {
2371         DBG("state %d", wifi->state);
2372
2373         switch (wifi->state) {
2374         case G_SUPPLICANT_STATE_UNKNOWN:
2375         case G_SUPPLICANT_STATE_DISABLED:
2376         case G_SUPPLICANT_STATE_DISCONNECTED:
2377         case G_SUPPLICANT_STATE_INACTIVE:
2378         case G_SUPPLICANT_STATE_SCANNING:
2379                 return true;
2380
2381         case G_SUPPLICANT_STATE_AUTHENTICATING:
2382         case G_SUPPLICANT_STATE_ASSOCIATING:
2383         case G_SUPPLICANT_STATE_ASSOCIATED:
2384         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2385         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2386         case G_SUPPLICANT_STATE_COMPLETED:
2387                 return false;
2388         }
2389
2390         return false;
2391 }
2392
2393 static bool is_idle_wps(GSupplicantInterface *interface,
2394                                                 struct wifi_data *wifi)
2395 {
2396         /* First, let's check if WPS processing did not went wrong */
2397         if (g_supplicant_interface_get_wps_state(interface) ==
2398                 G_SUPPLICANT_WPS_STATE_FAIL)
2399                 return false;
2400
2401         /* Unlike normal connection, being associated while processing wps
2402          * actually means that we are idling. */
2403         switch (wifi->state) {
2404         case G_SUPPLICANT_STATE_UNKNOWN:
2405         case G_SUPPLICANT_STATE_DISABLED:
2406         case G_SUPPLICANT_STATE_DISCONNECTED:
2407         case G_SUPPLICANT_STATE_INACTIVE:
2408         case G_SUPPLICANT_STATE_SCANNING:
2409         case G_SUPPLICANT_STATE_ASSOCIATED:
2410                 return true;
2411         case G_SUPPLICANT_STATE_AUTHENTICATING:
2412         case G_SUPPLICANT_STATE_ASSOCIATING:
2413         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2414         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2415         case G_SUPPLICANT_STATE_COMPLETED:
2416                 return false;
2417         }
2418
2419         return false;
2420 }
2421
2422 static bool handle_wps_completion(GSupplicantInterface *interface,
2423                                         struct connman_network *network,
2424                                         struct connman_device *device,
2425                                         struct wifi_data *wifi)
2426 {
2427         bool wps;
2428
2429         wps = connman_network_get_bool(network, "WiFi.UseWPS");
2430         if (wps) {
2431                 const unsigned char *ssid, *wps_ssid;
2432                 unsigned int ssid_len, wps_ssid_len;
2433                 const char *wps_key;
2434
2435                 /* Checking if we got associated with requested
2436                  * network */
2437                 ssid = connman_network_get_blob(network, "WiFi.SSID",
2438                                                 &ssid_len);
2439
2440                 wps_ssid = g_supplicant_interface_get_wps_ssid(
2441                         interface, &wps_ssid_len);
2442
2443                 if (!wps_ssid || wps_ssid_len != ssid_len ||
2444                                 memcmp(ssid, wps_ssid, ssid_len) != 0) {
2445                         connman_network_set_associating(network, false);
2446 #if defined TIZEN_EXT
2447                         g_supplicant_interface_disconnect(wifi->interface,
2448                                                 disconnect_callback, wifi->network);
2449
2450                         connman_network_set_bool(network, "WiFi.UseWPS", false);
2451                         connman_network_set_string(network, "WiFi.PinWPS", NULL);
2452 #else
2453                         g_supplicant_interface_disconnect(wifi->interface,
2454                                                 disconnect_callback, wifi);
2455 #endif
2456                         return false;
2457                 }
2458
2459                 wps_key = g_supplicant_interface_get_wps_key(interface);
2460                 connman_network_set_string(network, "WiFi.Passphrase",
2461                                         wps_key);
2462
2463                 connman_network_set_string(network, "WiFi.PinWPS", NULL);
2464         }
2465
2466         return true;
2467 }
2468
2469 static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
2470                                         struct connman_network *network,
2471                                         struct wifi_data *wifi)
2472 {
2473 #if defined TIZEN_EXT
2474         const char *security;
2475         struct connman_service *service;
2476
2477         if (wifi->connected)
2478                 return false;
2479
2480         security = connman_network_get_string(network, "WiFi.Security");
2481
2482         if (g_str_equal(security, "ieee8021x") == true &&
2483                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
2484                 wifi->retries = 0;
2485                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
2486
2487                 return false;
2488         }
2489
2490         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
2491                 return false;
2492 #else
2493         struct connman_service *service;
2494
2495         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
2496                 return false;
2497
2498         if (wifi->connected)
2499                 return false;
2500 #endif
2501
2502         service = connman_service_lookup_from_network(network);
2503         if (!service)
2504                 return false;
2505
2506         wifi->retries++;
2507
2508         if (connman_service_get_favorite(service)) {
2509                 if (wifi->retries < FAVORITE_MAXIMUM_RETRIES)
2510                         return true;
2511         }
2512
2513         wifi->retries = 0;
2514         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
2515
2516         return false;
2517 }
2518
2519 #if defined TIZEN_EXT
2520 static bool handle_wifi_assoc_retry(struct connman_network *network,
2521                                         struct wifi_data *wifi)
2522 {
2523         const char *security;
2524
2525         if (!wifi->network || wifi->connected || wifi->disconnecting ||
2526                         connman_network_get_connecting(network) != true) {
2527                 wifi->assoc_retry_count = 0;
2528                 return false;
2529         }
2530
2531         if (wifi->state != G_SUPPLICANT_STATE_ASSOCIATING &&
2532                         wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) {
2533                 wifi->assoc_retry_count = 0;
2534                 return false;
2535         }
2536
2537         security = connman_network_get_string(network, "WiFi.Security");
2538         if (g_str_equal(security, "ieee8021x") == true &&
2539                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
2540                 wifi->assoc_retry_count = 0;
2541                 return false;
2542         }
2543
2544         if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) {
2545                 wifi->assoc_retry_count = 0;
2546
2547                 /* Honestly it's not an invalid-key error,
2548                  * however QA team recommends that the invalid-key error
2549                  * might be better to display for user experience.
2550                  */
2551                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
2552
2553                 return false;
2554         }
2555
2556         return true;
2557 }
2558 #endif
2559
2560 static void interface_state(GSupplicantInterface *interface)
2561 {
2562         struct connman_network *network;
2563         struct connman_device *device;
2564         struct wifi_data *wifi;
2565         GSupplicantState state = g_supplicant_interface_get_state(interface);
2566         bool wps;
2567
2568         wifi = g_supplicant_interface_get_data(interface);
2569
2570         DBG("wifi %p interface state %d", wifi, state);
2571
2572         if (!wifi)
2573                 return;
2574
2575         device = wifi->device;
2576         if (!device)
2577                 return;
2578
2579         if (g_supplicant_interface_get_ready(interface) &&
2580                                         !wifi->interface_ready) {
2581                 wifi->interface_ready = true;
2582                 finalize_interface_creation(wifi);
2583         }
2584
2585         network = wifi->network;
2586         if (!network)
2587                 return;
2588
2589         switch (state) {
2590         case G_SUPPLICANT_STATE_SCANNING:
2591                 break;
2592
2593         case G_SUPPLICANT_STATE_AUTHENTICATING:
2594         case G_SUPPLICANT_STATE_ASSOCIATING:
2595 #if defined TIZEN_EXT
2596                 reset_autoscan(device);
2597 #else
2598                 stop_autoscan(device);
2599 #endif
2600
2601                 if (!wifi->connected)
2602                         connman_network_set_associating(network, true);
2603
2604                 break;
2605
2606         case G_SUPPLICANT_STATE_COMPLETED:
2607 #if defined TIZEN_EXT
2608                 /* though it should be already reset: */
2609                 reset_autoscan(device);
2610
2611                 wifi->assoc_retry_count = 0;
2612
2613                 wifi->scan_pending_network = NULL;
2614 #else
2615                 /* though it should be already stopped: */
2616                 stop_autoscan(device);
2617 #endif
2618
2619                 if (!handle_wps_completion(interface, network, device, wifi))
2620                         break;
2621
2622                 connman_network_set_connected(network, true);
2623                 break;
2624
2625         case G_SUPPLICANT_STATE_DISCONNECTED:
2626                 /*
2627                  * If we're in one of the idle modes, we have
2628                  * not started association yet and thus setting
2629                  * those ones to FALSE could cancel an association
2630                  * in progress.
2631                  */
2632                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
2633                 if (wps)
2634                         if (is_idle_wps(interface, wifi))
2635                                 break;
2636
2637                 if (is_idle(wifi))
2638                         break;
2639
2640                 /* If previous state was 4way-handshake, then
2641                  * it's either: psk was incorrect and thus we retry
2642                  * or if we reach the maximum retries we declare the
2643                  * psk as wrong */
2644                 if (handle_4way_handshake_failure(interface,
2645                                                 network, wifi))
2646                         break;
2647
2648                 /* We disable the selected network, if not then
2649                  * wpa_supplicant will loop retrying */
2650                 if (g_supplicant_interface_enable_selected_network(interface,
2651                                                 FALSE) != 0)
2652                         DBG("Could not disables selected network");
2653
2654 #if defined TIZEN_EXT
2655                 int err;
2656                 int reason_code = 0;
2657
2658                 err = g_supplicant_interface_remove_network(wifi->interface);
2659                 if (err < 0)
2660                         DBG("Failed to remove network(%d)", err);
2661
2662                 reason_code = g_supplicant_interface_get_disconnect_reason(wifi->interface);
2663
2664                 /* Some of Wi-Fi networks are not comply Wi-Fi specification.
2665                  * Retry association until its retry count is expired */
2666                 if (handle_wifi_assoc_retry(network, wifi) == true) {
2667                         throw_wifi_scan(wifi->device, scan_callback);
2668                         wifi->scan_pending_network = wifi->network;
2669                         break;
2670                 }
2671
2672                 if(reason_code > 0){
2673                         DBG("Set disconnect reason code(%d)", reason_code);
2674                         connman_network_set_disconnect_reason(network, reason_code);
2675                 }
2676
2677                 /* To avoid unnecessary repeated association in wpa_supplicant,
2678                  * "RemoveNetwork" should be made when Wi-Fi is disconnected */
2679                 if (wps != true && wifi->network && wifi->disconnecting == false) {
2680                         wifi->disconnecting = true;
2681                         err = g_supplicant_interface_disconnect(wifi->interface,
2682                                                         disconnect_callback, wifi->network);
2683                         if (err < 0)
2684                                 wifi->disconnecting = false;
2685
2686                 connman_network_set_connected(network, false);
2687                 connman_network_set_associating(network, false);
2688
2689                 start_autoscan(device);
2690
2691                 break;
2692                 }
2693 #endif
2694
2695                 connman_network_set_connected(network, false);
2696                 connman_network_set_associating(network, false);
2697                 wifi->disconnecting = false;
2698
2699                 start_autoscan(device);
2700
2701                 break;
2702
2703         case G_SUPPLICANT_STATE_INACTIVE:
2704 #if defined TIZEN_EXT
2705                 if (handle_wps_completion(interface, network, device, wifi) == false)
2706                         break;
2707 #endif
2708                 connman_network_set_associating(network, false);
2709                 start_autoscan(device);
2710
2711                 break;
2712
2713         case G_SUPPLICANT_STATE_UNKNOWN:
2714         case G_SUPPLICANT_STATE_DISABLED:
2715         case G_SUPPLICANT_STATE_ASSOCIATED:
2716         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2717         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2718                 break;
2719         }
2720
2721         wifi->state = state;
2722
2723         /* Saving wpa_s state policy:
2724          * If connected and if the state changes are roaming related:
2725          * --> We stay connected
2726          * If completed
2727          * --> We are connected
2728          * All other case:
2729          * --> We are not connected
2730          * */
2731         switch (state) {
2732 #if defined TIZEN_EXT
2733         case G_SUPPLICANT_STATE_SCANNING:
2734                 break;
2735 #endif
2736         case G_SUPPLICANT_STATE_AUTHENTICATING:
2737         case G_SUPPLICANT_STATE_ASSOCIATING:
2738         case G_SUPPLICANT_STATE_ASSOCIATED:
2739         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2740         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2741                 if (wifi->connected)
2742                         connman_warn("Probably roaming right now!"
2743                                                 " Staying connected...");
2744                 else
2745                         wifi->connected = false;
2746                 break;
2747         case G_SUPPLICANT_STATE_COMPLETED:
2748                 wifi->connected = true;
2749                 break;
2750         default:
2751                 wifi->connected = false;
2752                 break;
2753         }
2754
2755         DBG("DONE");
2756 }
2757
2758 static void interface_removed(GSupplicantInterface *interface)
2759 {
2760         const char *ifname = g_supplicant_interface_get_ifname(interface);
2761         struct wifi_data *wifi;
2762
2763         DBG("ifname %s", ifname);
2764
2765         wifi = g_supplicant_interface_get_data(interface);
2766
2767         if (wifi)
2768                 wifi->interface = NULL;
2769
2770         if (wifi && wifi->tethering)
2771                 return;
2772
2773         if (!wifi || !wifi->device) {
2774                 DBG("wifi interface already removed");
2775                 return;
2776         }
2777
2778         connman_device_set_powered(wifi->device, false);
2779
2780         check_p2p_technology();
2781 }
2782
2783 static void set_device_type(const char *type, char dev_type[17])
2784 {
2785         const char *oui = "0050F204";
2786         const char *category = "0100";
2787         const char *sub_category = "0000";
2788
2789         if (!g_strcmp0(type, "handset")) {
2790                 category = "0A00";
2791                 sub_category = "0500";
2792         } else if (!g_strcmp0(type, "vm") || !g_strcmp0(type, "container"))
2793                 sub_category = "0100";
2794         else if (!g_strcmp0(type, "server"))
2795                 sub_category = "0200";
2796         else if (!g_strcmp0(type, "laptop"))
2797                 sub_category = "0500";
2798         else if (!g_strcmp0(type, "desktop"))
2799                 sub_category = "0600";
2800         else if (!g_strcmp0(type, "tablet"))
2801                 sub_category = "0900";
2802         else if (!g_strcmp0(type, "watch"))
2803                 category = "FF00";
2804
2805         snprintf(dev_type, 17, "%s%s%s", category, oui, sub_category);
2806 }
2807
2808 static void p2p_support(GSupplicantInterface *interface)
2809 {
2810         char dev_type[17] = {};
2811         const char *hostname;
2812
2813         DBG("");
2814
2815         if (!g_supplicant_interface_has_p2p(interface))
2816                 return;
2817
2818         if (connman_technology_driver_register(&p2p_tech_driver) < 0) {
2819                 DBG("Could not register P2P technology driver");
2820                 return;
2821         }
2822
2823         hostname = connman_utsname_get_hostname();
2824         if (!hostname)
2825                 hostname = "ConnMan";
2826
2827         set_device_type(connman_machine_get_type(), dev_type);
2828         g_supplicant_interface_set_p2p_device_config(interface,
2829                                                         hostname, dev_type);
2830         connman_peer_driver_register(&peer_driver);
2831 }
2832
2833 static void scan_started(GSupplicantInterface *interface)
2834 {
2835         DBG("");
2836 }
2837
2838 static void scan_finished(GSupplicantInterface *interface)
2839 {
2840 #if defined TIZEN_EXT
2841         struct wifi_data *wifi;
2842         bool is_associating = false;
2843         static bool is_scanning = true;
2844 #endif
2845
2846         DBG("");
2847
2848 #if defined TIZEN_EXT
2849         wifi = g_supplicant_interface_get_data(interface);
2850         if (wifi && wifi->scan_pending_network) {
2851                 network_connect(wifi->scan_pending_network);
2852                 wifi->scan_pending_network = NULL;
2853         }
2854
2855         //service state - associating
2856         if(!wifi || !wifi->network)
2857                 return;
2858
2859         is_associating = connman_network_get_associating(wifi->network);
2860         if(is_associating && is_scanning){
2861                 is_scanning = false;
2862                 DBG("send scan for connecting");
2863                 throw_wifi_scan(wifi->device, scan_callback);
2864
2865                 return;
2866         }
2867         is_scanning = true;
2868
2869         //go scan
2870
2871 #endif
2872 }
2873
2874 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
2875 {
2876         unsigned char strength;
2877
2878         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
2879         if (strength > 100)
2880                 strength = 100;
2881
2882         return strength;
2883 }
2884
2885 static void network_added(GSupplicantNetwork *supplicant_network)
2886 {
2887         struct connman_network *network;
2888         GSupplicantInterface *interface;
2889         struct wifi_data *wifi;
2890         const char *name, *identifier, *security, *group, *mode;
2891         const unsigned char *ssid;
2892         unsigned int ssid_len;
2893         bool wps;
2894         bool wps_pbc;
2895         bool wps_ready;
2896         bool wps_advertizing;
2897
2898         mode = g_supplicant_network_get_mode(supplicant_network);
2899         identifier = g_supplicant_network_get_identifier(supplicant_network);
2900
2901         DBG("%s", identifier);
2902
2903         if (!g_strcmp0(mode, "adhoc"))
2904                 return;
2905
2906         interface = g_supplicant_network_get_interface(supplicant_network);
2907         wifi = g_supplicant_interface_get_data(interface);
2908         name = g_supplicant_network_get_name(supplicant_network);
2909         security = g_supplicant_network_get_security(supplicant_network);
2910         group = g_supplicant_network_get_identifier(supplicant_network);
2911         wps = g_supplicant_network_get_wps(supplicant_network);
2912         wps_pbc = g_supplicant_network_is_wps_pbc(supplicant_network);
2913         wps_ready = g_supplicant_network_is_wps_active(supplicant_network);
2914         wps_advertizing = g_supplicant_network_is_wps_advertizing(
2915                                                         supplicant_network);
2916
2917         if (!wifi)
2918                 return;
2919
2920         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
2921
2922         network = connman_device_get_network(wifi->device, identifier);
2923
2924         if (!network) {
2925                 network = connman_network_create(identifier,
2926                                                 CONNMAN_NETWORK_TYPE_WIFI);
2927                 if (!network)
2928                         return;
2929
2930                 connman_network_set_index(network, wifi->index);
2931
2932                 if (connman_device_add_network(wifi->device, network) < 0) {
2933                         connman_network_unref(network);
2934                         return;
2935                 }
2936
2937                 wifi->networks = g_slist_prepend(wifi->networks, network);
2938         }
2939
2940         if (name && name[0] != '\0')
2941                 connman_network_set_name(network, name);
2942
2943         connman_network_set_blob(network, "WiFi.SSID",
2944                                                 ssid, ssid_len);
2945         connman_network_set_string(network, "WiFi.Security", security);
2946         connman_network_set_strength(network,
2947                                 calculate_strength(supplicant_network));
2948         connman_network_set_bool(network, "WiFi.WPS", wps);
2949
2950         if (wps) {
2951                 /* Is AP advertizing for WPS association?
2952                  * If so, we decide to use WPS by default */
2953                 if (wps_ready && wps_pbc &&
2954                                                 wps_advertizing) {
2955 #if !defined TIZEN_EXT
2956                         connman_network_set_bool(network, "WiFi.UseWPS", true);
2957 #else
2958                         DBG("wps is activating by ap but ignore it.");
2959 #endif
2960                 }
2961         }
2962
2963         connman_network_set_frequency(network,
2964                         g_supplicant_network_get_frequency(supplicant_network));
2965 #if defined TIZEN_EXT
2966         connman_network_set_bssid(network,
2967                         g_supplicant_network_get_bssid(supplicant_network));
2968         connman_network_set_maxrate(network,
2969                         g_supplicant_network_get_maxrate(supplicant_network));
2970         connman_network_set_enc_mode(network,
2971                         g_supplicant_network_get_enc_mode(supplicant_network));
2972         connman_network_set_rsn_mode(network,
2973                         g_supplicant_network_get_rsn_mode(supplicant_network));
2974         connman_network_set_keymgmt(network,
2975                         g_supplicant_network_get_keymgmt(supplicant_network));
2976 #endif
2977         connman_network_set_available(network, true);
2978         connman_network_set_string(network, "WiFi.Mode", mode);
2979
2980 #if defined TIZEN_EXT
2981         if (group)
2982 #else
2983         if (ssid)
2984 #endif
2985                 connman_network_set_group(network, group);
2986
2987 #if defined TIZEN_EXT
2988         if (wifi_first_scan == true)
2989                 found_with_first_scan = true;
2990 #endif
2991
2992         if (wifi->hidden && ssid) {
2993 #if defined TIZEN_EXT
2994                 if (network_security(wifi->hidden->security) ==
2995                         network_security(security) &&
2996 #else
2997                 if (!g_strcmp0(wifi->hidden->security, security) &&
2998 #endif
2999                                 wifi->hidden->ssid_len == ssid_len &&
3000                                 !memcmp(wifi->hidden->ssid, ssid, ssid_len)) {
3001                         connman_network_connect_hidden(network,
3002                                         wifi->hidden->identity,
3003                                         wifi->hidden->passphrase,
3004                                         wifi->hidden->user_data);
3005                         wifi->hidden->user_data = NULL;
3006                         hidden_free(wifi->hidden);
3007                         wifi->hidden = NULL;
3008                 }
3009         }
3010 }
3011
3012 static void network_removed(GSupplicantNetwork *network)
3013 {
3014         GSupplicantInterface *interface;
3015         struct wifi_data *wifi;
3016         const char *name, *identifier;
3017         struct connman_network *connman_network;
3018
3019         interface = g_supplicant_network_get_interface(network);
3020         wifi = g_supplicant_interface_get_data(interface);
3021         identifier = g_supplicant_network_get_identifier(network);
3022         name = g_supplicant_network_get_name(network);
3023
3024         DBG("name %s", name);
3025
3026         if (!wifi)
3027                 return;
3028
3029         connman_network = connman_device_get_network(wifi->device, identifier);
3030         if (!connman_network)
3031                 return;
3032
3033 #if defined TIZEN_EXT
3034         if (connman_network == wifi->scan_pending_network)
3035                 wifi->scan_pending_network = NULL;
3036
3037         if (connman_network == wifi->pending_network)
3038                 wifi->pending_network = NULL;
3039
3040         if(connman_network_get_connecting(connman_network) == true){
3041                 connman_network_set_connected(connman_network, false);
3042         }
3043 #endif
3044
3045         wifi->networks = g_slist_remove(wifi->networks, connman_network);
3046
3047         connman_device_remove_network(wifi->device, connman_network);
3048         connman_network_unref(connman_network);
3049 }
3050
3051 static void network_changed(GSupplicantNetwork *network, const char *property)
3052 {
3053         GSupplicantInterface *interface;
3054         struct wifi_data *wifi;
3055         const char *name, *identifier;
3056         struct connman_network *connman_network;
3057
3058 #if defined TIZEN_EXT
3059         const unsigned char *bssid;
3060         unsigned int maxrate;
3061         uint16_t frequency;
3062         bool wps;
3063 #endif
3064
3065         interface = g_supplicant_network_get_interface(network);
3066         wifi = g_supplicant_interface_get_data(interface);
3067         identifier = g_supplicant_network_get_identifier(network);
3068         name = g_supplicant_network_get_name(network);
3069
3070         DBG("name %s", name);
3071
3072         if (!wifi)
3073                 return;
3074
3075         connman_network = connman_device_get_network(wifi->device, identifier);
3076         if (!connman_network)
3077                 return;
3078
3079         if (g_str_equal(property, "Signal")) {
3080                connman_network_set_strength(connman_network,
3081                                         calculate_strength(network));
3082                connman_network_update(connman_network);
3083         }
3084
3085 #if defined TIZEN_EXT
3086         bssid = g_supplicant_network_get_bssid(network);
3087         maxrate = g_supplicant_network_get_maxrate(network);
3088         frequency = g_supplicant_network_get_frequency(network);
3089         wps = g_supplicant_network_get_wps(network);
3090
3091         connman_network_set_bssid(connman_network, bssid);
3092         connman_network_set_maxrate(connman_network, maxrate);
3093         connman_network_set_frequency(connman_network, frequency);
3094         connman_network_set_bool(connman_network, "WiFi.WPS", wps);
3095 #endif
3096 }
3097
3098 static void apply_peer_services(GSupplicantPeer *peer,
3099                                 struct connman_peer *connman_peer)
3100 {
3101         const unsigned char *data;
3102         int length;
3103
3104         DBG("");
3105
3106         connman_peer_reset_services(connman_peer);
3107
3108         data = g_supplicant_peer_get_widi_ies(peer, &length);
3109         if (data) {
3110                 connman_peer_add_service(connman_peer,
3111                         CONNMAN_PEER_SERVICE_WIFI_DISPLAY, data, length);
3112         }
3113 }
3114
3115 static void add_station(const char *mac)
3116 {
3117         connman_technology_tethering_add_station(CONNMAN_SERVICE_TYPE_WIFI,
3118                                                  mac);
3119 }
3120
3121 static void remove_station(const char *mac)
3122 {
3123         connman_technology_tethering_remove_station(mac);
3124 }
3125
3126 static void peer_found(GSupplicantPeer *peer)
3127 {
3128         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3129         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3130         struct connman_peer *connman_peer;
3131         const char *identifier, *name;
3132         int ret;
3133
3134         identifier = g_supplicant_peer_get_identifier(peer);
3135         name = g_supplicant_peer_get_name(peer);
3136
3137         DBG("ident: %s", identifier);
3138
3139         connman_peer = connman_peer_get(wifi->device, identifier);
3140         if (connman_peer)
3141                 return;
3142
3143         connman_peer = connman_peer_create(identifier);
3144         connman_peer_set_name(connman_peer, name);
3145         connman_peer_set_device(connman_peer, wifi->device);
3146         apply_peer_services(peer, connman_peer);
3147
3148         ret = connman_peer_register(connman_peer);
3149         if (ret < 0 && ret != -EALREADY)
3150                 connman_peer_unref(connman_peer);
3151 }
3152
3153 static void peer_lost(GSupplicantPeer *peer)
3154 {
3155         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3156         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3157         struct connman_peer *connman_peer;
3158         const char *identifier;
3159
3160         if (!wifi)
3161                 return;
3162
3163         identifier = g_supplicant_peer_get_identifier(peer);
3164
3165         DBG("ident: %s", identifier);
3166
3167         connman_peer = connman_peer_get(wifi->device, identifier);
3168         if (connman_peer) {
3169                 if (wifi->p2p_connecting &&
3170                                 wifi->pending_peer == connman_peer) {
3171                         peer_connect_timeout(wifi);
3172                 }
3173                 connman_peer_unregister(connman_peer);
3174                 connman_peer_unref(connman_peer);
3175         }
3176 }
3177
3178 static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state)
3179 {
3180         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3181         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3182         enum connman_peer_state p_state = CONNMAN_PEER_STATE_UNKNOWN;
3183         struct connman_peer *connman_peer;
3184         const char *identifier;
3185
3186         identifier = g_supplicant_peer_get_identifier(peer);
3187
3188         DBG("ident: %s", identifier);
3189
3190         connman_peer = connman_peer_get(wifi->device, identifier);
3191         if (!connman_peer)
3192                 return;
3193
3194         switch (state) {
3195         case G_SUPPLICANT_PEER_SERVICES_CHANGED:
3196                 apply_peer_services(peer, connman_peer);
3197                 connman_peer_services_changed(connman_peer);
3198                 return;
3199         case G_SUPPLICANT_PEER_GROUP_CHANGED:
3200                 if (!g_supplicant_peer_is_in_a_group(peer))
3201                         p_state = CONNMAN_PEER_STATE_IDLE;
3202                 else
3203                         p_state = CONNMAN_PEER_STATE_CONFIGURATION;
3204                 break;
3205         case G_SUPPLICANT_PEER_GROUP_STARTED:
3206                 break;
3207         case G_SUPPLICANT_PEER_GROUP_FINISHED:
3208                 p_state = CONNMAN_PEER_STATE_IDLE;
3209                 break;
3210         case G_SUPPLICANT_PEER_GROUP_JOINED:
3211                 connman_peer_set_iface_address(connman_peer,
3212                                 g_supplicant_peer_get_iface_address(peer));
3213                 break;
3214         case G_SUPPLICANT_PEER_GROUP_DISCONNECTED:
3215                 p_state = CONNMAN_PEER_STATE_IDLE;
3216                 break;
3217         case G_SUPPLICANT_PEER_GROUP_FAILED:
3218                 if (g_supplicant_peer_has_requested_connection(peer))
3219                         p_state = CONNMAN_PEER_STATE_IDLE;
3220                 else
3221                         p_state = CONNMAN_PEER_STATE_FAILURE;
3222                 break;
3223         }
3224
3225         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION ||
3226                                         p_state == CONNMAN_PEER_STATE_FAILURE) {
3227                 if (wifi->p2p_connecting
3228                                 && connman_peer == wifi->pending_peer)
3229                         peer_cancel_timeout(wifi);
3230                 else
3231                         p_state = CONNMAN_PEER_STATE_UNKNOWN;
3232         }
3233
3234         if (p_state == CONNMAN_PEER_STATE_UNKNOWN)
3235                 return;
3236
3237         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION) {
3238                 GSupplicantInterface *g_iface;
3239                 struct wifi_data *g_wifi;
3240
3241                 g_iface = g_supplicant_peer_get_group_interface(peer);
3242                 if (!g_iface)
3243                         return;
3244
3245                 g_wifi = g_supplicant_interface_get_data(g_iface);
3246                 if (!g_wifi)
3247                         return;
3248
3249                 connman_peer_set_as_master(connman_peer,
3250                                         !g_supplicant_peer_is_client(peer));
3251                 connman_peer_set_sub_device(connman_peer, g_wifi->device);
3252         }
3253
3254         connman_peer_set_state(connman_peer, p_state);
3255 }
3256
3257 static void peer_request(GSupplicantPeer *peer)
3258 {
3259         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3260         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3261         struct connman_peer *connman_peer;
3262         const char *identifier;
3263
3264         identifier = g_supplicant_peer_get_identifier(peer);
3265
3266         DBG("ident: %s", identifier);
3267
3268         connman_peer = connman_peer_get(wifi->device, identifier);
3269         if (!connman_peer)
3270                 return;
3271
3272         connman_peer_request_connection(connman_peer);
3273 }
3274
3275 #if defined TIZEN_EXT
3276 static void system_power_off(void)
3277 {
3278         GList *list;
3279         struct wifi_data *wifi;
3280         struct connman_service *service;
3281         struct connman_ipconfig *ipconfig_ipv4;
3282
3283         if (connman_setting_get_bool("WiFiDHCPRelease") == true) {
3284                 for (list = iface_list; list; list = list->next) {
3285                         wifi = list->data;
3286
3287                         if (wifi->network != NULL) {
3288                                 service = connman_service_lookup_from_network(wifi->network);
3289                                 ipconfig_ipv4 = __connman_service_get_ip4config(service);
3290                                 __connman_dhcp_stop(ipconfig_ipv4);
3291                         }
3292                 }
3293         }
3294 }
3295
3296 static void network_merged(GSupplicantNetwork *network)
3297 {
3298         GSupplicantInterface *interface;
3299         GSupplicantState state;
3300         struct wifi_data *wifi;
3301         const char *identifier;
3302         struct connman_network *connman_network;
3303         unsigned int ishs20AP = 0;
3304         char *temp = NULL;
3305
3306         interface = g_supplicant_network_get_interface(network);
3307         if (!interface)
3308                 return;
3309
3310         state = g_supplicant_interface_get_state(interface);
3311         if (state < G_SUPPLICANT_STATE_AUTHENTICATING)
3312                 return;
3313
3314         wifi = g_supplicant_interface_get_data(interface);
3315         if (!wifi)
3316                 return;
3317
3318         identifier = g_supplicant_network_get_identifier(network);
3319
3320         connman_network = connman_device_get_network(wifi->device, identifier);
3321         if (!connman_network)
3322                 return;
3323
3324         DBG("merged identifier %s", identifier);
3325
3326         if (wifi->connected == FALSE) {
3327                 switch (state) {
3328                 case G_SUPPLICANT_STATE_AUTHENTICATING:
3329                 case G_SUPPLICANT_STATE_ASSOCIATING:
3330                 case G_SUPPLICANT_STATE_ASSOCIATED:
3331                 case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3332                 case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3333                         connman_network_set_associating(connman_network, TRUE);
3334                         break;
3335                 case G_SUPPLICANT_STATE_COMPLETED:
3336                         connman_network_set_connected(connman_network, TRUE);
3337                         break;
3338                 default:
3339                         DBG("Not handled the state : %d", state);
3340                         break;
3341                 }
3342         }
3343
3344         ishs20AP = g_supplicant_network_is_hs20AP(network);
3345         connman_network_set_is_hs20AP(connman_network, ishs20AP);
3346
3347         if (ishs20AP &&
3348                 g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) {
3349                 temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1);
3350                 connman_network_set_string(connman_network, "WiFi.EAP",
3351                                 temp);
3352                 connman_network_set_string(connman_network, "WiFi.Identity",
3353                                 g_supplicant_network_get_identity(network));
3354                 connman_network_set_string(connman_network, "WiFi.Phase2",
3355                                 g_supplicant_network_get_phase2(network));
3356
3357                 g_free(temp);
3358         }
3359
3360         wifi->network = connman_network;
3361 }
3362 #endif
3363
3364 static void debug(const char *str)
3365 {
3366         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
3367                 connman_debug("%s", str);
3368 }
3369
3370 static const GSupplicantCallbacks callbacks = {
3371         .system_ready           = system_ready,
3372         .system_killed          = system_killed,
3373         .interface_added        = interface_added,
3374         .interface_state        = interface_state,
3375         .interface_removed      = interface_removed,
3376         .p2p_support            = p2p_support,
3377         .scan_started           = scan_started,
3378         .scan_finished          = scan_finished,
3379         .network_added          = network_added,
3380         .network_removed        = network_removed,
3381         .network_changed        = network_changed,
3382         .add_station            = add_station,
3383         .remove_station         = remove_station,
3384         .peer_found             = peer_found,
3385         .peer_lost              = peer_lost,
3386         .peer_changed           = peer_changed,
3387         .peer_request           = peer_request,
3388 #if defined TIZEN_EXT
3389         .system_power_off       = system_power_off,
3390         .network_merged = network_merged,
3391 #endif
3392         .debug                  = debug,
3393 };
3394
3395
3396 static int tech_probe(struct connman_technology *technology)
3397 {
3398         wifi_technology = technology;
3399
3400         return 0;
3401 }
3402
3403 static void tech_remove(struct connman_technology *technology)
3404 {
3405         wifi_technology = NULL;
3406 }
3407
3408 struct wifi_tethering_info {
3409         struct wifi_data *wifi;
3410         struct connman_technology *technology;
3411         char *ifname;
3412         GSupplicantSSID *ssid;
3413 };
3414
3415 static GSupplicantSSID *ssid_ap_init(const char *ssid,
3416                 const char *passphrase, bool hidden)
3417 {
3418         GSupplicantSSID *ap;
3419
3420         ap = g_try_malloc0(sizeof(GSupplicantSSID));
3421         if (!ap)
3422                 return NULL;
3423
3424         ap->mode = G_SUPPLICANT_MODE_MASTER;
3425         ap->ssid = ssid;
3426         ap->ssid_len = strlen(ssid);
3427         ap->scan_ssid = 0;
3428         ap->freq = 2412;
3429
3430         if (!passphrase || strlen(passphrase) == 0) {
3431                 ap->security = G_SUPPLICANT_SECURITY_NONE;
3432                 ap->passphrase = NULL;
3433         } else {
3434                ap->security = G_SUPPLICANT_SECURITY_PSK;
3435                ap->protocol = G_SUPPLICANT_PROTO_RSN;
3436                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
3437                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
3438                ap->passphrase = passphrase;
3439         }
3440
3441         if (hidden)
3442                 ap->ignore_broadcast_ssid =
3443                                 G_SUPPLICANT_AP_HIDDEN_SSID_ZERO_CONTENTS;
3444         else
3445                 ap->ignore_broadcast_ssid = G_SUPPLICANT_AP_NO_SSID_HIDING;
3446
3447         return ap;
3448 }
3449
3450 static void ap_start_callback(int result, GSupplicantInterface *interface,
3451                                                         void *user_data)
3452 {
3453         struct wifi_tethering_info *info = user_data;
3454
3455         DBG("result %d index %d bridge %s",
3456                 result, info->wifi->index, info->wifi->bridge);
3457
3458         if (result < 0) {
3459                 connman_inet_remove_from_bridge(info->wifi->index,
3460                                                         info->wifi->bridge);
3461                 connman_technology_tethering_notify(info->technology, false);
3462         }
3463
3464         g_free(info->ifname);
3465         g_free(info);
3466 }
3467
3468 static void ap_create_callback(int result,
3469                                 GSupplicantInterface *interface,
3470                                         void *user_data)
3471 {
3472         struct wifi_tethering_info *info = user_data;
3473
3474         DBG("result %d ifname %s", result,
3475                                 g_supplicant_interface_get_ifname(interface));
3476
3477         if (result < 0) {
3478                 connman_inet_remove_from_bridge(info->wifi->index,
3479                                                         info->wifi->bridge);
3480                 connman_technology_tethering_notify(info->technology, false);
3481
3482                 g_free(info->ifname);
3483                 g_free(info->ssid);
3484                 g_free(info);
3485                 return;
3486         }
3487
3488         info->wifi->interface = interface;
3489         g_supplicant_interface_set_data(interface, info->wifi);
3490
3491         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
3492                 connman_error("Failed to set interface ap_scan property");
3493
3494         g_supplicant_interface_connect(interface, info->ssid,
3495                                                 ap_start_callback, info);
3496 }
3497
3498 static void sta_remove_callback(int result,
3499                                 GSupplicantInterface *interface,
3500                                         void *user_data)
3501 {
3502         struct wifi_tethering_info *info = user_data;
3503         const char *driver = connman_option_get_string("wifi");
3504
3505         DBG("ifname %s result %d ", info->ifname, result);
3506
3507         if (result < 0) {
3508                 info->wifi->tethering = true;
3509
3510                 g_free(info->ifname);
3511                 g_free(info->ssid);
3512                 g_free(info);
3513                 return;
3514         }
3515
3516         info->wifi->interface = NULL;
3517
3518         connman_technology_tethering_notify(info->technology, true);
3519
3520         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
3521                                                 ap_create_callback,
3522                                                         info);
3523 }
3524
3525 static int tech_set_tethering(struct connman_technology *technology,
3526                                 const char *identifier, const char *passphrase,
3527                                 const char *bridge, bool enabled, bool hidden)
3528 {
3529         GList *list;
3530         GSupplicantInterface *interface;
3531         struct wifi_data *wifi;
3532         struct wifi_tethering_info *info;
3533         const char *ifname;
3534         unsigned int mode;
3535         int err;
3536
3537         DBG("");
3538
3539         if (!enabled) {
3540                 for (list = iface_list; list; list = list->next) {
3541                         wifi = list->data;
3542
3543                         if (wifi->tethering) {
3544                                 wifi->tethering = false;
3545
3546                                 connman_inet_remove_from_bridge(wifi->index,
3547                                                                         bridge);
3548                                 wifi->bridged = false;
3549                         }
3550                 }
3551
3552                 connman_technology_tethering_notify(technology, false);
3553
3554                 return 0;
3555         }
3556
3557         for (list = iface_list; list; list = list->next) {
3558                 wifi = list->data;
3559
3560                 interface = wifi->interface;
3561
3562                 if (!interface)
3563                         continue;
3564
3565                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
3566
3567                 mode = g_supplicant_interface_get_mode(interface);
3568                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
3569                         DBG("%s does not support AP mode", ifname);
3570                         continue;
3571                 }
3572
3573                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
3574                 if (!info)
3575                         return -ENOMEM;
3576
3577                 info->wifi = wifi;
3578                 info->technology = technology;
3579                 info->wifi->bridge = bridge;
3580                 info->ssid = ssid_ap_init(identifier, passphrase, hidden);
3581                 if (!info->ssid) {
3582                         g_free(info);
3583                         continue;
3584                 }
3585                 info->ifname = g_strdup(ifname);
3586                 if (!info->ifname) {
3587                         g_free(info->ssid);
3588                         g_free(info);
3589                         continue;
3590                 }
3591
3592                 info->wifi->tethering = true;
3593
3594                 err = g_supplicant_interface_remove(interface,
3595                                                 sta_remove_callback,
3596                                                         info);
3597                 if (err == 0)
3598                         return err;
3599         }
3600
3601         return -EOPNOTSUPP;
3602 }
3603
3604 static void regdom_callback(int result, const char *alpha2, void *user_data)
3605 {
3606         DBG("");
3607
3608         if (!wifi_technology)
3609                 return;
3610
3611         if (result != 0)
3612                 alpha2 = NULL;
3613
3614         connman_technology_regdom_notify(wifi_technology, alpha2);
3615 }
3616
3617 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
3618 {
3619         return g_supplicant_set_country(alpha2, regdom_callback, NULL);
3620 }
3621
3622 static struct connman_technology_driver tech_driver = {
3623         .name           = "wifi",
3624         .type           = CONNMAN_SERVICE_TYPE_WIFI,
3625         .probe          = tech_probe,
3626         .remove         = tech_remove,
3627         .set_tethering  = tech_set_tethering,
3628         .set_regdom     = tech_set_regdom,
3629 };
3630
3631 static int wifi_init(void)
3632 {
3633         int err;
3634
3635         err = connman_network_driver_register(&network_driver);
3636         if (err < 0)
3637                 return err;
3638
3639         err = g_supplicant_register(&callbacks);
3640         if (err < 0) {
3641                 connman_network_driver_unregister(&network_driver);
3642                 return err;
3643         }
3644
3645         err = connman_technology_driver_register(&tech_driver);
3646         if (err < 0) {
3647                 g_supplicant_unregister(&callbacks);
3648                 connman_network_driver_unregister(&network_driver);
3649                 return err;
3650         }
3651
3652         return 0;
3653 }
3654
3655 static void wifi_exit(void)
3656 {
3657         DBG();
3658
3659         connman_technology_driver_unregister(&tech_driver);
3660
3661         g_supplicant_unregister(&callbacks);
3662
3663         connman_network_driver_unregister(&network_driver);
3664 }
3665
3666 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
3667                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)