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