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