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