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