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