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