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