Added new dbus method to support bssid based connection
[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         set_connman_bssid(RESET_BSSID, NULL);
2397
2398         for (list = iface_list; list; list = list->next) {
2399                 wifi = list->data;
2400
2401                 if (wifi && wifi->network == network)
2402                         goto found;
2403         }
2404
2405         /* wifi_data may be invalid because wifi is already disabled */
2406         return;
2407
2408 found:
2409 #endif
2410         if (result == -ENOKEY) {
2411                 connman_network_set_error(network,
2412                                         CONNMAN_NETWORK_ERROR_INVALID_KEY);
2413         } else if (result < 0) {
2414                 connman_network_set_error(network,
2415                                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
2416         }
2417
2418         connman_network_unref(network);
2419 }
2420
2421 static GSupplicantSecurity network_security(const char *security)
2422 {
2423         if (g_str_equal(security, "none"))
2424                 return G_SUPPLICANT_SECURITY_NONE;
2425         else if (g_str_equal(security, "wep"))
2426                 return G_SUPPLICANT_SECURITY_WEP;
2427         else if (g_str_equal(security, "psk"))
2428                 return G_SUPPLICANT_SECURITY_PSK;
2429         else if (g_str_equal(security, "wpa"))
2430                 return G_SUPPLICANT_SECURITY_PSK;
2431         else if (g_str_equal(security, "rsn"))
2432                 return G_SUPPLICANT_SECURITY_PSK;
2433         else if (g_str_equal(security, "ieee8021x"))
2434                 return G_SUPPLICANT_SECURITY_IEEE8021X;
2435 #if defined TIZEN_EXT
2436         else if (g_str_equal(security, "ft_psk") == TRUE)
2437                 return G_SUPPLICANT_SECURITY_FT_PSK;
2438         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
2439                 return G_SUPPLICANT_SECURITY_FT_IEEE8021X;
2440 #endif
2441
2442         return G_SUPPLICANT_SECURITY_UNKNOWN;
2443 }
2444
2445 static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
2446 {
2447         const char *security;
2448
2449         memset(ssid, 0, sizeof(*ssid));
2450         ssid->mode = G_SUPPLICANT_MODE_INFRA;
2451         ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
2452                                                 &ssid->ssid_len);
2453         ssid->scan_ssid = 1;
2454         security = connman_network_get_string(network, "WiFi.Security");
2455         ssid->security = network_security(security);
2456         ssid->passphrase = connman_network_get_string(network,
2457                                                 "WiFi.Passphrase");
2458         ssid->eap = connman_network_get_string(network, "WiFi.EAP");
2459
2460         /*
2461          * If our private key password is unset,
2462          * we use the supplied passphrase. That is needed
2463          * for PEAP where 2 passphrases (identity and client
2464          * cert may have to be provided.
2465          */
2466         if (!connman_network_get_string(network, "WiFi.PrivateKeyPassphrase"))
2467                 connman_network_set_string(network,
2468                                                 "WiFi.PrivateKeyPassphrase",
2469                                                 ssid->passphrase);
2470         /* We must have an identity for both PEAP and TLS */
2471         ssid->identity = connman_network_get_string(network, "WiFi.Identity");
2472
2473         /* Use agent provided identity as a fallback */
2474         if (!ssid->identity || strlen(ssid->identity) == 0)
2475                 ssid->identity = connman_network_get_string(network,
2476                                                         "WiFi.AgentIdentity");
2477
2478         ssid->anonymous_identity = connman_network_get_string(network,
2479                                                 "WiFi.AnonymousIdentity");
2480         ssid->ca_cert_path = connman_network_get_string(network,
2481                                                         "WiFi.CACertFile");
2482         ssid->subject_match = connman_network_get_string(network,
2483                                                         "WiFi.SubjectMatch");
2484         ssid->altsubject_match = connman_network_get_string(network,
2485                                                         "WiFi.AltSubjectMatch");
2486         ssid->domain_suffix_match = connman_network_get_string(network,
2487                                                         "WiFi.DomainSuffixMatch");
2488         ssid->domain_match = connman_network_get_string(network,
2489                                                         "WiFi.DomainMatch");
2490         ssid->client_cert_path = connman_network_get_string(network,
2491                                                         "WiFi.ClientCertFile");
2492         ssid->private_key_path = connman_network_get_string(network,
2493                                                         "WiFi.PrivateKeyFile");
2494         ssid->private_key_passphrase = connman_network_get_string(network,
2495                                                 "WiFi.PrivateKeyPassphrase");
2496         ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
2497
2498         ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS");
2499         ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS");
2500
2501 #if defined TIZEN_EXT
2502         ssid->bssid = connman_network_get_bssid(network);
2503 #endif
2504 #if defined TIZEN_EXT
2505         if (set_connman_bssid(CHECK_BSSID, NULL) == 6) {
2506                 ssid->bssid_for_connect_len = 6;
2507                 set_connman_bssid(GET_BSSID, (char *)ssid->bssid_for_connect);
2508                 DBG("BSSID : %02x:%02x:%02x:%02x:%02x:%02x",
2509                         ssid->bssid_for_connect[0], ssid->bssid_for_connect[1],
2510                         ssid->bssid_for_connect[2], ssid->bssid_for_connect[3],
2511                         ssid->bssid_for_connect[4], ssid->bssid_for_connect[5]);
2512         } else {
2513                 ssid->freq = connman_network_get_frequency(network);
2514         }
2515 #endif
2516
2517         if (connman_setting_get_bool("BackgroundScanning"))
2518                 ssid->bgscan = BGSCAN_DEFAULT;
2519 }
2520
2521 static int network_connect(struct connman_network *network)
2522 {
2523         struct connman_device *device = connman_network_get_device(network);
2524         struct wifi_data *wifi;
2525         GSupplicantInterface *interface;
2526         GSupplicantSSID *ssid;
2527
2528         DBG("network %p", network);
2529
2530         if (!device)
2531                 return -ENODEV;
2532
2533         wifi = connman_device_get_data(device);
2534         if (!wifi)
2535                 return -ENODEV;
2536
2537         ssid = g_try_malloc0(sizeof(GSupplicantSSID));
2538         if (!ssid)
2539                 return -ENOMEM;
2540
2541         interface = wifi->interface;
2542
2543         ssid_init(ssid, network);
2544
2545         if (wifi->disconnecting) {
2546                 wifi->pending_network = network;
2547                 g_free(ssid);
2548         } else {
2549                 wifi->network = connman_network_ref(network);
2550                 wifi->retries = 0;
2551 #if defined TIZEN_EXT
2552                 wifi->scan_pending_network = NULL;
2553 #endif
2554
2555                 return g_supplicant_interface_connect(interface, ssid,
2556                                                 connect_callback, network);
2557         }
2558
2559         return -EINPROGRESS;
2560 }
2561
2562 static void disconnect_callback(int result, GSupplicantInterface *interface,
2563                                                                 void *user_data)
2564 {
2565 #if defined TIZEN_EXT
2566         GList *list;
2567         struct wifi_data *wifi;
2568         struct connman_network *network = user_data;
2569
2570         DBG("network %p result %d", network, result);
2571
2572         for (list = iface_list; list; list = list->next) {
2573                 wifi = list->data;
2574
2575                 if (wifi->network == NULL && wifi->disconnecting == true)
2576                         wifi->disconnecting = false;
2577
2578                 if (wifi->network == network)
2579                         goto found;
2580         }
2581
2582         /* wifi_data may be invalid because wifi is already disabled */
2583         return;
2584
2585 found:
2586 #else
2587         struct wifi_data *wifi = user_data;
2588 #endif
2589
2590         DBG("result %d supplicant interface %p wifi %p",
2591                         result, interface, wifi);
2592
2593         if (result == -ECONNABORTED) {
2594                 DBG("wifi interface no longer available");
2595                 return;
2596         }
2597
2598         if (wifi->network) {
2599                 connman_network_set_connected(wifi->network, false);
2600                 wifi->network = NULL;
2601         }
2602
2603         wifi->disconnecting = false;
2604         wifi->connected = false;
2605
2606         if (wifi->pending_network) {
2607                 network_connect(wifi->pending_network);
2608                 wifi->pending_network = NULL;
2609         }
2610
2611         start_autoscan(wifi->device);
2612 }
2613
2614 static int network_disconnect(struct connman_network *network)
2615 {
2616         struct connman_device *device = connman_network_get_device(network);
2617         struct wifi_data *wifi;
2618         int err;
2619 #if defined TIZEN_EXT
2620         struct connman_service *service;
2621 #endif
2622
2623         DBG("network %p", network);
2624
2625         wifi = connman_device_get_data(device);
2626         if (!wifi || !wifi->interface)
2627                 return -ENODEV;
2628
2629 #if defined TIZEN_EXT
2630         if (connman_network_get_associating(network) == true) {
2631                 connman_network_clear_associating(network);
2632                 connman_network_set_bool(network, "WiFi.UseWPS", false);
2633         } else {
2634                 service = connman_service_lookup_from_network(network);
2635
2636                 if (service != NULL &&
2637                         (__connman_service_is_connected_state(service,
2638                                         CONNMAN_IPCONFIG_TYPE_IPV4) == false &&
2639                         __connman_service_is_connected_state(service,
2640                                         CONNMAN_IPCONFIG_TYPE_IPV6) == false) &&
2641                         (connman_service_get_favorite(service) == false))
2642                                         __connman_service_set_passphrase(service, NULL);
2643         }
2644
2645         if (wifi->pending_network == network)
2646                 wifi->pending_network = NULL;
2647
2648         if (wifi->scan_pending_network == network)
2649                 wifi->scan_pending_network = NULL;
2650
2651 #endif
2652         connman_network_set_associating(network, false);
2653
2654         if (wifi->disconnecting)
2655                 return -EALREADY;
2656
2657         wifi->disconnecting = true;
2658
2659 #if defined TIZEN_EXT
2660         err = g_supplicant_interface_disconnect(wifi->interface,
2661                                                 disconnect_callback, network);
2662 #else
2663         err = g_supplicant_interface_disconnect(wifi->interface,
2664                                                 disconnect_callback, wifi);
2665 #endif
2666
2667         if (err < 0)
2668                 wifi->disconnecting = false;
2669
2670         return err;
2671 }
2672
2673 static struct connman_network_driver network_driver = {
2674         .name           = "wifi",
2675         .type           = CONNMAN_NETWORK_TYPE_WIFI,
2676         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
2677         .probe          = network_probe,
2678         .remove         = network_remove,
2679         .connect        = network_connect,
2680         .disconnect     = network_disconnect,
2681 };
2682
2683 static void interface_added(GSupplicantInterface *interface)
2684 {
2685         const char *ifname = g_supplicant_interface_get_ifname(interface);
2686         const char *driver = g_supplicant_interface_get_driver(interface);
2687         struct wifi_data *wifi;
2688
2689         wifi = g_supplicant_interface_get_data(interface);
2690         if (!wifi) {
2691                 wifi = get_pending_wifi_data(ifname);
2692                 if (!wifi)
2693                         return;
2694
2695                 wifi->interface = interface;
2696                 g_supplicant_interface_set_data(interface, wifi);
2697                 p2p_iface_list = g_list_append(p2p_iface_list, wifi);
2698                 wifi->p2p_device = true;
2699         }
2700
2701         DBG("ifname %s driver %s wifi %p tethering %d",
2702                         ifname, driver, wifi, wifi->tethering);
2703
2704         if (!wifi->device) {
2705                 connman_error("WiFi device not set");
2706                 return;
2707         }
2708
2709         connman_device_set_powered(wifi->device, true);
2710 }
2711
2712 static bool is_idle(struct wifi_data *wifi)
2713 {
2714         DBG("state %d", wifi->state);
2715
2716         switch (wifi->state) {
2717         case G_SUPPLICANT_STATE_UNKNOWN:
2718         case G_SUPPLICANT_STATE_DISABLED:
2719         case G_SUPPLICANT_STATE_DISCONNECTED:
2720         case G_SUPPLICANT_STATE_INACTIVE:
2721         case G_SUPPLICANT_STATE_SCANNING:
2722                 return true;
2723
2724         case G_SUPPLICANT_STATE_AUTHENTICATING:
2725         case G_SUPPLICANT_STATE_ASSOCIATING:
2726         case G_SUPPLICANT_STATE_ASSOCIATED:
2727         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2728         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2729         case G_SUPPLICANT_STATE_COMPLETED:
2730                 return false;
2731         }
2732
2733         return false;
2734 }
2735
2736 static bool is_idle_wps(GSupplicantInterface *interface,
2737                                                 struct wifi_data *wifi)
2738 {
2739         /* First, let's check if WPS processing did not went wrong */
2740         if (g_supplicant_interface_get_wps_state(interface) ==
2741                 G_SUPPLICANT_WPS_STATE_FAIL)
2742                 return false;
2743
2744         /* Unlike normal connection, being associated while processing wps
2745          * actually means that we are idling. */
2746         switch (wifi->state) {
2747         case G_SUPPLICANT_STATE_UNKNOWN:
2748         case G_SUPPLICANT_STATE_DISABLED:
2749         case G_SUPPLICANT_STATE_DISCONNECTED:
2750         case G_SUPPLICANT_STATE_INACTIVE:
2751         case G_SUPPLICANT_STATE_SCANNING:
2752         case G_SUPPLICANT_STATE_ASSOCIATED:
2753                 return true;
2754         case G_SUPPLICANT_STATE_AUTHENTICATING:
2755         case G_SUPPLICANT_STATE_ASSOCIATING:
2756         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2757         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2758         case G_SUPPLICANT_STATE_COMPLETED:
2759                 return false;
2760         }
2761
2762         return false;
2763 }
2764
2765 static bool handle_wps_completion(GSupplicantInterface *interface,
2766                                         struct connman_network *network,
2767                                         struct connman_device *device,
2768                                         struct wifi_data *wifi)
2769 {
2770         bool wps;
2771
2772         wps = connman_network_get_bool(network, "WiFi.UseWPS");
2773         if (wps) {
2774                 const unsigned char *ssid, *wps_ssid;
2775                 unsigned int ssid_len, wps_ssid_len;
2776                 const char *wps_key;
2777
2778                 /* Checking if we got associated with requested
2779                  * network */
2780                 ssid = connman_network_get_blob(network, "WiFi.SSID",
2781                                                 &ssid_len);
2782
2783                 wps_ssid = g_supplicant_interface_get_wps_ssid(
2784                         interface, &wps_ssid_len);
2785
2786                 if (!wps_ssid || wps_ssid_len != ssid_len ||
2787                                 memcmp(ssid, wps_ssid, ssid_len) != 0) {
2788                         connman_network_set_associating(network, false);
2789 #if defined TIZEN_EXT
2790                         g_supplicant_interface_disconnect(wifi->interface,
2791                                                 disconnect_callback, wifi->network);
2792
2793                         connman_network_set_bool(network, "WiFi.UseWPS", false);
2794                         connman_network_set_string(network, "WiFi.PinWPS", NULL);
2795 #else
2796                         g_supplicant_interface_disconnect(wifi->interface,
2797                                                 disconnect_callback, wifi);
2798 #endif
2799                         return false;
2800                 }
2801
2802                 wps_key = g_supplicant_interface_get_wps_key(interface);
2803 #if defined TIZEN_EXT
2804                 /* Check the passphrase and encrypt it
2805                  */
2806                  int ret;
2807                  gchar *passphrase = g_strdup(wps_key);
2808
2809                  connman_network_set_string(network, "WiFi.PinWPS", NULL);
2810
2811                  if (check_passphrase_ext(network, passphrase) < 0) {
2812                          DBG("[WPS] Invalid passphrase");
2813                          g_free(passphrase);
2814                          return true;
2815                  }
2816
2817                  ret = send_encryption_request(passphrase, network);
2818
2819                  g_free(passphrase);
2820
2821                  if (!ret)
2822                          DBG("[WPS] Encryption request succeeded");
2823                  else
2824                          DBG("[WPS] Encryption request failed %d", ret);
2825
2826 #else
2827                 connman_network_set_string(network, "WiFi.Passphrase",
2828                                         wps_key);
2829
2830                 connman_network_set_string(network, "WiFi.PinWPS", NULL);
2831 #endif
2832         }
2833
2834         return true;
2835 }
2836
2837 static bool handle_assoc_status_code(GSupplicantInterface *interface,
2838                                      struct wifi_data *wifi)
2839 {
2840         if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING &&
2841                         wifi->assoc_code == ASSOC_STATUS_NO_CLIENT &&
2842                         wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) {
2843                 wifi->load_shaping_retries ++;
2844                 return TRUE;
2845         }
2846         wifi->load_shaping_retries = 0;
2847         return FALSE;
2848 }
2849
2850 static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
2851                                         struct connman_network *network,
2852                                         struct wifi_data *wifi)
2853 {
2854 #if defined TIZEN_EXT
2855         const char *security;
2856         struct connman_service *service;
2857
2858         if (wifi->connected)
2859                 return false;
2860
2861         security = connman_network_get_string(network, "WiFi.Security");
2862
2863         if (security && g_str_equal(security, "ieee8021x") == true &&
2864                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
2865                 wifi->retries = 0;
2866                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
2867
2868                 return false;
2869         }
2870
2871         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
2872                 return false;
2873 #else
2874         struct connman_service *service;
2875
2876         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
2877                 return false;
2878
2879         if (wifi->connected)
2880                 return false;
2881 #endif
2882
2883         service = connman_service_lookup_from_network(network);
2884         if (!service)
2885                 return false;
2886
2887         wifi->retries++;
2888
2889         if (connman_service_get_favorite(service)) {
2890                 if (wifi->retries < FAVORITE_MAXIMUM_RETRIES)
2891                         return true;
2892         }
2893
2894         wifi->retries = 0;
2895         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
2896
2897         return false;
2898 }
2899
2900 #if defined TIZEN_EXT
2901 static bool handle_wifi_assoc_retry(struct connman_network *network,
2902                                         struct wifi_data *wifi)
2903 {
2904         const char *security;
2905
2906         if (!wifi->network || wifi->connected || wifi->disconnecting ||
2907                         connman_network_get_connecting(network) != true) {
2908                 wifi->assoc_retry_count = 0;
2909                 return false;
2910         }
2911
2912         if (wifi->state != G_SUPPLICANT_STATE_ASSOCIATING &&
2913                         wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) {
2914                 wifi->assoc_retry_count = 0;
2915                 return false;
2916         }
2917
2918         security = connman_network_get_string(network, "WiFi.Security");
2919         if (security && g_str_equal(security, "ieee8021x") == true &&
2920                         wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) {
2921                 wifi->assoc_retry_count = 0;
2922                 return false;
2923         }
2924
2925         if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) {
2926                 wifi->assoc_retry_count = 0;
2927
2928                 /* Honestly it's not an invalid-key error,
2929                  * however QA team recommends that the invalid-key error
2930                  * might be better to display for user experience.
2931                  */
2932                 connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
2933
2934                 return false;
2935         }
2936
2937         return true;
2938 }
2939 #endif
2940
2941 static void interface_state(GSupplicantInterface *interface)
2942 {
2943         struct connman_network *network;
2944         struct connman_device *device;
2945         struct wifi_data *wifi;
2946         GSupplicantState state = g_supplicant_interface_get_state(interface);
2947         bool wps;
2948         bool old_connected;
2949
2950         wifi = g_supplicant_interface_get_data(interface);
2951
2952         DBG("wifi %p interface state %d", wifi, state);
2953
2954         if (!wifi)
2955                 return;
2956
2957         if (state == G_SUPPLICANT_STATE_COMPLETED) {
2958                 if (wifi->tethering_param) {
2959                         g_free(wifi->tethering_param->ssid);
2960                         g_free(wifi->tethering_param);
2961                         wifi->tethering_param = NULL;
2962                 }
2963         }
2964
2965         device = wifi->device;
2966         if (!device)
2967                 return;
2968
2969         if (g_supplicant_interface_get_ready(interface) &&
2970                                         !wifi->interface_ready) {
2971                 wifi->interface_ready = true;
2972                 finalize_interface_creation(wifi);
2973         }
2974
2975         network = wifi->network;
2976         if (!network)
2977                 return;
2978
2979         switch (state) {
2980         case G_SUPPLICANT_STATE_SCANNING:
2981                 if (wifi->connected)
2982                         connman_network_set_connected(network, false);
2983
2984                 break;
2985
2986         case G_SUPPLICANT_STATE_AUTHENTICATING:
2987         case G_SUPPLICANT_STATE_ASSOCIATING:
2988 #if defined TIZEN_EXT
2989                 reset_autoscan(device);
2990 #else
2991                 stop_autoscan(device);
2992 #endif
2993
2994                 if (!wifi->connected)
2995                         connman_network_set_associating(network, true);
2996
2997                 break;
2998
2999         case G_SUPPLICANT_STATE_COMPLETED:
3000 #if defined TIZEN_EXT
3001                 /* though it should be already reset: */
3002                 reset_autoscan(device);
3003
3004                 wifi->assoc_retry_count = 0;
3005
3006                 wifi->scan_pending_network = NULL;
3007
3008                 /* should be cleared scanning flag */
3009                 bool scanning = connman_device_get_scanning(device);
3010                 if (scanning){
3011                         connman_device_set_scanning(device,
3012                                 CONNMAN_SERVICE_TYPE_WIFI, false);
3013                         connman_device_unref(device);
3014                 }
3015 #else
3016                 /* though it should be already stopped: */
3017                 stop_autoscan(device);
3018 #endif
3019
3020                 if (!handle_wps_completion(interface, network, device, wifi))
3021                         break;
3022
3023                 connman_network_set_connected(network, true);
3024
3025                 wifi->disconnect_code = 0;
3026                 wifi->assoc_code = 0;
3027                 wifi->load_shaping_retries = 0;
3028                 break;
3029
3030         case G_SUPPLICANT_STATE_DISCONNECTED:
3031                 /*
3032                  * If we're in one of the idle modes, we have
3033                  * not started association yet and thus setting
3034                  * those ones to FALSE could cancel an association
3035                  * in progress.
3036                  */
3037                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
3038                 if (wps)
3039                         if (is_idle_wps(interface, wifi))
3040                                 break;
3041
3042                 if (is_idle(wifi))
3043                         break;
3044
3045                 if (handle_assoc_status_code(interface, wifi))
3046                         break;
3047
3048                 /* If previous state was 4way-handshake, then
3049                  * it's either: psk was incorrect and thus we retry
3050                  * or if we reach the maximum retries we declare the
3051                  * psk as wrong */
3052                 if (handle_4way_handshake_failure(interface,
3053                                                 network, wifi))
3054                         break;
3055
3056                 /* See table 8-36 Reason codes in IEEE Std 802.11 */
3057                 switch (wifi->disconnect_code) {
3058                 case 1: /* Unspecified reason */
3059                         /* Let's assume it's because we got blocked */
3060
3061                 case 6: /* Class 2 frame received from nonauthenticated STA */
3062                         connman_network_set_error(network,
3063                                                 CONNMAN_NETWORK_ERROR_BLOCKED);
3064                         break;
3065
3066                 default:
3067                         break;
3068                 }
3069
3070 #if defined TIZEN_EXT
3071                 int err;
3072
3073                 err = g_supplicant_interface_remove_network(wifi->interface);
3074                 if (err < 0)
3075                         DBG("Failed to remove network(%d)", err);
3076
3077
3078                 /* Some of Wi-Fi networks are not comply Wi-Fi specification.
3079                  * Retry association until its retry count is expired */
3080                 if (handle_wifi_assoc_retry(network, wifi) == true) {
3081                         throw_wifi_scan(wifi->device, scan_callback);
3082                         wifi->scan_pending_network = wifi->network;
3083                         break;
3084                 }
3085
3086                 if(wifi->disconnect_code > 0){
3087                         DBG("Set disconnect reason code(%d)", wifi->disconnect_code);
3088                         connman_network_set_disconnect_reason(network, wifi->disconnect_code);
3089                 }
3090
3091                 /* To avoid unnecessary repeated association in wpa_supplicant,
3092                  * "RemoveNetwork" should be made when Wi-Fi is disconnected */
3093                 if (wps != true && wifi->network && wifi->disconnecting == false) {
3094                         wifi->disconnecting = true;
3095                         err = g_supplicant_interface_disconnect(wifi->interface,
3096                                                         disconnect_callback, wifi->network);
3097                         if (err < 0)
3098                                 wifi->disconnecting = false;
3099
3100                 connman_network_set_connected(network, false);
3101                 connman_network_set_associating(network, false);
3102
3103                 start_autoscan(device);
3104
3105                 break;
3106                 }
3107 #endif
3108
3109                 connman_network_set_connected(network, false);
3110                 connman_network_set_associating(network, false);
3111                 wifi->disconnecting = false;
3112
3113                 start_autoscan(device);
3114
3115                 break;
3116
3117         case G_SUPPLICANT_STATE_INACTIVE:
3118 #if defined TIZEN_EXT
3119                 if (handle_wps_completion(interface, network, device, wifi) == false)
3120                         break;
3121 #endif
3122                 connman_network_set_associating(network, false);
3123                 start_autoscan(device);
3124
3125                 break;
3126
3127         case G_SUPPLICANT_STATE_UNKNOWN:
3128         case G_SUPPLICANT_STATE_DISABLED:
3129         case G_SUPPLICANT_STATE_ASSOCIATED:
3130         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3131         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3132                 break;
3133         }
3134
3135         old_connected = wifi->connected;
3136         wifi->state = state;
3137
3138         /* Saving wpa_s state policy:
3139          * If connected and if the state changes are roaming related:
3140          * --> We stay connected
3141          * If completed
3142          * --> We are connected
3143          * All other case:
3144          * --> We are not connected
3145          * */
3146         switch (state) {
3147         case G_SUPPLICANT_STATE_AUTHENTICATING:
3148         case G_SUPPLICANT_STATE_ASSOCIATING:
3149         case G_SUPPLICANT_STATE_ASSOCIATED:
3150         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3151         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3152                 if (wifi->connected)
3153                         connman_warn("Probably roaming right now!"
3154                                                 " Staying connected...");
3155                 break;
3156         case G_SUPPLICANT_STATE_SCANNING:
3157                 wifi->connected = false;
3158
3159                 if (old_connected)
3160                         start_autoscan(device);
3161                 break;
3162         case G_SUPPLICANT_STATE_COMPLETED:
3163                 wifi->connected = true;
3164                 break;
3165         default:
3166                 wifi->connected = false;
3167                 break;
3168         }
3169
3170         DBG("DONE");
3171 }
3172
3173 static void interface_removed(GSupplicantInterface *interface)
3174 {
3175         const char *ifname = g_supplicant_interface_get_ifname(interface);
3176         struct wifi_data *wifi;
3177
3178         DBG("ifname %s", ifname);
3179
3180         wifi = g_supplicant_interface_get_data(interface);
3181
3182         if (wifi)
3183                 wifi->interface = NULL;
3184
3185         if (wifi && wifi->tethering)
3186                 return;
3187
3188         if (!wifi || !wifi->device) {
3189                 DBG("wifi interface already removed");
3190                 return;
3191         }
3192
3193         connman_device_set_powered(wifi->device, false);
3194
3195         check_p2p_technology();
3196 }
3197
3198 static void set_device_type(const char *type, char dev_type[17])
3199 {
3200         const char *oui = "0050F204";
3201         const char *category = "0001";
3202         const char *sub_category = "0000";
3203
3204         if (!g_strcmp0(type, "handset")) {
3205                 category = "000A";
3206                 sub_category = "0005";
3207         } else if (!g_strcmp0(type, "vm") || !g_strcmp0(type, "container"))
3208                 sub_category = "0001";
3209         else if (!g_strcmp0(type, "server"))
3210                 sub_category = "0002";
3211         else if (!g_strcmp0(type, "laptop"))
3212                 sub_category = "0005";
3213         else if (!g_strcmp0(type, "desktop"))
3214                 sub_category = "0006";
3215         else if (!g_strcmp0(type, "tablet"))
3216                 sub_category = "0009";
3217         else if (!g_strcmp0(type, "watch"))
3218                 category = "00FF";
3219
3220         snprintf(dev_type, 17, "%s%s%s", category, oui, sub_category);
3221 }
3222
3223 static void p2p_support(GSupplicantInterface *interface)
3224 {
3225         char dev_type[17] = {};
3226         const char *hostname;
3227
3228         DBG("");
3229
3230         if (!interface)
3231                 return;
3232
3233         if (!g_supplicant_interface_has_p2p(interface))
3234                 return;
3235
3236         if (connman_technology_driver_register(&p2p_tech_driver) < 0) {
3237                 DBG("Could not register P2P technology driver");
3238                 return;
3239         }
3240
3241         hostname = connman_utsname_get_hostname();
3242         if (!hostname)
3243                 hostname = "ConnMan";
3244
3245         set_device_type(connman_machine_get_type(), dev_type);
3246         g_supplicant_interface_set_p2p_device_config(interface,
3247                                                         hostname, dev_type);
3248         connman_peer_driver_register(&peer_driver);
3249 }
3250
3251 static void scan_started(GSupplicantInterface *interface)
3252 {
3253         DBG("");
3254 }
3255
3256 static void scan_finished(GSupplicantInterface *interface)
3257 {
3258 #if defined TIZEN_EXT
3259         struct wifi_data *wifi;
3260         bool is_associating = false;
3261         static bool is_scanning = true;
3262 #endif
3263
3264         DBG("");
3265
3266 #if defined TIZEN_EXT
3267         wifi = g_supplicant_interface_get_data(interface);
3268         if (wifi && wifi->scan_pending_network) {
3269                 network_connect(wifi->scan_pending_network);
3270                 wifi->scan_pending_network = NULL;
3271         }
3272
3273         //service state - associating
3274         if(!wifi || !wifi->network)
3275                 return;
3276
3277         is_associating = connman_network_get_associating(wifi->network);
3278         if(is_associating && is_scanning){
3279                 is_scanning = false;
3280                 DBG("send scan for connecting");
3281                 throw_wifi_scan(wifi->device, scan_callback);
3282
3283                 return;
3284         }
3285         is_scanning = true;
3286
3287         //go scan
3288
3289 #endif
3290 }
3291
3292 static void ap_create_fail(GSupplicantInterface *interface)
3293 {
3294         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
3295         int ret;
3296
3297         if ((wifi->tethering) && (wifi->tethering_param)) {
3298                 DBG("%s create AP fail \n",
3299                                 g_supplicant_interface_get_ifname(wifi->interface));
3300
3301                 connman_inet_remove_from_bridge(wifi->index, wifi->bridge);
3302                 wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
3303                 wifi->tethering = false;
3304
3305                 ret = tech_set_tethering(wifi->tethering_param->technology,
3306                                 wifi->tethering_param->ssid->ssid,
3307                                 wifi->tethering_param->ssid->passphrase,
3308                                 wifi->bridge, true);
3309
3310                 if ((ret == -EOPNOTSUPP) && (wifi_technology)) {
3311                         connman_technology_tethering_notify(wifi_technology,false);
3312                 }
3313
3314                 g_free(wifi->tethering_param->ssid);
3315                 g_free(wifi->tethering_param);
3316                 wifi->tethering_param = NULL;
3317         }
3318
3319         return;
3320 }
3321
3322 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
3323 {
3324         unsigned char strength;
3325
3326         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
3327
3328 #if !defined TIZEN_EXT
3329         if (strength > 100)
3330                 strength = 100;
3331 #endif
3332         return strength;
3333 }
3334
3335 static void network_added(GSupplicantNetwork *supplicant_network)
3336 {
3337         struct connman_network *network;
3338         GSupplicantInterface *interface;
3339         struct wifi_data *wifi;
3340         const char *name, *identifier, *security, *group, *mode;
3341         const unsigned char *ssid;
3342         unsigned int ssid_len;
3343         bool wps;
3344         bool wps_pbc;
3345         bool wps_ready;
3346         bool wps_advertizing;
3347
3348 #if defined TIZEN_EXT
3349         GSList *vsie_list = NULL;
3350 #endif
3351
3352         mode = g_supplicant_network_get_mode(supplicant_network);
3353         identifier = g_supplicant_network_get_identifier(supplicant_network);
3354
3355         DBG("%s", identifier);
3356
3357         if (!g_strcmp0(mode, "adhoc"))
3358                 return;
3359
3360         interface = g_supplicant_network_get_interface(supplicant_network);
3361         wifi = g_supplicant_interface_get_data(interface);
3362         name = g_supplicant_network_get_name(supplicant_network);
3363         security = g_supplicant_network_get_security(supplicant_network);
3364         group = g_supplicant_network_get_identifier(supplicant_network);
3365         wps = g_supplicant_network_get_wps(supplicant_network);
3366         wps_pbc = g_supplicant_network_is_wps_pbc(supplicant_network);
3367         wps_ready = g_supplicant_network_is_wps_active(supplicant_network);
3368         wps_advertizing = g_supplicant_network_is_wps_advertizing(
3369                                                         supplicant_network);
3370
3371         if (!wifi)
3372                 return;
3373
3374         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
3375
3376         network = connman_device_get_network(wifi->device, identifier);
3377
3378         if (!network) {
3379                 network = connman_network_create(identifier,
3380                                                 CONNMAN_NETWORK_TYPE_WIFI);
3381                 if (!network)
3382                         return;
3383
3384                 connman_network_set_index(network, wifi->index);
3385
3386                 if (connman_device_add_network(wifi->device, network) < 0) {
3387                         connman_network_unref(network);
3388                         return;
3389                 }
3390
3391                 wifi->networks = g_slist_prepend(wifi->networks, network);
3392         }
3393
3394         if (name && name[0] != '\0')
3395                 connman_network_set_name(network, name);
3396
3397         connman_network_set_blob(network, "WiFi.SSID",
3398                                                 ssid, ssid_len);
3399 #if defined TIZEN_EXT
3400         vsie_list = (GSList *)g_supplicant_network_get_wifi_vsie(supplicant_network);
3401         if (vsie_list)
3402                 connman_network_set_vsie_list(network, vsie_list);
3403         else
3404                 DBG("vsie_list is NULL");
3405 #endif
3406         connman_network_set_string(network, "WiFi.Security", security);
3407         connman_network_set_strength(network,
3408                                 calculate_strength(supplicant_network));
3409         connman_network_set_bool(network, "WiFi.WPS", wps);
3410
3411         if (wps) {
3412                 /* Is AP advertizing for WPS association?
3413                  * If so, we decide to use WPS by default */
3414                 if (wps_ready && wps_pbc &&
3415                                                 wps_advertizing) {
3416 #if !defined TIZEN_EXT
3417                         connman_network_set_bool(network, "WiFi.UseWPS", true);
3418 #else
3419                         DBG("wps is activating by ap but ignore it.");
3420 #endif
3421                 }
3422         }
3423
3424         connman_network_set_frequency(network,
3425                         g_supplicant_network_get_frequency(supplicant_network));
3426 #if defined TIZEN_EXT
3427         connman_network_set_bssid(network,
3428                         g_supplicant_network_get_bssid(supplicant_network));
3429         connman_network_set_maxrate(network,
3430                         g_supplicant_network_get_maxrate(supplicant_network));
3431         connman_network_set_enc_mode(network,
3432                         g_supplicant_network_get_enc_mode(supplicant_network));
3433         connman_network_set_rsn_mode(network,
3434                         g_supplicant_network_get_rsn_mode(supplicant_network));
3435         connman_network_set_keymgmt(network,
3436                         g_supplicant_network_get_keymgmt(supplicant_network));
3437         connman_network_set_bool(network, "WiFi.HS20AP",
3438                         g_supplicant_network_is_hs20AP(supplicant_network));
3439 #endif
3440         connman_network_set_available(network, true);
3441         connman_network_set_string(network, "WiFi.Mode", mode);
3442
3443 #if defined TIZEN_EXT
3444         if (group)
3445 #else
3446         if (ssid)
3447 #endif
3448                 connman_network_set_group(network, group);
3449
3450 #if defined TIZEN_EXT
3451         if (wifi_first_scan == true)
3452                 found_with_first_scan = true;
3453 #endif
3454
3455         if (wifi->hidden && ssid) {
3456 #if defined TIZEN_EXT
3457                 if (network_security(wifi->hidden->security) ==
3458                         network_security(security) &&
3459 #else
3460                 if (!g_strcmp0(wifi->hidden->security, security) &&
3461 #endif
3462                                 wifi->hidden->ssid_len == ssid_len &&
3463                                 !memcmp(wifi->hidden->ssid, ssid, ssid_len)) {
3464                         connman_network_connect_hidden(network,
3465                                         wifi->hidden->identity,
3466                                         wifi->hidden->passphrase,
3467                                         wifi->hidden->user_data);
3468                         wifi->hidden->user_data = NULL;
3469                         hidden_free(wifi->hidden);
3470                         wifi->hidden = NULL;
3471                 }
3472         }
3473 }
3474
3475 static void network_removed(GSupplicantNetwork *network)
3476 {
3477         GSupplicantInterface *interface;
3478         struct wifi_data *wifi;
3479         const char *name, *identifier;
3480         struct connman_network *connman_network;
3481
3482         interface = g_supplicant_network_get_interface(network);
3483         wifi = g_supplicant_interface_get_data(interface);
3484         identifier = g_supplicant_network_get_identifier(network);
3485         name = g_supplicant_network_get_name(network);
3486
3487         DBG("name %s", name);
3488
3489         if (!wifi)
3490                 return;
3491
3492         connman_network = connman_device_get_network(wifi->device, identifier);
3493         if (!connman_network)
3494                 return;
3495
3496 #if defined TIZEN_EXT
3497         if (connman_network == wifi->scan_pending_network)
3498                 wifi->scan_pending_network = NULL;
3499
3500         if (connman_network == wifi->pending_network)
3501                 wifi->pending_network = NULL;
3502
3503         if(connman_network_get_connecting(connman_network) == true){
3504                 connman_network_set_connected(connman_network, false);
3505         }
3506 #endif
3507
3508         wifi->networks = g_slist_remove(wifi->networks, connman_network);
3509
3510         connman_device_remove_network(wifi->device, connman_network);
3511         connman_network_unref(connman_network);
3512 }
3513
3514 static void network_changed(GSupplicantNetwork *network, const char *property)
3515 {
3516         GSupplicantInterface *interface;
3517         struct wifi_data *wifi;
3518         const char *name, *identifier;
3519         struct connman_network *connman_network;
3520
3521 #if defined TIZEN_EXT
3522         const unsigned char *bssid;
3523         unsigned int maxrate;
3524         uint16_t frequency;
3525         bool wps;
3526 #endif
3527
3528         interface = g_supplicant_network_get_interface(network);
3529         wifi = g_supplicant_interface_get_data(interface);
3530         identifier = g_supplicant_network_get_identifier(network);
3531         name = g_supplicant_network_get_name(network);
3532
3533         DBG("name %s", name);
3534
3535         if (!wifi)
3536                 return;
3537
3538         connman_network = connman_device_get_network(wifi->device, identifier);
3539         if (!connman_network)
3540                 return;
3541
3542         if (g_str_equal(property, "Signal")) {
3543                connman_network_set_strength(connman_network,
3544                                         calculate_strength(network));
3545                connman_network_update(connman_network);
3546         }
3547
3548 #if defined TIZEN_EXT
3549         bssid = g_supplicant_network_get_bssid(network);
3550         maxrate = g_supplicant_network_get_maxrate(network);
3551         frequency = g_supplicant_network_get_frequency(network);
3552         wps = g_supplicant_network_get_wps(network);
3553
3554         connman_network_set_bssid(connman_network, bssid);
3555         connman_network_set_maxrate(connman_network, maxrate);
3556         connman_network_set_frequency(connman_network, frequency);
3557         connman_network_set_bool(connman_network, "WiFi.WPS", wps);
3558 #endif
3559 }
3560
3561 static void network_associated(GSupplicantNetwork *network)
3562 {
3563         GSupplicantInterface *interface;
3564         struct wifi_data *wifi;
3565         struct connman_network *connman_network;
3566         const char *identifier;
3567
3568         DBG("");
3569
3570         interface = g_supplicant_network_get_interface(network);
3571         if (!interface)
3572                 return;
3573
3574         wifi = g_supplicant_interface_get_data(interface);
3575         if (!wifi)
3576                 return;
3577
3578         identifier = g_supplicant_network_get_identifier(network);
3579
3580         connman_network = connman_device_get_network(wifi->device, identifier);
3581         if (!connman_network)
3582                 return;
3583
3584         if (wifi->network) {
3585                 if (wifi->network == connman_network)
3586                         return;
3587
3588                 /*
3589                  * This should never happen, we got associated with
3590                  * a network different than the one we were expecting.
3591                  */
3592                 DBG("Associated to %p while expecting %p",
3593                                         connman_network, wifi->network);
3594
3595                 connman_network_set_associating(wifi->network, false);
3596         }
3597
3598         DBG("Reconnecting to previous network %p from wpa_s", connman_network);
3599
3600         wifi->network = connman_network_ref(connman_network);
3601         wifi->retries = 0;
3602
3603         /*
3604          * Interface state changes callback (interface_state) is always
3605          * called before network_associated callback thus we need to call
3606          * interface_state again in order to process the new state now that
3607          * we have the network properly set.
3608          */
3609         interface_state(interface);
3610 }
3611
3612 static void apply_peer_services(GSupplicantPeer *peer,
3613                                 struct connman_peer *connman_peer)
3614 {
3615         const unsigned char *data;
3616         int length;
3617
3618         DBG("");
3619
3620         connman_peer_reset_services(connman_peer);
3621
3622         data = g_supplicant_peer_get_widi_ies(peer, &length);
3623         if (data) {
3624                 connman_peer_add_service(connman_peer,
3625                         CONNMAN_PEER_SERVICE_WIFI_DISPLAY, data, length);
3626         }
3627 }
3628
3629 static void add_station(const char *mac)
3630 {
3631         connman_technology_tethering_add_station(CONNMAN_SERVICE_TYPE_WIFI,
3632                                                  mac);
3633 }
3634
3635 static void remove_station(const char *mac)
3636 {
3637         connman_technology_tethering_remove_station(mac);
3638 }
3639
3640 static void peer_found(GSupplicantPeer *peer)
3641 {
3642         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3643         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3644         struct connman_peer *connman_peer;
3645         const char *identifier, *name;
3646         int ret;
3647 #if defined TIZEN_EXT
3648         if (!wifi)
3649                 return;
3650 #endif
3651         identifier = g_supplicant_peer_get_identifier(peer);
3652         name = g_supplicant_peer_get_name(peer);
3653
3654         DBG("ident: %s", identifier);
3655
3656         connman_peer = connman_peer_get(wifi->device, identifier);
3657         if (connman_peer)
3658                 return;
3659
3660         connman_peer = connman_peer_create(identifier);
3661         connman_peer_set_name(connman_peer, name);
3662         connman_peer_set_device(connman_peer, wifi->device);
3663         apply_peer_services(peer, connman_peer);
3664
3665         ret = connman_peer_register(connman_peer);
3666         if (ret < 0 && ret != -EALREADY)
3667                 connman_peer_unref(connman_peer);
3668         else
3669                 wifi->peers = g_slist_prepend(wifi->peers, connman_peer);
3670 }
3671
3672 static void peer_lost(GSupplicantPeer *peer)
3673 {
3674         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3675         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3676         struct connman_peer *connman_peer;
3677         const char *identifier;
3678
3679         if (!wifi)
3680                 return;
3681
3682         identifier = g_supplicant_peer_get_identifier(peer);
3683
3684         DBG("ident: %s", identifier);
3685
3686         connman_peer = connman_peer_get(wifi->device, identifier);
3687         if (connman_peer) {
3688                 if (wifi->p2p_connecting &&
3689                                 wifi->pending_peer == connman_peer) {
3690                         peer_connect_timeout(wifi);
3691                 }
3692                 connman_peer_unregister(connman_peer);
3693                 connman_peer_unref(connman_peer);
3694         }
3695
3696         wifi->peers = g_slist_remove(wifi->peers, connman_peer);
3697 }
3698
3699 static void peer_changed(GSupplicantPeer *peer, GSupplicantPeerState state)
3700 {
3701         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3702         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3703         enum connman_peer_state p_state = CONNMAN_PEER_STATE_UNKNOWN;
3704         struct connman_peer *connman_peer;
3705         const char *identifier;
3706
3707 #if defined TIZEN_EXT
3708         if (!wifi)
3709                 return;
3710 #endif
3711
3712         identifier = g_supplicant_peer_get_identifier(peer);
3713
3714         DBG("ident: %s", identifier);
3715
3716         if (!wifi)
3717                 return;
3718
3719         connman_peer = connman_peer_get(wifi->device, identifier);
3720         if (!connman_peer)
3721                 return;
3722
3723         switch (state) {
3724         case G_SUPPLICANT_PEER_SERVICES_CHANGED:
3725                 apply_peer_services(peer, connman_peer);
3726                 connman_peer_services_changed(connman_peer);
3727                 return;
3728         case G_SUPPLICANT_PEER_GROUP_CHANGED:
3729                 if (!g_supplicant_peer_is_in_a_group(peer))
3730                         p_state = CONNMAN_PEER_STATE_IDLE;
3731                 else
3732                         p_state = CONNMAN_PEER_STATE_CONFIGURATION;
3733                 break;
3734         case G_SUPPLICANT_PEER_GROUP_STARTED:
3735                 break;
3736         case G_SUPPLICANT_PEER_GROUP_FINISHED:
3737                 p_state = CONNMAN_PEER_STATE_IDLE;
3738                 break;
3739         case G_SUPPLICANT_PEER_GROUP_JOINED:
3740                 connman_peer_set_iface_address(connman_peer,
3741                                 g_supplicant_peer_get_iface_address(peer));
3742                 break;
3743         case G_SUPPLICANT_PEER_GROUP_DISCONNECTED:
3744                 p_state = CONNMAN_PEER_STATE_IDLE;
3745                 break;
3746         case G_SUPPLICANT_PEER_GROUP_FAILED:
3747                 if (g_supplicant_peer_has_requested_connection(peer))
3748                         p_state = CONNMAN_PEER_STATE_IDLE;
3749                 else
3750                         p_state = CONNMAN_PEER_STATE_FAILURE;
3751                 break;
3752         }
3753
3754         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION ||
3755                                         p_state == CONNMAN_PEER_STATE_FAILURE) {
3756                 if (wifi->p2p_connecting
3757                                 && connman_peer == wifi->pending_peer)
3758                         peer_cancel_timeout(wifi);
3759                 else
3760                         p_state = CONNMAN_PEER_STATE_UNKNOWN;
3761         }
3762
3763         if (p_state == CONNMAN_PEER_STATE_UNKNOWN)
3764                 return;
3765
3766         if (p_state == CONNMAN_PEER_STATE_CONFIGURATION) {
3767                 GSupplicantInterface *g_iface;
3768                 struct wifi_data *g_wifi;
3769
3770                 g_iface = g_supplicant_peer_get_group_interface(peer);
3771                 if (!g_iface)
3772                         return;
3773
3774                 g_wifi = g_supplicant_interface_get_data(g_iface);
3775                 if (!g_wifi)
3776                         return;
3777
3778                 connman_peer_set_as_master(connman_peer,
3779                                         !g_supplicant_peer_is_client(peer));
3780                 connman_peer_set_sub_device(connman_peer, g_wifi->device);
3781
3782                 /*
3783                  * If wpa_supplicant didn't create a dedicated p2p-group
3784                  * interface then mark this interface as p2p_device to avoid
3785                  * scan and auto-scan are launched on it while P2P is connected.
3786                  */
3787                 if (!g_list_find(p2p_iface_list, g_wifi))
3788                         wifi->p2p_device = true;
3789         }
3790
3791         connman_peer_set_state(connman_peer, p_state);
3792 }
3793
3794 static void peer_request(GSupplicantPeer *peer)
3795 {
3796         GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
3797         struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
3798         struct connman_peer *connman_peer;
3799         const char *identifier;
3800
3801 #if defined TIZEN_EXT
3802         if (!wifi)
3803                 return;
3804 #endif
3805
3806         identifier = g_supplicant_peer_get_identifier(peer);
3807
3808         DBG("ident: %s", identifier);
3809
3810         connman_peer = connman_peer_get(wifi->device, identifier);
3811         if (!connman_peer)
3812                 return;
3813
3814         connman_peer_request_connection(connman_peer);
3815 }
3816
3817 #if defined TIZEN_EXT
3818 static void system_power_off(void)
3819 {
3820         GList *list;
3821         struct wifi_data *wifi;
3822         struct connman_service *service;
3823         struct connman_ipconfig *ipconfig_ipv4;
3824
3825         if (connman_setting_get_bool("WiFiDHCPRelease") == true) {
3826                 for (list = iface_list; list; list = list->next) {
3827                         wifi = list->data;
3828
3829                         if (wifi->network != NULL) {
3830                                 service = connman_service_lookup_from_network(wifi->network);
3831                                 ipconfig_ipv4 = __connman_service_get_ip4config(service);
3832                                 __connman_dhcp_stop(ipconfig_ipv4);
3833                         }
3834                 }
3835         }
3836 }
3837
3838 static void network_merged(GSupplicantNetwork *network)
3839 {
3840         GSupplicantInterface *interface;
3841         GSupplicantState state;
3842         struct wifi_data *wifi;
3843         const char *identifier;
3844         struct connman_network *connman_network;
3845         bool ishs20AP = 0;
3846         char *temp = NULL;
3847
3848         interface = g_supplicant_network_get_interface(network);
3849         if (!interface)
3850                 return;
3851
3852         state = g_supplicant_interface_get_state(interface);
3853         if (state < G_SUPPLICANT_STATE_AUTHENTICATING)
3854                 return;
3855
3856         wifi = g_supplicant_interface_get_data(interface);
3857         if (!wifi)
3858                 return;
3859
3860         identifier = g_supplicant_network_get_identifier(network);
3861
3862         connman_network = connman_device_get_network(wifi->device, identifier);
3863         if (!connman_network)
3864                 return;
3865
3866         DBG("merged identifier %s", identifier);
3867
3868         if (wifi->connected == FALSE) {
3869                 switch (state) {
3870                 case G_SUPPLICANT_STATE_AUTHENTICATING:
3871                 case G_SUPPLICANT_STATE_ASSOCIATING:
3872                 case G_SUPPLICANT_STATE_ASSOCIATED:
3873                 case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
3874                 case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
3875                         connman_network_set_associating(connman_network, TRUE);
3876                         break;
3877                 case G_SUPPLICANT_STATE_COMPLETED:
3878                         connman_network_set_connected(connman_network, TRUE);
3879                         break;
3880                 default:
3881                         DBG("Not handled the state : %d", state);
3882                         break;
3883                 }
3884         }
3885
3886         ishs20AP = g_supplicant_network_is_hs20AP(network);
3887
3888         if (ishs20AP &&
3889                 g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) {
3890                 temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1);
3891                 connman_network_set_string(connman_network, "WiFi.EAP",
3892                                 temp);
3893                 connman_network_set_string(connman_network, "WiFi.Identity",
3894                                 g_supplicant_network_get_identity(network));
3895                 connman_network_set_string(connman_network, "WiFi.Phase2",
3896                                 g_supplicant_network_get_phase2(network));
3897
3898                 g_free(temp);
3899         }
3900
3901         wifi->network = connman_network;
3902 }
3903
3904 static void assoc_failed(void *user_data)
3905 {
3906         struct connman_network *network = user_data;
3907         connman_network_set_associating(network, false);
3908 }
3909 #endif
3910
3911 static void debug(const char *str)
3912 {
3913         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
3914                 connman_debug("%s", str);
3915 }
3916
3917 static void disconnect_reasoncode(GSupplicantInterface *interface,
3918                                 int reasoncode)
3919 {
3920         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
3921
3922         if (wifi != NULL) {
3923                 wifi->disconnect_code = reasoncode;
3924         }
3925 }
3926
3927 static void assoc_status_code(GSupplicantInterface *interface, int status_code)
3928 {
3929         struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
3930
3931         if (wifi != NULL) {
3932                 wifi->assoc_code = status_code;
3933         }
3934 }
3935
3936 static const GSupplicantCallbacks callbacks = {
3937         .system_ready           = system_ready,
3938         .system_killed          = system_killed,
3939         .interface_added        = interface_added,
3940         .interface_state        = interface_state,
3941         .interface_removed      = interface_removed,
3942         .p2p_support            = p2p_support,
3943         .scan_started           = scan_started,
3944         .scan_finished          = scan_finished,
3945         .ap_create_fail         = ap_create_fail,
3946         .network_added          = network_added,
3947         .network_removed        = network_removed,
3948         .network_changed        = network_changed,
3949         .network_associated     = network_associated,
3950         .add_station            = add_station,
3951         .remove_station         = remove_station,
3952         .peer_found             = peer_found,
3953         .peer_lost              = peer_lost,
3954         .peer_changed           = peer_changed,
3955         .peer_request           = peer_request,
3956 #if defined TIZEN_EXT
3957         .system_power_off       = system_power_off,
3958         .network_merged = network_merged,
3959         .assoc_failed           = assoc_failed,
3960 #endif
3961         .debug                  = debug,
3962         .disconnect_reasoncode  = disconnect_reasoncode,
3963         .assoc_status_code      = assoc_status_code,
3964 };
3965
3966
3967 static int tech_probe(struct connman_technology *technology)
3968 {
3969         wifi_technology = technology;
3970
3971         return 0;
3972 }
3973
3974 static void tech_remove(struct connman_technology *technology)
3975 {
3976         wifi_technology = NULL;
3977 }
3978
3979 static GSupplicantSSID *ssid_ap_init(const char *ssid,
3980                 const char *passphrase)
3981 {
3982         GSupplicantSSID *ap;
3983
3984         ap = g_try_malloc0(sizeof(GSupplicantSSID));
3985         if (!ap)
3986                 return NULL;
3987
3988         ap->mode = G_SUPPLICANT_MODE_MASTER;
3989         ap->ssid = ssid;
3990         ap->ssid_len = strlen(ssid);
3991         ap->scan_ssid = 0;
3992         ap->freq = 2412;
3993
3994         if (!passphrase || strlen(passphrase) == 0) {
3995                 ap->security = G_SUPPLICANT_SECURITY_NONE;
3996                 ap->passphrase = NULL;
3997         } else {
3998                ap->security = G_SUPPLICANT_SECURITY_PSK;
3999                ap->protocol = G_SUPPLICANT_PROTO_RSN;
4000                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
4001                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
4002                ap->passphrase = passphrase;
4003         }
4004
4005         return ap;
4006 }
4007
4008 static void ap_start_callback(int result, GSupplicantInterface *interface,
4009                                                         void *user_data)
4010 {
4011         struct wifi_tethering_info *info = user_data;
4012
4013         DBG("result %d index %d bridge %s",
4014                 result, info->wifi->index, info->wifi->bridge);
4015
4016         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
4017                 connman_inet_remove_from_bridge(info->wifi->index,
4018                                                         info->wifi->bridge);
4019
4020                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
4021                         connman_technology_tethering_notify(info->technology, false);
4022                         g_free(info->wifi->tethering_param->ssid);
4023                         g_free(info->wifi->tethering_param);
4024                         info->wifi->tethering_param = NULL;
4025                 }
4026         }
4027
4028         g_free(info->ifname);
4029         g_free(info);
4030 }
4031
4032 static void ap_create_callback(int result,
4033                                 GSupplicantInterface *interface,
4034                                         void *user_data)
4035 {
4036         struct wifi_tethering_info *info = user_data;
4037
4038         DBG("result %d ifname %s", result,
4039                                 g_supplicant_interface_get_ifname(interface));
4040
4041         if ((result < 0) || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
4042                 connman_inet_remove_from_bridge(info->wifi->index,
4043                                                         info->wifi->bridge);
4044
4045                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
4046                         connman_technology_tethering_notify(info->technology, false);
4047                         g_free(info->wifi->tethering_param->ssid);
4048                         g_free(info->wifi->tethering_param);
4049                         info->wifi->tethering_param = NULL;
4050
4051                 }
4052
4053                 g_free(info->ifname);
4054                 g_free(info->ssid);
4055                 g_free(info);
4056                 return;
4057         }
4058
4059         info->wifi->interface = interface;
4060         g_supplicant_interface_set_data(interface, info->wifi);
4061
4062         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
4063                 connman_error("Failed to set interface ap_scan property");
4064
4065         g_supplicant_interface_connect(interface, info->ssid,
4066                                                 ap_start_callback, info);
4067 }
4068
4069 static void sta_remove_callback(int result,
4070                                 GSupplicantInterface *interface,
4071                                         void *user_data)
4072 {
4073         struct wifi_tethering_info *info = user_data;
4074         const char *driver = connman_option_get_string("wifi");
4075
4076         DBG("ifname %s result %d ", info->ifname, result);
4077
4078         if (result < 0 || (info->wifi->ap_supported != WIFI_AP_SUPPORTED)) {
4079                 info->wifi->tethering = false;
4080                 connman_technology_tethering_notify(info->technology, false);
4081
4082                 g_free(info->ifname);
4083                 g_free(info->ssid);
4084                 g_free(info);
4085
4086                 if (info->wifi->ap_supported == WIFI_AP_SUPPORTED) {
4087                         g_free(info->wifi->tethering_param->ssid);
4088                         g_free(info->wifi->tethering_param);
4089                         info->wifi->tethering_param = NULL;
4090                 }
4091                 return;
4092         }
4093
4094         info->wifi->interface = NULL;
4095
4096         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
4097                                                 ap_create_callback,
4098                                                         info);
4099 }
4100
4101 static int enable_wifi_tethering(struct connman_technology *technology,
4102                                 const char *bridge, const char *identifier,
4103                                 const char *passphrase, bool available)
4104 {
4105         GList *list;
4106         GSupplicantInterface *interface;
4107         struct wifi_data *wifi;
4108         struct wifi_tethering_info *info;
4109         const char *ifname;
4110         unsigned int mode;
4111         int err, berr = 0;
4112
4113         for (list = iface_list; list; list = list->next) {
4114                 wifi = list->data;
4115
4116                 DBG("wifi %p network %p pending_network %p", wifi,
4117                         wifi->network, wifi->pending_network);
4118
4119                 interface = wifi->interface;
4120
4121                 if (!interface)
4122                         continue;
4123
4124                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED)
4125                         continue;
4126
4127                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
4128
4129                 if (wifi->ap_supported == WIFI_AP_NOT_SUPPORTED) {
4130                         DBG("%s does not support AP mode (detected)", ifname);
4131                         continue;
4132                 }
4133
4134                 mode = g_supplicant_interface_get_mode(interface);
4135                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
4136                         wifi->ap_supported = WIFI_AP_NOT_SUPPORTED;
4137                         DBG("%s does not support AP mode (capability)", ifname);
4138                         continue;
4139                 }
4140
4141                 if (wifi->network && available)
4142                         continue;
4143
4144                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
4145                 if (!info)
4146                         return -ENOMEM;
4147
4148                 wifi->tethering_param = g_try_malloc0(sizeof(struct wifi_tethering_info));
4149                 if (!wifi->tethering_param) {
4150                         g_free(info);
4151                         return -ENOMEM;
4152                 }
4153
4154                 info->wifi = wifi;
4155                 info->technology = technology;
4156                 info->wifi->bridge = bridge;
4157                 info->ssid = ssid_ap_init(identifier, passphrase);
4158                 if (!info->ssid)
4159                         goto failed;
4160
4161                 info->ifname = g_strdup(ifname);
4162                 if (!info->ifname)
4163                         goto failed;
4164
4165                 wifi->tethering_param->technology = technology;
4166                 wifi->tethering_param->ssid = ssid_ap_init(identifier, passphrase);
4167                 if (!wifi->tethering_param->ssid)
4168                         goto failed;
4169
4170                 info->wifi->tethering = true;
4171                 info->wifi->ap_supported = WIFI_AP_SUPPORTED;
4172
4173                 berr = connman_technology_tethering_notify(technology, true);
4174                 if (berr < 0)
4175                         goto failed;
4176
4177                 err = g_supplicant_interface_remove(interface,
4178                                                 sta_remove_callback,
4179                                                         info);
4180                 if (err >= 0) {
4181                         DBG("tethering wifi %p ifname %s", wifi, ifname);
4182                         return 0;
4183                 }
4184
4185         failed:
4186                 g_free(info->ifname);
4187                 g_free(info->ssid);
4188                 g_free(info);
4189                 g_free(wifi->tethering_param);
4190                 wifi->tethering_param = NULL;
4191
4192                 /*
4193                  * Remove bridge if it was correctly created but remove
4194                  * operation failed. Instead, if bridge creation failed then
4195                  * break out and do not try again on another interface,
4196                  * bridge set-up does not depend on it.
4197                  */
4198                 if (berr == 0)
4199                         connman_technology_tethering_notify(technology, false);
4200                 else
4201                         break;
4202         }
4203
4204         return -EOPNOTSUPP;
4205 }
4206
4207 static int tech_set_tethering(struct connman_technology *technology,
4208                                 const char *identifier, const char *passphrase,
4209                                 const char *bridge, bool enabled)
4210 {
4211         GList *list;
4212         struct wifi_data *wifi;
4213         int err;
4214
4215         DBG("");
4216
4217         if (!enabled) {
4218                 for (list = iface_list; list; list = list->next) {
4219                         wifi = list->data;
4220
4221                         if (wifi->tethering) {
4222                                 wifi->tethering = false;
4223
4224                                 connman_inet_remove_from_bridge(wifi->index,
4225                                                                         bridge);
4226                                 wifi->bridged = false;
4227                         }
4228                 }
4229
4230                 connman_technology_tethering_notify(technology, false);
4231
4232                 return 0;
4233         }
4234
4235         DBG("trying tethering for available devices");
4236         err = enable_wifi_tethering(technology, bridge, identifier, passphrase,
4237                                 true);
4238
4239         if (err < 0) {
4240                 DBG("trying tethering for any device");
4241                 err = enable_wifi_tethering(technology, bridge, identifier,
4242                                         passphrase, false);
4243         }
4244
4245         return err;
4246 }
4247
4248 static void regdom_callback(int result, const char *alpha2, void *user_data)
4249 {
4250         DBG("");
4251
4252         if (!wifi_technology)
4253                 return;
4254
4255         if (result != 0)
4256                 alpha2 = NULL;
4257
4258         connman_technology_regdom_notify(wifi_technology, alpha2);
4259 }
4260
4261 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
4262 {
4263         return g_supplicant_set_country(alpha2, regdom_callback, NULL);
4264 }
4265
4266 static struct connman_technology_driver tech_driver = {
4267         .name           = "wifi",
4268         .type           = CONNMAN_SERVICE_TYPE_WIFI,
4269         .probe          = tech_probe,
4270         .remove         = tech_remove,
4271         .set_tethering  = tech_set_tethering,
4272         .set_regdom     = tech_set_regdom,
4273 };
4274
4275 static int wifi_init(void)
4276 {
4277         int err;
4278
4279         err = connman_network_driver_register(&network_driver);
4280         if (err < 0)
4281                 return err;
4282
4283         err = g_supplicant_register(&callbacks);
4284         if (err < 0) {
4285                 connman_network_driver_unregister(&network_driver);
4286                 return err;
4287         }
4288
4289         err = connman_technology_driver_register(&tech_driver);
4290         if (err < 0) {
4291                 g_supplicant_unregister(&callbacks);
4292                 connman_network_driver_unregister(&network_driver);
4293                 return err;
4294         }
4295
4296         return 0;
4297 }
4298
4299 static void wifi_exit(void)
4300 {
4301         DBG();
4302
4303         connman_technology_driver_unregister(&tech_driver);
4304
4305         g_supplicant_unregister(&callbacks);
4306
4307         connman_network_driver_unregister(&network_driver);
4308 }
4309
4310 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
4311                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)