84d07088eef45308ba01978aff9b2dad144b29a2
[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 #if defined TIZEN_EXT
2174         ssid->freq = connman_network_get_frequency(network);
2175 #endif
2176
2177         if (connman_setting_get_bool("BackgroundScanning"))
2178                 ssid->bgscan = BGSCAN_DEFAULT;
2179 }
2180
2181 static int network_connect(struct connman_network *network)
2182 {
2183         struct connman_device *device = connman_network_get_device(network);
2184         struct wifi_data *wifi;
2185         GSupplicantInterface *interface;
2186         GSupplicantSSID *ssid;
2187
2188         DBG("network %p", network);
2189
2190         if (!device)
2191                 return -ENODEV;
2192
2193         wifi = connman_device_get_data(device);
2194         if (!wifi)
2195                 return -ENODEV;
2196
2197         ssid = g_try_malloc0(sizeof(GSupplicantSSID));
2198         if (!ssid)
2199                 return -ENOMEM;
2200
2201         interface = wifi->interface;
2202
2203         ssid_init(ssid, network);
2204
2205         if (wifi->disconnecting) {
2206                 wifi->pending_network = network;
2207                 g_free(ssid);
2208         } else {
2209                 wifi->network = connman_network_ref(network);
2210                 wifi->retries = 0;
2211 #if defined TIZEN_EXT
2212                 wifi->scan_pending_network = NULL;
2213 #endif
2214
2215                 return g_supplicant_interface_connect(interface, ssid,
2216                                                 connect_callback, network);
2217         }
2218
2219         return -EINPROGRESS;
2220 }
2221
2222 static void disconnect_callback(int result, GSupplicantInterface *interface,
2223                                                                 void *user_data)
2224 {
2225 #if defined TIZEN_EXT
2226         GList *list;
2227         struct wifi_data *wifi;
2228         struct connman_network *network = user_data;
2229
2230         DBG("network %p result %d", network, result);
2231
2232         for (list = iface_list; list; list = list->next) {
2233                 wifi = list->data;
2234
2235                 if (wifi->network == NULL && wifi->disconnecting == true)
2236                         wifi->disconnecting = false;
2237
2238                 if (wifi->network == network)
2239                         goto found;
2240         }
2241
2242         /* wifi_data may be invalid because wifi is already disabled */
2243         return;
2244
2245 found:
2246 #else
2247         struct wifi_data *wifi = user_data;
2248 #endif
2249
2250         DBG("result %d supplicant interface %p wifi %p",
2251                         result, interface, wifi);
2252
2253         if (result == -ECONNABORTED) {
2254                 DBG("wifi interface no longer available");
2255                 return;
2256         }
2257
2258         if (wifi->network) {
2259                 /*
2260                  * if result < 0 supplican return an error because
2261                  * the network is not current.
2262                  * we wont receive G_SUPPLICANT_STATE_DISCONNECTED since it
2263                  * failed, call connman_network_set_connected to report
2264                  * disconnect is completed.
2265                  */
2266                 if (result < 0)
2267                         connman_network_set_connected(wifi->network, false);
2268         }
2269
2270         wifi->network = NULL;
2271
2272         wifi->disconnecting = false;
2273
2274         if (wifi->pending_network) {
2275                 network_connect(wifi->pending_network);
2276                 wifi->pending_network = NULL;
2277         }
2278
2279         start_autoscan(wifi->device);
2280 }
2281
2282 static int network_disconnect(struct connman_network *network)
2283 {
2284         struct connman_device *device = connman_network_get_device(network);
2285         struct wifi_data *wifi;
2286         int err;
2287 #if defined TIZEN_EXT
2288         struct connman_service *service;
2289 #endif
2290
2291         DBG("network %p", network);
2292
2293         wifi = connman_device_get_data(device);
2294         if (!wifi || !wifi->interface)
2295                 return -ENODEV;
2296
2297 #if defined TIZEN_EXT
2298         if (connman_network_get_associating(network) == true) {
2299                 connman_network_clear_associating(network);
2300                 connman_network_set_bool(network, "WiFi.UseWPS", false);
2301         } else {
2302                 service = connman_service_lookup_from_network(network);
2303
2304                 if (service != NULL &&
2305                         (__connman_service_is_connected_state(service,
2306                                         CONNMAN_IPCONFIG_TYPE_IPV4) == false &&
2307                         __connman_service_is_connected_state(service,
2308                                         CONNMAN_IPCONFIG_TYPE_IPV6) == false) &&
2309                         (connman_service_get_favorite(service) == false))
2310                                         __connman_service_set_passphrase(service, NULL);
2311         }
2312
2313         if (wifi->pending_network == network)
2314                 wifi->pending_network = NULL;
2315
2316         if (wifi->scan_pending_network == network)
2317                 wifi->scan_pending_network = NULL;
2318
2319 #endif
2320         connman_network_set_associating(network, false);
2321
2322         if (wifi->disconnecting)
2323                 return -EALREADY;
2324
2325         wifi->disconnecting = true;
2326
2327 #if defined TIZEN_EXT
2328         err = g_supplicant_interface_disconnect(wifi->interface,
2329                                                 disconnect_callback, network);
2330 #else
2331         err = g_supplicant_interface_disconnect(wifi->interface,
2332                                                 disconnect_callback, wifi);
2333 #endif
2334
2335         if (err < 0)
2336                 wifi->disconnecting = false;
2337
2338         return err;
2339 }
2340
2341 static struct connman_network_driver network_driver = {
2342         .name           = "wifi",
2343         .type           = CONNMAN_NETWORK_TYPE_WIFI,
2344         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
2345         .probe          = network_probe,
2346         .remove         = network_remove,
2347         .connect        = network_connect,
2348         .disconnect     = network_disconnect,
2349 };
2350
2351 static void interface_added(GSupplicantInterface *interface)
2352 {
2353         const char *ifname = g_supplicant_interface_get_ifname(interface);
2354         const char *driver = g_supplicant_interface_get_driver(interface);
2355         struct wifi_data *wifi;
2356
2357         wifi = g_supplicant_interface_get_data(interface);
2358         if (!wifi) {
2359                 wifi = get_pending_wifi_data(ifname);
2360                 if (!wifi)
2361                         return;
2362
2363                 g_supplicant_interface_set_data(interface, wifi);
2364                 p2p_iface_list = g_list_append(p2p_iface_list, wifi);
2365                 wifi->p2p_device = true;
2366         }
2367
2368         DBG("ifname %s driver %s wifi %p tethering %d",
2369                         ifname, driver, wifi, wifi->tethering);
2370
2371         if (!wifi->device) {
2372                 connman_error("WiFi device not set");
2373                 return;
2374         }
2375
2376         connman_device_set_powered(wifi->device, true);
2377 }
2378
2379 static bool is_idle(struct wifi_data *wifi)
2380 {
2381         DBG("state %d", wifi->state);
2382
2383         switch (wifi->state) {
2384         case G_SUPPLICANT_STATE_UNKNOWN:
2385         case G_SUPPLICANT_STATE_DISABLED:
2386         case G_SUPPLICANT_STATE_DISCONNECTED:
2387         case G_SUPPLICANT_STATE_INACTIVE:
2388         case G_SUPPLICANT_STATE_SCANNING:
2389                 return true;
2390
2391         case G_SUPPLICANT_STATE_AUTHENTICATING:
2392         case G_SUPPLICANT_STATE_ASSOCIATING:
2393         case G_SUPPLICANT_STATE_ASSOCIATED:
2394         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2395         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2396         case G_SUPPLICANT_STATE_COMPLETED:
2397                 return false;
2398         }
2399
2400         return false;
2401 }
2402
2403 static bool is_idle_wps(GSupplicantInterface *interface,
2404                                                 struct wifi_data *wifi)
2405 {
2406         /* First, let's check if WPS processing did not went wrong */
2407         if (g_supplicant_interface_get_wps_state(interface) ==
2408                 G_SUPPLICANT_WPS_STATE_FAIL)
2409                 return false;
2410
2411         /* Unlike normal connection, being associated while processing wps
2412          * actually means that we are idling. */
2413         switch (wifi->state) {
2414         case G_SUPPLICANT_STATE_UNKNOWN:
2415         case G_SUPPLICANT_STATE_DISABLED:
2416         case G_SUPPLICANT_STATE_DISCONNECTED:
2417         case G_SUPPLICANT_STATE_INACTIVE:
2418         case G_SUPPLICANT_STATE_SCANNING:
2419         case G_SUPPLICANT_STATE_ASSOCIATED:
2420                 return true;
2421         case G_SUPPLICANT_STATE_AUTHENTICATING:
2422         case G_SUPPLICANT_STATE_ASSOCIATING:
2423         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2424         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2425         case G_SUPPLICANT_STATE_COMPLETED:
2426                 return false;
2427         }
2428
2429         return false;
2430 }
2431
2432 static bool handle_wps_completion(GSupplicantInterface *interface,
2433                                         struct connman_network *network,
2434                                         struct connman_device *device,
2435                                         struct wifi_data *wifi)
2436 {
2437         bool wps;
2438
2439         wps = connman_network_get_bool(network, "WiFi.UseWPS");
2440         if (wps) {
2441                 const unsigned char *ssid, *wps_ssid;
2442                 unsigned int ssid_len, wps_ssid_len;
2443                 const char *wps_key;
2444
2445                 /* Checking if we got associated with requested
2446                  * network */
2447                 ssid = connman_network_get_blob(network, "WiFi.SSID",
2448                                                 &ssid_len);
2449
2450                 wps_ssid = g_supplicant_interface_get_wps_ssid(
2451                         interface, &wps_ssid_len);
2452
2453                 if (!wps_ssid || wps_ssid_len != ssid_len ||
2454                                 memcmp(ssid, wps_ssid, ssid_len) != 0) {
2455                         connman_network_set_associating(network, false);
2456 #if defined TIZEN_EXT
2457                         g_supplicant_interface_disconnect(wifi->interface,
2458                                                 disconnect_callback, wifi->network);
2459
2460                         connman_network_set_bool(network, "WiFi.UseWPS", false);
2461                         connman_network_set_string(network, "WiFi.PinWPS", NULL);
2462 #else
2463                         g_supplicant_interface_disconnect(wifi->interface,
2464                                                 disconnect_callback, wifi);
2465 #endif
2466                         return false;
2467                 }
2468
2469                 wps_key = g_supplicant_interface_get_wps_key(interface);
2470                 connman_network_set_string(network, "WiFi.Passphrase",
2471                                         wps_key);
2472
2473                 connman_network_set_string(network, "WiFi.PinWPS", NULL);
2474         }
2475
2476         return true;
2477 }
2478
2479 static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
2480                                         struct connman_network *network,
2481                                         struct wifi_data *wifi)
2482 {
2483 #if defined TIZEN_EXT
2484         const char *security;
2485         struct connman_service *service;
2486
2487         if (wifi->connected)
2488                 return false;
2489
2490         security = connman_network_get_string(network, "WiFi.Security");
2491
2492         if (g_str_equal(security, "ieee8021x") == true &&
2493                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
2494                 wifi->retries = 0;
2495                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
2496
2497                 return false;
2498         }
2499
2500         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
2501                 return false;
2502 #else
2503         struct connman_service *service;
2504
2505         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
2506                 return false;
2507
2508         if (wifi->connected)
2509                 return false;
2510 #endif
2511
2512         service = connman_service_lookup_from_network(network);
2513         if (!service)
2514                 return false;
2515
2516         wifi->retries++;
2517
2518         if (connman_service_get_favorite(service)) {
2519                 if (wifi->retries < FAVORITE_MAXIMUM_RETRIES)
2520                         return true;
2521         }
2522
2523         wifi->retries = 0;
2524         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
2525
2526         return false;
2527 }
2528
2529 #if defined TIZEN_EXT
2530 static bool handle_wifi_assoc_retry(struct connman_network *network,
2531                                         struct wifi_data *wifi)
2532 {
2533         const char *security;
2534
2535         if (!wifi->network || wifi->connected || wifi->disconnecting ||
2536                         connman_network_get_connecting(network) != true) {
2537                 wifi->assoc_retry_count = 0;
2538                 return false;
2539         }
2540
2541         if (wifi->state != G_SUPPLICANT_STATE_ASSOCIATING &&
2542                         wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) {
2543                 wifi->assoc_retry_count = 0;
2544                 return false;
2545         }
2546
2547         security = connman_network_get_string(network, "WiFi.Security");
2548         if (g_str_equal(security, "ieee8021x") == true &&
2549                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
2550                 wifi->assoc_retry_count = 0;
2551                 return false;
2552         }
2553
2554         if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) {
2555                 wifi->assoc_retry_count = 0;
2556
2557                 /* Honestly it's not an invalid-key error,
2558                  * however QA team recommends that the invalid-key error
2559                  * might be better to display for user experience.
2560                  */
2561                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
2562
2563                 return false;
2564         }
2565
2566         return true;
2567 }
2568 #endif
2569
2570 static void interface_state(GSupplicantInterface *interface)
2571 {
2572         struct connman_network *network;
2573         struct connman_device *device;
2574         struct wifi_data *wifi;
2575         GSupplicantState state = g_supplicant_interface_get_state(interface);
2576         bool wps;
2577
2578         wifi = g_supplicant_interface_get_data(interface);
2579
2580         DBG("wifi %p interface state %d", wifi, state);
2581
2582         if (!wifi)
2583                 return;
2584
2585         device = wifi->device;
2586         if (!device)
2587                 return;
2588
2589         if (g_supplicant_interface_get_ready(interface) &&
2590                                         !wifi->interface_ready) {
2591                 wifi->interface_ready = true;
2592                 finalize_interface_creation(wifi);
2593         }
2594
2595         network = wifi->network;
2596         if (!network)
2597                 return;
2598
2599         switch (state) {
2600         case G_SUPPLICANT_STATE_SCANNING:
2601                 break;
2602
2603         case G_SUPPLICANT_STATE_AUTHENTICATING:
2604         case G_SUPPLICANT_STATE_ASSOCIATING:
2605 #if defined TIZEN_EXT
2606                 reset_autoscan(device);
2607 #else
2608                 stop_autoscan(device);
2609 #endif
2610
2611                 if (!wifi->connected)
2612                         connman_network_set_associating(network, true);
2613
2614                 break;
2615
2616         case G_SUPPLICANT_STATE_COMPLETED:
2617 #if defined TIZEN_EXT
2618                 /* though it should be already reset: */
2619                 reset_autoscan(device);
2620
2621                 wifi->assoc_retry_count = 0;
2622
2623                 wifi->scan_pending_network = NULL;
2624
2625                 /* should be cleared scanning flag */
2626                 bool scanning = connman_device_get_scanning(device);
2627                 if (scanning){
2628                         connman_device_set_scanning(device,
2629                                 CONNMAN_SERVICE_TYPE_WIFI, false);
2630                         connman_device_unref(device);
2631                 }
2632 #else
2633                 /* though it should be already stopped: */
2634                 stop_autoscan(device);
2635 #endif
2636
2637                 if (!handle_wps_completion(interface, network, device, wifi))
2638                         break;
2639
2640                 connman_network_set_connected(network, true);
2641                 break;
2642
2643         case G_SUPPLICANT_STATE_DISCONNECTED:
2644                 /*
2645                  * If we're in one of the idle modes, we have
2646                  * not started association yet and thus setting
2647                  * those ones to FALSE could cancel an association
2648                  * in progress.
2649                  */
2650                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
2651                 if (wps)
2652                         if (is_idle_wps(interface, wifi))
2653                                 break;
2654
2655                 if (is_idle(wifi))
2656                         break;
2657
2658                 /* If previous state was 4way-handshake, then
2659                  * it's either: psk was incorrect and thus we retry
2660                  * or if we reach the maximum retries we declare the
2661                  * psk as wrong */
2662                 if (handle_4way_handshake_failure(interface,
2663                                                 network, wifi))
2664                         break;
2665
2666 #if defined TIZEN_EXT
2667                 wifi->disconnect_code = g_supplicant_interface_get_disconnect_reason(wifi->interface);
2668                 DBG("Disconnect Reason code %d", wifi->disconnect_code);
2669 #endif
2670                 /* See table 8-36 Reason codes in IEEE Std 802.11 */
2671                 switch (wifi->disconnect_code) {
2672                 case 1: /* Unspecified reason */
2673                         /* Let's assume it's because we got blocked */
2674
2675                 case 6: /* Class 2 frame received from nonauthenticated STA */
2676                         connman_network_set_error(network,
2677                                                 CONNMAN_NETWORK_ERROR_BLOCKED);
2678                         break;
2679
2680                 default:
2681                         break;
2682                 }
2683
2684
2685                 /* We disable the selected network, if not then
2686                  * wpa_supplicant will loop retrying */
2687                 if (g_supplicant_interface_enable_selected_network(interface,
2688                                                 FALSE) != 0)
2689                         DBG("Could not disables selected network");
2690
2691 #if defined TIZEN_EXT
2692                 int err;
2693
2694                 err = g_supplicant_interface_remove_network(wifi->interface);
2695                 if (err < 0)
2696                         DBG("Failed to remove network(%d)", err);
2697
2698
2699                 /* Some of Wi-Fi networks are not comply Wi-Fi specification.
2700                  * Retry association until its retry count is expired */
2701                 if (handle_wifi_assoc_retry(network, wifi) == true) {
2702                         throw_wifi_scan(wifi->device, scan_callback);
2703                         wifi->scan_pending_network = wifi->network;
2704                         break;
2705                 }
2706
2707                 if(wifi->disconnect_code > 0){
2708                         DBG("Set disconnect reason code(%d)", wifi->disconnect_code);
2709                         connman_network_set_disconnect_reason(network, wifi->disconnect_code);
2710                 }
2711
2712                 /* To avoid unnecessary repeated association in wpa_supplicant,
2713                  * "RemoveNetwork" should be made when Wi-Fi is disconnected */
2714                 if (wps != true && wifi->network && wifi->disconnecting == false) {
2715                         wifi->disconnecting = true;
2716                         err = g_supplicant_interface_disconnect(wifi->interface,
2717                                                         disconnect_callback, wifi->network);
2718                         if (err < 0)
2719                                 wifi->disconnecting = false;
2720
2721                 connman_network_set_connected(network, false);
2722                 connman_network_set_associating(network, false);
2723
2724                 start_autoscan(device);
2725
2726                 break;
2727                 }
2728 #endif
2729
2730                 connman_network_set_connected(network, false);
2731                 connman_network_set_associating(network, false);
2732                 wifi->disconnecting = false;
2733
2734                 start_autoscan(device);
2735
2736                 break;
2737
2738         case G_SUPPLICANT_STATE_INACTIVE:
2739 #if defined TIZEN_EXT
2740                 if (handle_wps_completion(interface, network, device, wifi) == false)
2741                         break;
2742 #endif
2743                 connman_network_set_associating(network, false);
2744                 start_autoscan(device);
2745
2746                 break;
2747
2748         case G_SUPPLICANT_STATE_UNKNOWN:
2749         case G_SUPPLICANT_STATE_DISABLED:
2750         case G_SUPPLICANT_STATE_ASSOCIATED:
2751         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2752         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2753                 break;
2754         }
2755
2756         wifi->state = state;
2757
2758         /* Saving wpa_s state policy:
2759          * If connected and if the state changes are roaming related:
2760          * --> We stay connected
2761          * If completed
2762          * --> We are connected
2763          * All other case:
2764          * --> We are not connected
2765          * */
2766         switch (state) {
2767 #if defined TIZEN_EXT
2768         case G_SUPPLICANT_STATE_SCANNING:
2769                 break;
2770 #endif
2771         case G_SUPPLICANT_STATE_AUTHENTICATING:
2772         case G_SUPPLICANT_STATE_ASSOCIATING:
2773         case G_SUPPLICANT_STATE_ASSOCIATED:
2774         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2775         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2776                 if (wifi->connected)
2777                         connman_warn("Probably roaming right now!"
2778                                                 " Staying connected...");
2779                 else
2780                         wifi->connected = false;
2781                 break;
2782         case G_SUPPLICANT_STATE_COMPLETED:
2783                 wifi->connected = true;
2784                 break;
2785         default:
2786                 wifi->connected = false;
2787                 break;
2788         }
2789
2790         DBG("DONE");
2791 }
2792
2793 static void interface_removed(GSupplicantInterface *interface)
2794 {
2795         const char *ifname = g_supplicant_interface_get_ifname(interface);
2796         struct wifi_data *wifi;
2797
2798         DBG("ifname %s", ifname);
2799
2800         wifi = g_supplicant_interface_get_data(interface);
2801
2802         if (wifi)
2803                 wifi->interface = NULL;
2804
2805         if (wifi && wifi->tethering)
2806                 return;
2807
2808         if (!wifi || !wifi->device) {
2809                 DBG("wifi interface already removed");
2810                 return;
2811         }
2812
2813         connman_device_set_powered(wifi->device, false);
2814
2815         check_p2p_technology();
2816 }
2817
2818 static void set_device_type(const char *type, char dev_type[17])
2819 {
2820         const char *oui = "0050F204";
2821         const char *category = "0100";
2822         const char *sub_category = "0000";
2823
2824         if (!g_strcmp0(type, "handset")) {
2825                 category = "0A00";
2826                 sub_category = "0500";
2827         } else if (!g_strcmp0(type, "vm") || !g_strcmp0(type, "container"))
2828                 sub_category = "0100";
2829         else if (!g_strcmp0(type, "server"))
2830                 sub_category = "0200";
2831         else if (!g_strcmp0(type, "laptop"))
2832                 sub_category = "0500";
2833         else if (!g_strcmp0(type, "desktop"))
2834                 sub_category = "0600";
2835         else if (!g_strcmp0(type, "tablet"))
2836                 sub_category = "0900";
2837         else if (!g_strcmp0(type, "watch"))
2838                 category = "FF00";
2839
2840         snprintf(dev_type, 17, "%s%s%s", category, oui, sub_category);
2841 }
2842
2843 static void p2p_support(GSupplicantInterface *interface)
2844 {
2845         char dev_type[17] = {};
2846         const char *hostname;
2847
2848         DBG("");
2849
2850         if (!g_supplicant_interface_has_p2p(interface))
2851                 return;
2852
2853         if (connman_technology_driver_register(&p2p_tech_driver) < 0) {
2854                 DBG("Could not register P2P technology driver");
2855                 return;
2856         }
2857
2858         hostname = connman_utsname_get_hostname();
2859         if (!hostname)
2860                 hostname = "ConnMan";
2861
2862         set_device_type(connman_machine_get_type(), dev_type);
2863         g_supplicant_interface_set_p2p_device_config(interface,
2864                                                         hostname, dev_type);
2865         connman_peer_driver_register(&peer_driver);
2866 }
2867
2868 static void scan_started(GSupplicantInterface *interface)
2869 {
2870         DBG("");
2871 }
2872
2873 static void scan_finished(GSupplicantInterface *interface)
2874 {
2875 #if defined TIZEN_EXT
2876         struct wifi_data *wifi;
2877         bool is_associating = false;
2878         static bool is_scanning = true;
2879 #endif
2880
2881         DBG("");
2882
2883 #if defined TIZEN_EXT
2884         wifi = g_supplicant_interface_get_data(interface);
2885         if (wifi && wifi->scan_pending_network) {
2886                 network_connect(wifi->scan_pending_network);
2887                 wifi->scan_pending_network = NULL;
2888         }
2889
2890         //service state - associating
2891         if(!wifi || !wifi->network)
2892                 return;
2893
2894         is_associating = connman_network_get_associating(wifi->network);
2895         if(is_associating && is_scanning){
2896                 is_scanning = false;
2897                 DBG("send scan for connecting");
2898                 throw_wifi_scan(wifi->device, scan_callback);
2899
2900                 return;
2901         }
2902         is_scanning = true;
2903
2904         //go scan
2905
2906 #endif
2907 }
2908
2909 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
2910 {
2911         unsigned char strength;
2912
2913         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
2914         if (strength > 100)
2915                 strength = 100;
2916
2917         return strength;
2918 }
2919
2920 static void network_added(GSupplicantNetwork *supplicant_network)
2921 {
2922         struct connman_network *network;
2923         GSupplicantInterface *interface;
2924         struct wifi_data *wifi;
2925         const char *name, *identifier, *security, *group, *mode;
2926         const unsigned char *ssid;
2927         unsigned int ssid_len;
2928         bool wps;
2929         bool wps_pbc;
2930         bool wps_ready;
2931         bool wps_advertizing;
2932
2933         mode = g_supplicant_network_get_mode(supplicant_network);
2934         identifier = g_supplicant_network_get_identifier(supplicant_network);
2935
2936         DBG("%s", identifier);
2937
2938         if (!g_strcmp0(mode, "adhoc"))
2939                 return;
2940
2941         interface = g_supplicant_network_get_interface(supplicant_network);
2942         wifi = g_supplicant_interface_get_data(interface);
2943         name = g_supplicant_network_get_name(supplicant_network);
2944         security = g_supplicant_network_get_security(supplicant_network);
2945         group = g_supplicant_network_get_identifier(supplicant_network);
2946         wps = g_supplicant_network_get_wps(supplicant_network);
2947         wps_pbc = g_supplicant_network_is_wps_pbc(supplicant_network);
2948         wps_ready = g_supplicant_network_is_wps_active(supplicant_network);
2949         wps_advertizing = g_supplicant_network_is_wps_advertizing(
2950                                                         supplicant_network);
2951
2952         if (!wifi)
2953                 return;
2954
2955         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
2956
2957         network = connman_device_get_network(wifi->device, identifier);
2958
2959         if (!network) {
2960                 network = connman_network_create(identifier,
2961                                                 CONNMAN_NETWORK_TYPE_WIFI);
2962                 if (!network)
2963                         return;
2964
2965                 connman_network_set_index(network, wifi->index);
2966
2967                 if (connman_device_add_network(wifi->device, network) < 0) {
2968                         connman_network_unref(network);
2969                         return;
2970                 }
2971
2972                 wifi->networks = g_slist_prepend(wifi->networks, network);
2973         }
2974
2975         if (name && name[0] != '\0')
2976                 connman_network_set_name(network, name);
2977
2978         connman_network_set_blob(network, "WiFi.SSID",
2979                                                 ssid, ssid_len);
2980         connman_network_set_string(network, "WiFi.Security", security);
2981         connman_network_set_strength(network,
2982                                 calculate_strength(supplicant_network));
2983         connman_network_set_bool(network, "WiFi.WPS", wps);
2984
2985         if (wps) {
2986                 /* Is AP advertizing for WPS association?
2987                  * If so, we decide to use WPS by default */
2988                 if (wps_ready && wps_pbc &&
2989                                                 wps_advertizing) {
2990 #if !defined TIZEN_EXT
2991                         connman_network_set_bool(network, "WiFi.UseWPS", true);
2992 #else
2993                         DBG("wps is activating by ap but ignore it.");
2994 #endif
2995                 }
2996         }
2997
2998         connman_network_set_frequency(network,
2999                         g_supplicant_network_get_frequency(supplicant_network));
3000 #if defined TIZEN_EXT
3001         connman_network_set_bssid(network,
3002                         g_supplicant_network_get_bssid(supplicant_network));
3003         connman_network_set_maxrate(network,
3004                         g_supplicant_network_get_maxrate(supplicant_network));
3005         connman_network_set_enc_mode(network,
3006                         g_supplicant_network_get_enc_mode(supplicant_network));
3007         connman_network_set_rsn_mode(network,
3008                         g_supplicant_network_get_rsn_mode(supplicant_network));
3009         connman_network_set_keymgmt(network,
3010                         g_supplicant_network_get_keymgmt(supplicant_network));
3011 #endif
3012         connman_network_set_available(network, true);
3013         connman_network_set_string(network, "WiFi.Mode", mode);
3014
3015 #if defined TIZEN_EXT
3016         if (group)
3017 #else
3018         if (ssid)
3019 #endif
3020                 connman_network_set_group(network, group);
3021
3022 #if defined TIZEN_EXT
3023         if (wifi_first_scan == true)
3024                 found_with_first_scan = true;
3025 #endif
3026
3027         if (wifi->hidden && ssid) {
3028 #if defined TIZEN_EXT
3029                 if (network_security(wifi->hidden->security) ==
3030                         network_security(security) &&
3031 #else
3032                 if (!g_strcmp0(wifi->hidden->security, security) &&
3033 #endif
3034                                 wifi->hidden->ssid_len == ssid_len &&
3035                                 !memcmp(wifi->hidden->ssid, ssid, ssid_len)) {
3036                         connman_network_connect_hidden(network,
3037                                         wifi->hidden->identity,
3038                                         wifi->hidden->passphrase,
3039                                         wifi->hidden->user_data);
3040                         wifi->hidden->user_data = NULL;
3041                         hidden_free(wifi->hidden);
3042                         wifi->hidden = NULL;
3043                 }
3044         }
3045 }
3046
3047 static void network_removed(GSupplicantNetwork *network)
3048 {
3049         GSupplicantInterface *interface;
3050         struct wifi_data *wifi;
3051         const char *name, *identifier;
3052         struct connman_network *connman_network;
3053
3054         interface = g_supplicant_network_get_interface(network);
3055         wifi = g_supplicant_interface_get_data(interface);
3056         identifier = g_supplicant_network_get_identifier(network);
3057         name = g_supplicant_network_get_name(network);
3058
3059         DBG("name %s", name);
3060
3061         if (!wifi)
3062                 return;
3063
3064         connman_network = connman_device_get_network(wifi->device, identifier);
3065         if (!connman_network)
3066                 return;
3067
3068 #if defined TIZEN_EXT
3069         if (connman_network == wifi->scan_pending_network)
3070                 wifi->scan_pending_network = NULL;
3071
3072         if (connman_network == wifi->pending_network)
3073                 wifi->pending_network = NULL;
3074
3075         if(connman_network_get_connecting(connman_network) == true){
3076                 connman_network_set_connected(connman_network, false);
3077         }
3078 #endif
3079
3080         wifi->networks = g_slist_remove(wifi->networks, connman_network);
3081
3082         connman_device_remove_network(wifi->device, connman_network);
3083         connman_network_unref(connman_network);
3084 }
3085
3086 static void network_changed(GSupplicantNetwork *network, const char *property)
3087 {
3088         GSupplicantInterface *interface;
3089         struct wifi_data *wifi;
3090         const char *name, *identifier;
3091         struct connman_network *connman_network;
3092
3093 #if defined TIZEN_EXT
3094         const unsigned char *bssid;
3095         unsigned int maxrate;
3096         uint16_t frequency;
3097         bool wps;
3098 #endif
3099
3100         interface = g_supplicant_network_get_interface(network);
3101         wifi = g_supplicant_interface_get_data(interface);
3102         identifier = g_supplicant_network_get_identifier(network);
3103         name = g_supplicant_network_get_name(network);
3104
3105         DBG("name %s", name);
3106
3107         if (!wifi)
3108                 return;
3109
3110         connman_network = connman_device_get_network(wifi->device, identifier);
3111         if (!connman_network)
3112                 return;
3113
3114         if (g_str_equal(property, "Signal")) {
3115                connman_network_set_strength(connman_network,
3116                                         calculate_strength(network));
3117                connman_network_update(connman_network);
3118         }
3119
3120 #if defined TIZEN_EXT
3121         bssid = g_supplicant_network_get_bssid(network);
3122         maxrate = g_supplicant_network_get_maxrate(network);
3123         frequency = g_supplicant_network_get_frequency(network);
3124         wps = g_supplicant_network_get_wps(network);
3125
3126         connman_network_set_bssid(connman_network, bssid);
3127         connman_network_set_maxrate(connman_network, maxrate);
3128         connman_network_set_frequency(connman_network, frequency);
3129         connman_network_set_bool(connman_network, "WiFi.WPS", wps);
3130 #endif
3131 }
3132
3133 static void apply_peer_services(GSupplicantPeer *peer,
3134                                 struct connman_peer *connman_peer)
3135 {
3136         const unsigned char *data;
3137         int length;
3138
3139         DBG("");
3140
3141         connman_peer_reset_services(connman_peer);
3142
3143         data = g_supplicant_peer_get_widi_ies(peer, &length);
3144         if (data) {
3145                 connman_peer_add_service(connman_peer,
3146                         CONNMAN_PEER_SERVICE_WIFI_DISPLAY, data, length);
3147         }
3148 }
3149
3150 static void add_station(const char *mac)
3151 {
3152         connman_technology_tethering_add_station(CONNMAN_SERVICE_TYPE_WIFI,
3153                                                  mac);
3154 }
3155
3156 static void remove_station(const char *mac)
3157 {
3158         connman_technology_tethering_remove_station(mac);
3159 }
3160
3161 static void peer_found(GSupplicantPeer *peer)
3162 {
3163         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3164         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3165         struct connman_peer *connman_peer;
3166         const char *identifier, *name;
3167         int ret;
3168
3169         identifier = g_supplicant_peer_get_identifier(peer);
3170         name = g_supplicant_peer_get_name(peer);
3171
3172         DBG("ident: %s", identifier);
3173
3174         connman_peer = connman_peer_get(wifi->device, identifier);
3175         if (connman_peer)
3176                 return;
3177
3178         connman_peer = connman_peer_create(identifier);
3179         connman_peer_set_name(connman_peer, name);
3180         connman_peer_set_device(connman_peer, wifi->device);
3181         apply_peer_services(peer, connman_peer);
3182
3183         ret = connman_peer_register(connman_peer);
3184         if (ret < 0 && ret != -EALREADY)
3185                 connman_peer_unref(connman_peer);
3186 }
3187
3188 static void peer_lost(GSupplicantPeer *peer)
3189 {
3190         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3191         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3192         struct connman_peer *connman_peer;
3193         const char *identifier;
3194
3195         if (!wifi)
3196                 return;
3197
3198         identifier = g_supplicant_peer_get_identifier(peer);
3199
3200         DBG("ident: %s", identifier);
3201
3202         connman_peer = connman_peer_get(wifi->device, identifier);
3203         if (connman_peer) {
3204                 if (wifi->p2p_connecting &&
3205                                 wifi->pending_peer == connman_peer) {
3206                         peer_connect_timeout(wifi);
3207                 }
3208                 connman_peer_unregister(connman_peer);
3209                 connman_peer_unref(connman_peer);
3210         }
3211 }
3212
3213 static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state)
3214 {
3215         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3216         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3217         enum connman_peer_state p_state = CONNMAN_PEER_STATE_UNKNOWN;
3218         struct connman_peer *connman_peer;
3219         const char *identifier;
3220
3221         identifier = g_supplicant_peer_get_identifier(peer);
3222
3223         DBG("ident: %s", identifier);
3224
3225         connman_peer = connman_peer_get(wifi->device, identifier);
3226         if (!connman_peer)
3227                 return;
3228
3229         switch (state) {
3230         case G_SUPPLICANT_PEER_SERVICES_CHANGED:
3231                 apply_peer_services(peer, connman_peer);
3232                 connman_peer_services_changed(connman_peer);
3233                 return;
3234         case G_SUPPLICANT_PEER_GROUP_CHANGED:
3235                 if (!g_supplicant_peer_is_in_a_group(peer))
3236                         p_state = CONNMAN_PEER_STATE_IDLE;
3237                 else
3238                         p_state = CONNMAN_PEER_STATE_CONFIGURATION;
3239                 break;
3240         case G_SUPPLICANT_PEER_GROUP_STARTED:
3241                 break;
3242         case G_SUPPLICANT_PEER_GROUP_FINISHED:
3243                 p_state = CONNMAN_PEER_STATE_IDLE;
3244                 break;
3245         case G_SUPPLICANT_PEER_GROUP_JOINED:
3246                 connman_peer_set_iface_address(connman_peer,
3247                                 g_supplicant_peer_get_iface_address(peer));
3248                 break;
3249         case G_SUPPLICANT_PEER_GROUP_DISCONNECTED:
3250                 p_state = CONNMAN_PEER_STATE_IDLE;
3251                 break;
3252         case G_SUPPLICANT_PEER_GROUP_FAILED:
3253                 if (g_supplicant_peer_has_requested_connection(peer))
3254                         p_state = CONNMAN_PEER_STATE_IDLE;
3255                 else
3256                         p_state = CONNMAN_PEER_STATE_FAILURE;
3257                 break;
3258         }
3259
3260         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION ||
3261                                         p_state == CONNMAN_PEER_STATE_FAILURE) {
3262                 if (wifi->p2p_connecting
3263                                 && connman_peer == wifi->pending_peer)
3264                         peer_cancel_timeout(wifi);
3265                 else
3266                         p_state = CONNMAN_PEER_STATE_UNKNOWN;
3267         }
3268
3269         if (p_state == CONNMAN_PEER_STATE_UNKNOWN)
3270                 return;
3271
3272         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION) {
3273                 GSupplicantInterface *g_iface;
3274                 struct wifi_data *g_wifi;
3275
3276                 g_iface = g_supplicant_peer_get_group_interface(peer);
3277                 if (!g_iface)
3278                         return;
3279
3280                 g_wifi = g_supplicant_interface_get_data(g_iface);
3281                 if (!g_wifi)
3282                         return;
3283
3284                 connman_peer_set_as_master(connman_peer,
3285                                         !g_supplicant_peer_is_client(peer));
3286                 connman_peer_set_sub_device(connman_peer, g_wifi->device);
3287         }
3288
3289         connman_peer_set_state(connman_peer, p_state);
3290 }
3291
3292 static void peer_request(GSupplicantPeer *peer)
3293 {
3294         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3295         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3296         struct connman_peer *connman_peer;
3297         const char *identifier;
3298
3299         identifier = g_supplicant_peer_get_identifier(peer);
3300
3301         DBG("ident: %s", identifier);
3302
3303         connman_peer = connman_peer_get(wifi->device, identifier);
3304         if (!connman_peer)
3305                 return;
3306
3307         connman_peer_request_connection(connman_peer);
3308 }
3309
3310 #if defined TIZEN_EXT
3311 static void system_power_off(void)
3312 {
3313         GList *list;
3314         struct wifi_data *wifi;
3315         struct connman_service *service;
3316         struct connman_ipconfig *ipconfig_ipv4;
3317
3318         if (connman_setting_get_bool("WiFiDHCPRelease") == true) {
3319                 for (list = iface_list; list; list = list->next) {
3320                         wifi = list->data;
3321
3322                         if (wifi->network != NULL) {
3323                                 service = connman_service_lookup_from_network(wifi->network);
3324                                 ipconfig_ipv4 = __connman_service_get_ip4config(service);
3325                                 __connman_dhcp_stop(ipconfig_ipv4);
3326                         }
3327                 }
3328         }
3329 }
3330
3331 static void network_merged(GSupplicantNetwork *network)
3332 {
3333         GSupplicantInterface *interface;
3334         GSupplicantState state;
3335         struct wifi_data *wifi;
3336         const char *identifier;
3337         struct connman_network *connman_network;
3338         unsigned int ishs20AP = 0;
3339         char *temp = NULL;
3340
3341         interface = g_supplicant_network_get_interface(network);
3342         if (!interface)
3343                 return;
3344
3345         state = g_supplicant_interface_get_state(interface);
3346         if (state < G_SUPPLICANT_STATE_AUTHENTICATING)
3347                 return;
3348
3349         wifi = g_supplicant_interface_get_data(interface);
3350         if (!wifi)
3351                 return;
3352
3353         identifier = g_supplicant_network_get_identifier(network);
3354
3355         connman_network = connman_device_get_network(wifi->device, identifier);
3356         if (!connman_network)
3357                 return;
3358
3359         DBG("merged identifier %s", identifier);
3360
3361         if (wifi->connected == FALSE) {
3362                 switch (state) {
3363                 case G_SUPPLICANT_STATE_AUTHENTICATING:
3364                 case G_SUPPLICANT_STATE_ASSOCIATING:
3365                 case G_SUPPLICANT_STATE_ASSOCIATED:
3366                 case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3367                 case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3368                         connman_network_set_associating(connman_network, TRUE);
3369                         break;
3370                 case G_SUPPLICANT_STATE_COMPLETED:
3371                         connman_network_set_connected(connman_network, TRUE);
3372                         break;
3373                 default:
3374                         DBG("Not handled the state : %d", state);
3375                         break;
3376                 }
3377         }
3378
3379         ishs20AP = g_supplicant_network_is_hs20AP(network);
3380         connman_network_set_is_hs20AP(connman_network, ishs20AP);
3381
3382         if (ishs20AP &&
3383                 g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) {
3384                 temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1);
3385                 connman_network_set_string(connman_network, "WiFi.EAP",
3386                                 temp);
3387                 connman_network_set_string(connman_network, "WiFi.Identity",
3388                                 g_supplicant_network_get_identity(network));
3389                 connman_network_set_string(connman_network, "WiFi.Phase2",
3390                                 g_supplicant_network_get_phase2(network));
3391
3392                 g_free(temp);
3393         }
3394
3395         wifi->network = connman_network;
3396 }
3397 #endif
3398
3399 static void debug(const char *str)
3400 {
3401         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
3402                 connman_debug("%s", str);
3403 }
3404
3405 static const GSupplicantCallbacks callbacks = {
3406         .system_ready           = system_ready,
3407         .system_killed          = system_killed,
3408         .interface_added        = interface_added,
3409         .interface_state        = interface_state,
3410         .interface_removed      = interface_removed,
3411         .p2p_support            = p2p_support,
3412         .scan_started           = scan_started,
3413         .scan_finished          = scan_finished,
3414         .network_added          = network_added,
3415         .network_removed        = network_removed,
3416         .network_changed        = network_changed,
3417         .add_station            = add_station,
3418         .remove_station         = remove_station,
3419         .peer_found             = peer_found,
3420         .peer_lost              = peer_lost,
3421         .peer_changed           = peer_changed,
3422         .peer_request           = peer_request,
3423 #if defined TIZEN_EXT
3424         .system_power_off       = system_power_off,
3425         .network_merged = network_merged,
3426 #endif
3427         .debug                  = debug,
3428 };
3429
3430
3431 static int tech_probe(struct connman_technology *technology)
3432 {
3433         wifi_technology = technology;
3434
3435         return 0;
3436 }
3437
3438 static void tech_remove(struct connman_technology *technology)
3439 {
3440         wifi_technology = NULL;
3441 }
3442
3443 struct wifi_tethering_info {
3444         struct wifi_data *wifi;
3445         struct connman_technology *technology;
3446         char *ifname;
3447         GSupplicantSSID *ssid;
3448 };
3449
3450 static GSupplicantSSID *ssid_ap_init(const char *ssid,
3451                 const char *passphrase, bool hidden)
3452 {
3453         GSupplicantSSID *ap;
3454
3455         ap = g_try_malloc0(sizeof(GSupplicantSSID));
3456         if (!ap)
3457                 return NULL;
3458
3459         ap->mode = G_SUPPLICANT_MODE_MASTER;
3460         ap->ssid = ssid;
3461         ap->ssid_len = strlen(ssid);
3462         ap->scan_ssid = 0;
3463         ap->freq = 2412;
3464
3465         if (!passphrase || strlen(passphrase) == 0) {
3466                 ap->security = G_SUPPLICANT_SECURITY_NONE;
3467                 ap->passphrase = NULL;
3468         } else {
3469                ap->security = G_SUPPLICANT_SECURITY_PSK;
3470                ap->protocol = G_SUPPLICANT_PROTO_RSN;
3471                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
3472                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
3473                ap->passphrase = passphrase;
3474         }
3475
3476         if (hidden)
3477                 ap->ignore_broadcast_ssid =
3478                                 G_SUPPLICANT_AP_HIDDEN_SSID_ZERO_CONTENTS;
3479         else
3480                 ap->ignore_broadcast_ssid = G_SUPPLICANT_AP_NO_SSID_HIDING;
3481
3482         return ap;
3483 }
3484
3485 static void ap_start_callback(int result, GSupplicantInterface *interface,
3486                                                         void *user_data)
3487 {
3488         struct wifi_tethering_info *info = user_data;
3489
3490         DBG("result %d index %d bridge %s",
3491                 result, info->wifi->index, info->wifi->bridge);
3492
3493         if (result < 0) {
3494                 connman_inet_remove_from_bridge(info->wifi->index,
3495                                                         info->wifi->bridge);
3496                 connman_technology_tethering_notify(info->technology, false);
3497         }
3498
3499         g_free(info->ifname);
3500         g_free(info);
3501 }
3502
3503 static void ap_create_callback(int result,
3504                                 GSupplicantInterface *interface,
3505                                         void *user_data)
3506 {
3507         struct wifi_tethering_info *info = user_data;
3508
3509         DBG("result %d ifname %s", result,
3510                                 g_supplicant_interface_get_ifname(interface));
3511
3512         if (result < 0) {
3513                 connman_inet_remove_from_bridge(info->wifi->index,
3514                                                         info->wifi->bridge);
3515                 connman_technology_tethering_notify(info->technology, false);
3516
3517                 g_free(info->ifname);
3518                 g_free(info->ssid);
3519                 g_free(info);
3520                 return;
3521         }
3522
3523         info->wifi->interface = interface;
3524         g_supplicant_interface_set_data(interface, info->wifi);
3525
3526         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
3527                 connman_error("Failed to set interface ap_scan property");
3528
3529         g_supplicant_interface_connect(interface, info->ssid,
3530                                                 ap_start_callback, info);
3531 }
3532
3533 static void sta_remove_callback(int result,
3534                                 GSupplicantInterface *interface,
3535                                         void *user_data)
3536 {
3537         struct wifi_tethering_info *info = user_data;
3538         const char *driver = connman_option_get_string("wifi");
3539
3540         DBG("ifname %s result %d ", info->ifname, result);
3541
3542         if (result < 0) {
3543                 info->wifi->tethering = true;
3544
3545                 g_free(info->ifname);
3546                 g_free(info->ssid);
3547                 g_free(info);
3548                 return;
3549         }
3550
3551         info->wifi->interface = NULL;
3552
3553         connman_technology_tethering_notify(info->technology, true);
3554
3555         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
3556                                                 ap_create_callback,
3557                                                         info);
3558 }
3559
3560 static int tech_set_tethering(struct connman_technology *technology,
3561                                 const char *identifier, const char *passphrase,
3562                                 const char *bridge, bool enabled, bool hidden)
3563 {
3564         GList *list;
3565         GSupplicantInterface *interface;
3566         struct wifi_data *wifi;
3567         struct wifi_tethering_info *info;
3568         const char *ifname;
3569         unsigned int mode;
3570         int err;
3571
3572         DBG("");
3573
3574         if (!enabled) {
3575                 for (list = iface_list; list; list = list->next) {
3576                         wifi = list->data;
3577
3578                         if (wifi->tethering) {
3579                                 wifi->tethering = false;
3580
3581                                 connman_inet_remove_from_bridge(wifi->index,
3582                                                                         bridge);
3583                                 wifi->bridged = false;
3584                         }
3585                 }
3586
3587                 connman_technology_tethering_notify(technology, false);
3588
3589                 return 0;
3590         }
3591
3592         for (list = iface_list; list; list = list->next) {
3593                 wifi = list->data;
3594
3595                 interface = wifi->interface;
3596
3597                 if (!interface)
3598                         continue;
3599
3600                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
3601
3602                 mode = g_supplicant_interface_get_mode(interface);
3603                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
3604                         DBG("%s does not support AP mode", ifname);
3605                         continue;
3606                 }
3607
3608                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
3609                 if (!info)
3610                         return -ENOMEM;
3611
3612                 info->wifi = wifi;
3613                 info->technology = technology;
3614                 info->wifi->bridge = bridge;
3615                 info->ssid = ssid_ap_init(identifier, passphrase, hidden);
3616                 if (!info->ssid) {
3617                         g_free(info);
3618                         continue;
3619                 }
3620                 info->ifname = g_strdup(ifname);
3621                 if (!info->ifname) {
3622                         g_free(info->ssid);
3623                         g_free(info);
3624                         continue;
3625                 }
3626
3627                 info->wifi->tethering = true;
3628
3629                 err = g_supplicant_interface_remove(interface,
3630                                                 sta_remove_callback,
3631                                                         info);
3632                 if (err == 0)
3633                         return err;
3634         }
3635
3636         return -EOPNOTSUPP;
3637 }
3638
3639 static void regdom_callback(int result, const char *alpha2, void *user_data)
3640 {
3641         DBG("");
3642
3643         if (!wifi_technology)
3644                 return;
3645
3646         if (result != 0)
3647                 alpha2 = NULL;
3648
3649         connman_technology_regdom_notify(wifi_technology, alpha2);
3650 }
3651
3652 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
3653 {
3654         return g_supplicant_set_country(alpha2, regdom_callback, NULL);
3655 }
3656
3657 static struct connman_technology_driver tech_driver = {
3658         .name           = "wifi",
3659         .type           = CONNMAN_SERVICE_TYPE_WIFI,
3660         .probe          = tech_probe,
3661         .remove         = tech_remove,
3662         .set_tethering  = tech_set_tethering,
3663         .set_regdom     = tech_set_regdom,
3664 };
3665
3666 static int wifi_init(void)
3667 {
3668         int err;
3669
3670         err = connman_network_driver_register(&network_driver);
3671         if (err < 0)
3672                 return err;
3673
3674         err = g_supplicant_register(&callbacks);
3675         if (err < 0) {
3676                 connman_network_driver_unregister(&network_driver);
3677                 return err;
3678         }
3679
3680         err = connman_technology_driver_register(&tech_driver);
3681         if (err < 0) {
3682                 g_supplicant_unregister(&callbacks);
3683                 connman_network_driver_unregister(&network_driver);
3684                 return err;
3685         }
3686
3687         return 0;
3688 }
3689
3690 static void wifi_exit(void)
3691 {
3692         DBG();
3693
3694         connman_technology_driver_unregister(&tech_driver);
3695
3696         g_supplicant_unregister(&callbacks);
3697
3698         connman_network_driver_unregister(&network_driver);
3699 }
3700
3701 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
3702                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)