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