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