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