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