[connman]:Fixed Double Scan Indication Event
[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->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 #else
2620                 /* though it should be already stopped: */
2621                 stop_autoscan(device);
2622 #endif
2623
2624                 if (!handle_wps_completion(interface, network, device, wifi))
2625                         break;
2626
2627                 connman_network_set_connected(network, true);
2628                 break;
2629
2630         case G_SUPPLICANT_STATE_DISCONNECTED:
2631                 /*
2632                  * If we're in one of the idle modes, we have
2633                  * not started association yet and thus setting
2634                  * those ones to FALSE could cancel an association
2635                  * in progress.
2636                  */
2637                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
2638                 if (wps)
2639                         if (is_idle_wps(interface, wifi))
2640                                 break;
2641
2642                 if (is_idle(wifi))
2643                         break;
2644
2645                 /* If previous state was 4way-handshake, then
2646                  * it's either: psk was incorrect and thus we retry
2647                  * or if we reach the maximum retries we declare the
2648                  * psk as wrong */
2649                 if (handle_4way_handshake_failure(interface,
2650                                                 network, wifi))
2651                         break;
2652
2653                 /* We disable the selected network, if not then
2654                  * wpa_supplicant will loop retrying */
2655                 if (g_supplicant_interface_enable_selected_network(interface,
2656                                                 FALSE) != 0)
2657                         DBG("Could not disables selected network");
2658
2659 #if defined TIZEN_EXT
2660                 int err;
2661                 int reason_code = 0;
2662
2663                 err = g_supplicant_interface_remove_network(wifi->interface);
2664                 if (err < 0)
2665                         DBG("Failed to remove network(%d)", err);
2666
2667                 reason_code = g_supplicant_interface_get_disconnect_reason(wifi->interface);
2668
2669                 /* Some of Wi-Fi networks are not comply Wi-Fi specification.
2670                  * Retry association until its retry count is expired */
2671                 if (handle_wifi_assoc_retry(network, wifi) == true) {
2672                         throw_wifi_scan(wifi->device, scan_callback);
2673                         wifi->scan_pending_network = wifi->network;
2674                         break;
2675                 }
2676
2677                 if(reason_code > 0){
2678                         DBG("Set disconnect reason code(%d)", reason_code);
2679                         connman_network_set_disconnect_reason(network, reason_code);
2680                 }
2681
2682                 /* To avoid unnecessary repeated association in wpa_supplicant,
2683                  * "RemoveNetwork" should be made when Wi-Fi is disconnected */
2684                 if (wps != true && wifi->network && wifi->disconnecting == false) {
2685                         wifi->disconnecting = true;
2686                         err = g_supplicant_interface_disconnect(wifi->interface,
2687                                                         disconnect_callback, wifi->network);
2688                         if (err < 0)
2689                                 wifi->disconnecting = false;
2690
2691                 connman_network_set_connected(network, false);
2692                 connman_network_set_associating(network, false);
2693
2694                 start_autoscan(device);
2695
2696                 break;
2697                 }
2698 #endif
2699
2700                 connman_network_set_connected(network, false);
2701                 connman_network_set_associating(network, false);
2702                 wifi->disconnecting = false;
2703
2704                 start_autoscan(device);
2705
2706                 break;
2707
2708         case G_SUPPLICANT_STATE_INACTIVE:
2709 #if defined TIZEN_EXT
2710                 if (handle_wps_completion(interface, network, device, wifi) == false)
2711                         break;
2712 #endif
2713                 connman_network_set_associating(network, false);
2714                 start_autoscan(device);
2715
2716                 break;
2717
2718         case G_SUPPLICANT_STATE_UNKNOWN:
2719         case G_SUPPLICANT_STATE_DISABLED:
2720         case G_SUPPLICANT_STATE_ASSOCIATED:
2721         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2722         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2723                 break;
2724         }
2725
2726         wifi->state = state;
2727
2728         /* Saving wpa_s state policy:
2729          * If connected and if the state changes are roaming related:
2730          * --> We stay connected
2731          * If completed
2732          * --> We are connected
2733          * All other case:
2734          * --> We are not connected
2735          * */
2736         switch (state) {
2737 #if defined TIZEN_EXT
2738         case G_SUPPLICANT_STATE_SCANNING:
2739                 break;
2740 #endif
2741         case G_SUPPLICANT_STATE_AUTHENTICATING:
2742         case G_SUPPLICANT_STATE_ASSOCIATING:
2743         case G_SUPPLICANT_STATE_ASSOCIATED:
2744         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2745         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2746                 if (wifi->connected)
2747                         connman_warn("Probably roaming right now!"
2748                                                 " Staying connected...");
2749                 else
2750                         wifi->connected = false;
2751                 break;
2752         case G_SUPPLICANT_STATE_COMPLETED:
2753                 wifi->connected = true;
2754                 break;
2755         default:
2756                 wifi->connected = false;
2757                 break;
2758         }
2759
2760         DBG("DONE");
2761 }
2762
2763 static void interface_removed(GSupplicantInterface *interface)
2764 {
2765         const char *ifname = g_supplicant_interface_get_ifname(interface);
2766         struct wifi_data *wifi;
2767
2768         DBG("ifname %s", ifname);
2769
2770         wifi = g_supplicant_interface_get_data(interface);
2771
2772         if (wifi)
2773                 wifi->interface = NULL;
2774
2775         if (wifi && wifi->tethering)
2776                 return;
2777
2778         if (!wifi || !wifi->device) {
2779                 DBG("wifi interface already removed");
2780                 return;
2781         }
2782
2783         connman_device_set_powered(wifi->device, false);
2784
2785         check_p2p_technology();
2786 }
2787
2788 static void set_device_type(const char *type, char dev_type[17])
2789 {
2790         const char *oui = "0050F204";
2791         const char *category = "0100";
2792         const char *sub_category = "0000";
2793
2794         if (!g_strcmp0(type, "handset")) {
2795                 category = "0A00";
2796                 sub_category = "0500";
2797         } else if (!g_strcmp0(type, "vm") || !g_strcmp0(type, "container"))
2798                 sub_category = "0100";
2799         else if (!g_strcmp0(type, "server"))
2800                 sub_category = "0200";
2801         else if (!g_strcmp0(type, "laptop"))
2802                 sub_category = "0500";
2803         else if (!g_strcmp0(type, "desktop"))
2804                 sub_category = "0600";
2805         else if (!g_strcmp0(type, "tablet"))
2806                 sub_category = "0900";
2807         else if (!g_strcmp0(type, "watch"))
2808                 category = "FF00";
2809
2810         snprintf(dev_type, 17, "%s%s%s", category, oui, sub_category);
2811 }
2812
2813 static void p2p_support(GSupplicantInterface *interface)
2814 {
2815         char dev_type[17] = {};
2816         const char *hostname;
2817
2818         DBG("");
2819
2820         if (!g_supplicant_interface_has_p2p(interface))
2821                 return;
2822
2823         if (connman_technology_driver_register(&p2p_tech_driver) < 0) {
2824                 DBG("Could not register P2P technology driver");
2825                 return;
2826         }
2827
2828         hostname = connman_utsname_get_hostname();
2829         if (!hostname)
2830                 hostname = "ConnMan";
2831
2832         set_device_type(connman_machine_get_type(), dev_type);
2833         g_supplicant_interface_set_p2p_device_config(interface,
2834                                                         hostname, dev_type);
2835         connman_peer_driver_register(&peer_driver);
2836 }
2837
2838 static void scan_started(GSupplicantInterface *interface)
2839 {
2840         DBG("");
2841 }
2842
2843 static void scan_finished(GSupplicantInterface *interface)
2844 {
2845 #if defined TIZEN_EXT
2846         struct wifi_data *wifi;
2847         bool is_associating = false;
2848         static bool is_scanning = true;
2849 #endif
2850
2851         DBG("");
2852
2853 #if defined TIZEN_EXT
2854         wifi = g_supplicant_interface_get_data(interface);
2855         if (wifi && wifi->scan_pending_network) {
2856                 network_connect(wifi->scan_pending_network);
2857                 wifi->scan_pending_network = NULL;
2858         }
2859
2860         //service state - associating
2861         if(!wifi || !wifi->network)
2862                 return;
2863
2864         is_associating = connman_network_get_associating(wifi->network);
2865         if(is_associating && is_scanning){
2866                 is_scanning = false;
2867                 DBG("send scan for connecting");
2868                 throw_wifi_scan(wifi->device, scan_callback);
2869
2870                 return;
2871         }
2872         is_scanning = true;
2873
2874         //go scan
2875
2876 #endif
2877 }
2878
2879 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
2880 {
2881         unsigned char strength;
2882
2883         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
2884         if (strength > 100)
2885                 strength = 100;
2886
2887         return strength;
2888 }
2889
2890 static void network_added(GSupplicantNetwork *supplicant_network)
2891 {
2892         struct connman_network *network;
2893         GSupplicantInterface *interface;
2894         struct wifi_data *wifi;
2895         const char *name, *identifier, *security, *group, *mode;
2896         const unsigned char *ssid;
2897         unsigned int ssid_len;
2898         bool wps;
2899         bool wps_pbc;
2900         bool wps_ready;
2901         bool wps_advertizing;
2902
2903         mode = g_supplicant_network_get_mode(supplicant_network);
2904         identifier = g_supplicant_network_get_identifier(supplicant_network);
2905
2906         DBG("%s", identifier);
2907
2908         if (!g_strcmp0(mode, "adhoc"))
2909                 return;
2910
2911         interface = g_supplicant_network_get_interface(supplicant_network);
2912         wifi = g_supplicant_interface_get_data(interface);
2913         name = g_supplicant_network_get_name(supplicant_network);
2914         security = g_supplicant_network_get_security(supplicant_network);
2915         group = g_supplicant_network_get_identifier(supplicant_network);
2916         wps = g_supplicant_network_get_wps(supplicant_network);
2917         wps_pbc = g_supplicant_network_is_wps_pbc(supplicant_network);
2918         wps_ready = g_supplicant_network_is_wps_active(supplicant_network);
2919         wps_advertizing = g_supplicant_network_is_wps_advertizing(
2920                                                         supplicant_network);
2921
2922         if (!wifi)
2923                 return;
2924
2925         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
2926
2927         network = connman_device_get_network(wifi->device, identifier);
2928
2929         if (!network) {
2930                 network = connman_network_create(identifier,
2931                                                 CONNMAN_NETWORK_TYPE_WIFI);
2932                 if (!network)
2933                         return;
2934
2935                 connman_network_set_index(network, wifi->index);
2936
2937                 if (connman_device_add_network(wifi->device, network) < 0) {
2938                         connman_network_unref(network);
2939                         return;
2940                 }
2941
2942                 wifi->networks = g_slist_prepend(wifi->networks, network);
2943         }
2944
2945         if (name && name[0] != '\0')
2946                 connman_network_set_name(network, name);
2947
2948         connman_network_set_blob(network, "WiFi.SSID",
2949                                                 ssid, ssid_len);
2950         connman_network_set_string(network, "WiFi.Security", security);
2951         connman_network_set_strength(network,
2952                                 calculate_strength(supplicant_network));
2953         connman_network_set_bool(network, "WiFi.WPS", wps);
2954
2955         if (wps) {
2956                 /* Is AP advertizing for WPS association?
2957                  * If so, we decide to use WPS by default */
2958                 if (wps_ready && wps_pbc &&
2959                                                 wps_advertizing) {
2960 #if !defined TIZEN_EXT
2961                         connman_network_set_bool(network, "WiFi.UseWPS", true);
2962 #else
2963                         DBG("wps is activating by ap but ignore it.");
2964 #endif
2965                 }
2966         }
2967
2968         connman_network_set_frequency(network,
2969                         g_supplicant_network_get_frequency(supplicant_network));
2970 #if defined TIZEN_EXT
2971         connman_network_set_bssid(network,
2972                         g_supplicant_network_get_bssid(supplicant_network));
2973         connman_network_set_maxrate(network,
2974                         g_supplicant_network_get_maxrate(supplicant_network));
2975         connman_network_set_enc_mode(network,
2976                         g_supplicant_network_get_enc_mode(supplicant_network));
2977         connman_network_set_rsn_mode(network,
2978                         g_supplicant_network_get_rsn_mode(supplicant_network));
2979         connman_network_set_keymgmt(network,
2980                         g_supplicant_network_get_keymgmt(supplicant_network));
2981 #endif
2982         connman_network_set_available(network, true);
2983         connman_network_set_string(network, "WiFi.Mode", mode);
2984
2985 #if defined TIZEN_EXT
2986         if (group)
2987 #else
2988         if (ssid)
2989 #endif
2990                 connman_network_set_group(network, group);
2991
2992 #if defined TIZEN_EXT
2993         if (wifi_first_scan == true)
2994                 found_with_first_scan = true;
2995 #endif
2996
2997         if (wifi->hidden && ssid) {
2998 #if defined TIZEN_EXT
2999                 if (network_security(wifi->hidden->security) ==
3000                         network_security(security) &&
3001 #else
3002                 if (!g_strcmp0(wifi->hidden->security, security) &&
3003 #endif
3004                                 wifi->hidden->ssid_len == ssid_len &&
3005                                 !memcmp(wifi->hidden->ssid, ssid, ssid_len)) {
3006                         connman_network_connect_hidden(network,
3007                                         wifi->hidden->identity,
3008                                         wifi->hidden->passphrase,
3009                                         wifi->hidden->user_data);
3010                         wifi->hidden->user_data = NULL;
3011                         hidden_free(wifi->hidden);
3012                         wifi->hidden = NULL;
3013                 }
3014         }
3015 }
3016
3017 static void network_removed(GSupplicantNetwork *network)
3018 {
3019         GSupplicantInterface *interface;
3020         struct wifi_data *wifi;
3021         const char *name, *identifier;
3022         struct connman_network *connman_network;
3023
3024         interface = g_supplicant_network_get_interface(network);
3025         wifi = g_supplicant_interface_get_data(interface);
3026         identifier = g_supplicant_network_get_identifier(network);
3027         name = g_supplicant_network_get_name(network);
3028
3029         DBG("name %s", name);
3030
3031         if (!wifi)
3032                 return;
3033
3034         connman_network = connman_device_get_network(wifi->device, identifier);
3035         if (!connman_network)
3036                 return;
3037
3038 #if defined TIZEN_EXT
3039         if (connman_network == wifi->scan_pending_network)
3040                 wifi->scan_pending_network = NULL;
3041
3042         if (connman_network == wifi->pending_network)
3043                 wifi->pending_network = NULL;
3044
3045         if(connman_network_get_connecting(connman_network) == true){
3046                 connman_network_set_connected(connman_network, false);
3047         }
3048 #endif
3049
3050         wifi->networks = g_slist_remove(wifi->networks, connman_network);
3051
3052         connman_device_remove_network(wifi->device, connman_network);
3053         connman_network_unref(connman_network);
3054 }
3055
3056 static void network_changed(GSupplicantNetwork *network, const char *property)
3057 {
3058         GSupplicantInterface *interface;
3059         struct wifi_data *wifi;
3060         const char *name, *identifier;
3061         struct connman_network *connman_network;
3062
3063 #if defined TIZEN_EXT
3064         const unsigned char *bssid;
3065         unsigned int maxrate;
3066         uint16_t frequency;
3067         bool wps;
3068 #endif
3069
3070         interface = g_supplicant_network_get_interface(network);
3071         wifi = g_supplicant_interface_get_data(interface);
3072         identifier = g_supplicant_network_get_identifier(network);
3073         name = g_supplicant_network_get_name(network);
3074
3075         DBG("name %s", name);
3076
3077         if (!wifi)
3078                 return;
3079
3080         connman_network = connman_device_get_network(wifi->device, identifier);
3081         if (!connman_network)
3082                 return;
3083
3084         if (g_str_equal(property, "Signal")) {
3085                connman_network_set_strength(connman_network,
3086                                         calculate_strength(network));
3087                connman_network_update(connman_network);
3088         }
3089
3090 #if defined TIZEN_EXT
3091         bssid = g_supplicant_network_get_bssid(network);
3092         maxrate = g_supplicant_network_get_maxrate(network);
3093         frequency = g_supplicant_network_get_frequency(network);
3094         wps = g_supplicant_network_get_wps(network);
3095
3096         connman_network_set_bssid(connman_network, bssid);
3097         connman_network_set_maxrate(connman_network, maxrate);
3098         connman_network_set_frequency(connman_network, frequency);
3099         connman_network_set_bool(connman_network, "WiFi.WPS", wps);
3100 #endif
3101 }
3102
3103 static void apply_peer_services(GSupplicantPeer *peer,
3104                                 struct connman_peer *connman_peer)
3105 {
3106         const unsigned char *data;
3107         int length;
3108
3109         DBG("");
3110
3111         connman_peer_reset_services(connman_peer);
3112
3113         data = g_supplicant_peer_get_widi_ies(peer, &length);
3114         if (data) {
3115                 connman_peer_add_service(connman_peer,
3116                         CONNMAN_PEER_SERVICE_WIFI_DISPLAY, data, length);
3117         }
3118 }
3119
3120 static void add_station(const char *mac)
3121 {
3122         connman_technology_tethering_add_station(CONNMAN_SERVICE_TYPE_WIFI,
3123                                                  mac);
3124 }
3125
3126 static void remove_station(const char *mac)
3127 {
3128         connman_technology_tethering_remove_station(mac);
3129 }
3130
3131 static void peer_found(GSupplicantPeer *peer)
3132 {
3133         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3134         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3135         struct connman_peer *connman_peer;
3136         const char *identifier, *name;
3137         int ret;
3138
3139         identifier = g_supplicant_peer_get_identifier(peer);
3140         name = g_supplicant_peer_get_name(peer);
3141
3142         DBG("ident: %s", identifier);
3143
3144         connman_peer = connman_peer_get(wifi->device, identifier);
3145         if (connman_peer)
3146                 return;
3147
3148         connman_peer = connman_peer_create(identifier);
3149         connman_peer_set_name(connman_peer, name);
3150         connman_peer_set_device(connman_peer, wifi->device);
3151         apply_peer_services(peer, connman_peer);
3152
3153         ret = connman_peer_register(connman_peer);
3154         if (ret < 0 && ret != -EALREADY)
3155                 connman_peer_unref(connman_peer);
3156 }
3157
3158 static void peer_lost(GSupplicantPeer *peer)
3159 {
3160         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3161         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3162         struct connman_peer *connman_peer;
3163         const char *identifier;
3164
3165         if (!wifi)
3166                 return;
3167
3168         identifier = g_supplicant_peer_get_identifier(peer);
3169
3170         DBG("ident: %s", identifier);
3171
3172         connman_peer = connman_peer_get(wifi->device, identifier);
3173         if (connman_peer) {
3174                 if (wifi->p2p_connecting &&
3175                                 wifi->pending_peer == connman_peer) {
3176                         peer_connect_timeout(wifi);
3177                 }
3178                 connman_peer_unregister(connman_peer);
3179                 connman_peer_unref(connman_peer);
3180         }
3181 }
3182
3183 static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state)
3184 {
3185         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3186         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3187         enum connman_peer_state p_state = CONNMAN_PEER_STATE_UNKNOWN;
3188         struct connman_peer *connman_peer;
3189         const char *identifier;
3190
3191         identifier = g_supplicant_peer_get_identifier(peer);
3192
3193         DBG("ident: %s", identifier);
3194
3195         connman_peer = connman_peer_get(wifi->device, identifier);
3196         if (!connman_peer)
3197                 return;
3198
3199         switch (state) {
3200         case G_SUPPLICANT_PEER_SERVICES_CHANGED:
3201                 apply_peer_services(peer, connman_peer);
3202                 connman_peer_services_changed(connman_peer);
3203                 return;
3204         case G_SUPPLICANT_PEER_GROUP_CHANGED:
3205                 if (!g_supplicant_peer_is_in_a_group(peer))
3206                         p_state = CONNMAN_PEER_STATE_IDLE;
3207                 else
3208                         p_state = CONNMAN_PEER_STATE_CONFIGURATION;
3209                 break;
3210         case G_SUPPLICANT_PEER_GROUP_STARTED:
3211                 break;
3212         case G_SUPPLICANT_PEER_GROUP_FINISHED:
3213                 p_state = CONNMAN_PEER_STATE_IDLE;
3214                 break;
3215         case G_SUPPLICANT_PEER_GROUP_JOINED:
3216                 connman_peer_set_iface_address(connman_peer,
3217                                 g_supplicant_peer_get_iface_address(peer));
3218                 break;
3219         case G_SUPPLICANT_PEER_GROUP_DISCONNECTED:
3220                 p_state = CONNMAN_PEER_STATE_IDLE;
3221                 break;
3222         case G_SUPPLICANT_PEER_GROUP_FAILED:
3223                 if (g_supplicant_peer_has_requested_connection(peer))
3224                         p_state = CONNMAN_PEER_STATE_IDLE;
3225                 else
3226                         p_state = CONNMAN_PEER_STATE_FAILURE;
3227                 break;
3228         }
3229
3230         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION ||
3231                                         p_state == CONNMAN_PEER_STATE_FAILURE) {
3232                 if (wifi->p2p_connecting
3233                                 && connman_peer == wifi->pending_peer)
3234                         peer_cancel_timeout(wifi);
3235                 else
3236                         p_state = CONNMAN_PEER_STATE_UNKNOWN;
3237         }
3238
3239         if (p_state == CONNMAN_PEER_STATE_UNKNOWN)
3240                 return;
3241
3242         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION) {
3243                 GSupplicantInterface *g_iface;
3244                 struct wifi_data *g_wifi;
3245
3246                 g_iface = g_supplicant_peer_get_group_interface(peer);
3247                 if (!g_iface)
3248                         return;
3249
3250                 g_wifi = g_supplicant_interface_get_data(g_iface);
3251                 if (!g_wifi)
3252                         return;
3253
3254                 connman_peer_set_as_master(connman_peer,
3255                                         !g_supplicant_peer_is_client(peer));
3256                 connman_peer_set_sub_device(connman_peer, g_wifi->device);
3257         }
3258
3259         connman_peer_set_state(connman_peer, p_state);
3260 }
3261
3262 static void peer_request(GSupplicantPeer *peer)
3263 {
3264         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3265         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3266         struct connman_peer *connman_peer;
3267         const char *identifier;
3268
3269         identifier = g_supplicant_peer_get_identifier(peer);
3270
3271         DBG("ident: %s", identifier);
3272
3273         connman_peer = connman_peer_get(wifi->device, identifier);
3274         if (!connman_peer)
3275                 return;
3276
3277         connman_peer_request_connection(connman_peer);
3278 }
3279
3280 #if defined TIZEN_EXT
3281 static void system_power_off(void)
3282 {
3283         GList *list;
3284         struct wifi_data *wifi;
3285         struct connman_service *service;
3286         struct connman_ipconfig *ipconfig_ipv4;
3287
3288         if (connman_setting_get_bool("WiFiDHCPRelease") == true) {
3289                 for (list = iface_list; list; list = list->next) {
3290                         wifi = list->data;
3291
3292                         if (wifi->network != NULL) {
3293                                 service = connman_service_lookup_from_network(wifi->network);
3294                                 ipconfig_ipv4 = __connman_service_get_ip4config(service);
3295                                 __connman_dhcp_stop(ipconfig_ipv4);
3296                         }
3297                 }
3298         }
3299 }
3300
3301 static void network_merged(GSupplicantNetwork *network)
3302 {
3303         GSupplicantInterface *interface;
3304         GSupplicantState state;
3305         struct wifi_data *wifi;
3306         const char *identifier;
3307         struct connman_network *connman_network;
3308         unsigned int ishs20AP = 0;
3309         char *temp = NULL;
3310
3311         interface = g_supplicant_network_get_interface(network);
3312         if (!interface)
3313                 return;
3314
3315         state = g_supplicant_interface_get_state(interface);
3316         if (state < G_SUPPLICANT_STATE_AUTHENTICATING)
3317                 return;
3318
3319         wifi = g_supplicant_interface_get_data(interface);
3320         if (!wifi)
3321                 return;
3322
3323         identifier = g_supplicant_network_get_identifier(network);
3324
3325         connman_network = connman_device_get_network(wifi->device, identifier);
3326         if (!connman_network)
3327                 return;
3328
3329         DBG("merged identifier %s", identifier);
3330
3331         if (wifi->connected == FALSE) {
3332                 switch (state) {
3333                 case G_SUPPLICANT_STATE_AUTHENTICATING:
3334                 case G_SUPPLICANT_STATE_ASSOCIATING:
3335                 case G_SUPPLICANT_STATE_ASSOCIATED:
3336                 case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3337                 case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3338                         connman_network_set_associating(connman_network, TRUE);
3339                         break;
3340                 case G_SUPPLICANT_STATE_COMPLETED:
3341                         connman_network_set_connected(connman_network, TRUE);
3342                         break;
3343                 default:
3344                         DBG("Not handled the state : %d", state);
3345                         break;
3346                 }
3347         }
3348
3349         ishs20AP = g_supplicant_network_is_hs20AP(network);
3350         connman_network_set_is_hs20AP(connman_network, ishs20AP);
3351
3352         if (ishs20AP &&
3353                 g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) {
3354                 temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1);
3355                 connman_network_set_string(connman_network, "WiFi.EAP",
3356                                 temp);
3357                 connman_network_set_string(connman_network, "WiFi.Identity",
3358                                 g_supplicant_network_get_identity(network));
3359                 connman_network_set_string(connman_network, "WiFi.Phase2",
3360                                 g_supplicant_network_get_phase2(network));
3361
3362                 g_free(temp);
3363         }
3364
3365         wifi->network = connman_network;
3366 }
3367 #endif
3368
3369 static void debug(const char *str)
3370 {
3371         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
3372                 connman_debug("%s", str);
3373 }
3374
3375 static const GSupplicantCallbacks callbacks = {
3376         .system_ready           = system_ready,
3377         .system_killed          = system_killed,
3378         .interface_added        = interface_added,
3379         .interface_state        = interface_state,
3380         .interface_removed      = interface_removed,
3381         .p2p_support            = p2p_support,
3382         .scan_started           = scan_started,
3383         .scan_finished          = scan_finished,
3384         .network_added          = network_added,
3385         .network_removed        = network_removed,
3386         .network_changed        = network_changed,
3387         .add_station            = add_station,
3388         .remove_station         = remove_station,
3389         .peer_found             = peer_found,
3390         .peer_lost              = peer_lost,
3391         .peer_changed           = peer_changed,
3392         .peer_request           = peer_request,
3393 #if defined TIZEN_EXT
3394         .system_power_off       = system_power_off,
3395         .network_merged = network_merged,
3396 #endif
3397         .debug                  = debug,
3398 };
3399
3400
3401 static int tech_probe(struct connman_technology *technology)
3402 {
3403         wifi_technology = technology;
3404
3405         return 0;
3406 }
3407
3408 static void tech_remove(struct connman_technology *technology)
3409 {
3410         wifi_technology = NULL;
3411 }
3412
3413 struct wifi_tethering_info {
3414         struct wifi_data *wifi;
3415         struct connman_technology *technology;
3416         char *ifname;
3417         GSupplicantSSID *ssid;
3418 };
3419
3420 static GSupplicantSSID *ssid_ap_init(const char *ssid,
3421                 const char *passphrase, bool hidden)
3422 {
3423         GSupplicantSSID *ap;
3424
3425         ap = g_try_malloc0(sizeof(GSupplicantSSID));
3426         if (!ap)
3427                 return NULL;
3428
3429         ap->mode = G_SUPPLICANT_MODE_MASTER;
3430         ap->ssid = ssid;
3431         ap->ssid_len = strlen(ssid);
3432         ap->scan_ssid = 0;
3433         ap->freq = 2412;
3434
3435         if (!passphrase || strlen(passphrase) == 0) {
3436                 ap->security = G_SUPPLICANT_SECURITY_NONE;
3437                 ap->passphrase = NULL;
3438         } else {
3439                ap->security = G_SUPPLICANT_SECURITY_PSK;
3440                ap->protocol = G_SUPPLICANT_PROTO_RSN;
3441                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
3442                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
3443                ap->passphrase = passphrase;
3444         }
3445
3446         if (hidden)
3447                 ap->ignore_broadcast_ssid =
3448                                 G_SUPPLICANT_AP_HIDDEN_SSID_ZERO_CONTENTS;
3449         else
3450                 ap->ignore_broadcast_ssid = G_SUPPLICANT_AP_NO_SSID_HIDING;
3451
3452         return ap;
3453 }
3454
3455 static void ap_start_callback(int result, GSupplicantInterface *interface,
3456                                                         void *user_data)
3457 {
3458         struct wifi_tethering_info *info = user_data;
3459
3460         DBG("result %d index %d bridge %s",
3461                 result, info->wifi->index, info->wifi->bridge);
3462
3463         if (result < 0) {
3464                 connman_inet_remove_from_bridge(info->wifi->index,
3465                                                         info->wifi->bridge);
3466                 connman_technology_tethering_notify(info->technology, false);
3467         }
3468
3469         g_free(info->ifname);
3470         g_free(info);
3471 }
3472
3473 static void ap_create_callback(int result,
3474                                 GSupplicantInterface *interface,
3475                                         void *user_data)
3476 {
3477         struct wifi_tethering_info *info = user_data;
3478
3479         DBG("result %d ifname %s", result,
3480                                 g_supplicant_interface_get_ifname(interface));
3481
3482         if (result < 0) {
3483                 connman_inet_remove_from_bridge(info->wifi->index,
3484                                                         info->wifi->bridge);
3485                 connman_technology_tethering_notify(info->technology, false);
3486
3487                 g_free(info->ifname);
3488                 g_free(info->ssid);
3489                 g_free(info);
3490                 return;
3491         }
3492
3493         info->wifi->interface = interface;
3494         g_supplicant_interface_set_data(interface, info->wifi);
3495
3496         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
3497                 connman_error("Failed to set interface ap_scan property");
3498
3499         g_supplicant_interface_connect(interface, info->ssid,
3500                                                 ap_start_callback, info);
3501 }
3502
3503 static void sta_remove_callback(int result,
3504                                 GSupplicantInterface *interface,
3505                                         void *user_data)
3506 {
3507         struct wifi_tethering_info *info = user_data;
3508         const char *driver = connman_option_get_string("wifi");
3509
3510         DBG("ifname %s result %d ", info->ifname, result);
3511
3512         if (result < 0) {
3513                 info->wifi->tethering = true;
3514
3515                 g_free(info->ifname);
3516                 g_free(info->ssid);
3517                 g_free(info);
3518                 return;
3519         }
3520
3521         info->wifi->interface = NULL;
3522
3523         connman_technology_tethering_notify(info->technology, true);
3524
3525         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
3526                                                 ap_create_callback,
3527                                                         info);
3528 }
3529
3530 static int tech_set_tethering(struct connman_technology *technology,
3531                                 const char *identifier, const char *passphrase,
3532                                 const char *bridge, bool enabled, bool hidden)
3533 {
3534         GList *list;
3535         GSupplicantInterface *interface;
3536         struct wifi_data *wifi;
3537         struct wifi_tethering_info *info;
3538         const char *ifname;
3539         unsigned int mode;
3540         int err;
3541
3542         DBG("");
3543
3544         if (!enabled) {
3545                 for (list = iface_list; list; list = list->next) {
3546                         wifi = list->data;
3547
3548                         if (wifi->tethering) {
3549                                 wifi->tethering = false;
3550
3551                                 connman_inet_remove_from_bridge(wifi->index,
3552                                                                         bridge);
3553                                 wifi->bridged = false;
3554                         }
3555                 }
3556
3557                 connman_technology_tethering_notify(technology, false);
3558
3559                 return 0;
3560         }
3561
3562         for (list = iface_list; list; list = list->next) {
3563                 wifi = list->data;
3564
3565                 interface = wifi->interface;
3566
3567                 if (!interface)
3568                         continue;
3569
3570                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
3571
3572                 mode = g_supplicant_interface_get_mode(interface);
3573                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
3574                         DBG("%s does not support AP mode", ifname);
3575                         continue;
3576                 }
3577
3578                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
3579                 if (!info)
3580                         return -ENOMEM;
3581
3582                 info->wifi = wifi;
3583                 info->technology = technology;
3584                 info->wifi->bridge = bridge;
3585                 info->ssid = ssid_ap_init(identifier, passphrase, hidden);
3586                 if (!info->ssid) {
3587                         g_free(info);
3588                         continue;
3589                 }
3590                 info->ifname = g_strdup(ifname);
3591                 if (!info->ifname) {
3592                         g_free(info->ssid);
3593                         g_free(info);
3594                         continue;
3595                 }
3596
3597                 info->wifi->tethering = true;
3598
3599                 err = g_supplicant_interface_remove(interface,
3600                                                 sta_remove_callback,
3601                                                         info);
3602                 if (err == 0)
3603                         return err;
3604         }
3605
3606         return -EOPNOTSUPP;
3607 }
3608
3609 static void regdom_callback(int result, const char *alpha2, void *user_data)
3610 {
3611         DBG("");
3612
3613         if (!wifi_technology)
3614                 return;
3615
3616         if (result != 0)
3617                 alpha2 = NULL;
3618
3619         connman_technology_regdom_notify(wifi_technology, alpha2);
3620 }
3621
3622 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
3623 {
3624         return g_supplicant_set_country(alpha2, regdom_callback, NULL);
3625 }
3626
3627 static struct connman_technology_driver tech_driver = {
3628         .name           = "wifi",
3629         .type           = CONNMAN_SERVICE_TYPE_WIFI,
3630         .probe          = tech_probe,
3631         .remove         = tech_remove,
3632         .set_tethering  = tech_set_tethering,
3633         .set_regdom     = tech_set_regdom,
3634 };
3635
3636 static int wifi_init(void)
3637 {
3638         int err;
3639
3640         err = connman_network_driver_register(&network_driver);
3641         if (err < 0)
3642                 return err;
3643
3644         err = g_supplicant_register(&callbacks);
3645         if (err < 0) {
3646                 connman_network_driver_unregister(&network_driver);
3647                 return err;
3648         }
3649
3650         err = connman_technology_driver_register(&tech_driver);
3651         if (err < 0) {
3652                 g_supplicant_unregister(&callbacks);
3653                 connman_network_driver_unregister(&network_driver);
3654                 return err;
3655         }
3656
3657         return 0;
3658 }
3659
3660 static void wifi_exit(void)
3661 {
3662         DBG();
3663
3664         connman_technology_driver_unregister(&tech_driver);
3665
3666         g_supplicant_unregister(&callbacks);
3667
3668         connman_network_driver_unregister(&network_driver);
3669 }
3670
3671 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
3672                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)