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