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