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