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