device: Change signature of connman_device_remove_network()
[framework/connectivity/connman.git] / plugins / wifi.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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 <string.h>
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
32 #include <linux/if_arp.h>
33 #include <linux/wireless.h>
34 #include <net/ethernet.h>
35
36 #ifndef IFF_LOWER_UP
37 #define IFF_LOWER_UP    0x10000
38 #endif
39
40 #include <dbus/dbus.h>
41 #include <glib.h>
42
43 #define CONNMAN_API_SUBJECT_TO_CHANGE
44 #include <connman/plugin.h>
45 #include <connman/inet.h>
46 #include <connman/device.h>
47 #include <connman/rtnl.h>
48 #include <connman/technology.h>
49 #include <connman/log.h>
50 #include <connman/option.h>
51
52 #include <gsupplicant/gsupplicant.h>
53
54 #define CLEANUP_TIMEOUT   8     /* in seconds */
55 #define INACTIVE_TIMEOUT  12    /* in seconds */
56
57 struct connman_technology *wifi_technology = NULL;
58
59 struct wifi_data {
60         char *identifier;
61         struct connman_device *device;
62         struct connman_network *network;
63         struct connman_network *pending_network;
64         GSupplicantInterface *interface;
65         GSupplicantState state;
66         connman_bool_t connected;
67         connman_bool_t disconnecting;
68         connman_bool_t tethering;
69         connman_bool_t bridged;
70         const char *bridge;
71         int index;
72         unsigned flags;
73         unsigned int watch;
74 };
75
76 static GList *iface_list = NULL;
77
78 static void handle_tethering(struct wifi_data *wifi)
79 {
80         if (wifi->tethering == FALSE)
81                 return;
82
83         if (wifi->bridge == NULL)
84                 return;
85
86         if (wifi->bridged == TRUE)
87                 return;
88
89         DBG("index %d bridge %s", wifi->index, wifi->bridge);
90
91         if (connman_inet_add_to_bridge(wifi->index, wifi->bridge) < 0)
92                 return;
93
94         wifi->bridged = TRUE;
95 }
96
97 static void wifi_newlink(unsigned flags, unsigned change, void *user_data)
98 {
99         struct connman_device *device = user_data;
100         struct wifi_data *wifi = connman_device_get_data(device);
101
102         DBG("index %d flags %d change %d", wifi->index, flags, change);
103
104         if (!change)
105                 return;
106
107         if ((wifi->flags & IFF_UP) != (flags & IFF_UP)) {
108                 if (flags & IFF_UP)
109                         DBG("interface up");
110                 else
111                         DBG("interface down");
112         }
113
114         if ((wifi->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
115                 if (flags & IFF_LOWER_UP) {
116                         DBG("carrier on");
117
118                         handle_tethering(wifi);
119                 } else
120                         DBG("carrier off");
121         }
122
123         wifi->flags = flags;
124 }
125
126 static int wifi_probe(struct connman_device *device)
127 {
128         struct wifi_data *wifi;
129
130         DBG("device %p", device);
131
132         wifi = g_try_new0(struct wifi_data, 1);
133         if (wifi == NULL)
134                 return -ENOMEM;
135
136         wifi->connected = FALSE;
137         wifi->disconnecting = FALSE;
138         wifi->tethering = FALSE;
139         wifi->bridged = FALSE;
140         wifi->bridge = NULL;
141         wifi->state = G_SUPPLICANT_STATE_INACTIVE;
142
143         connman_device_set_data(device, wifi);
144         wifi->device = connman_device_ref(device);
145
146         wifi->index = connman_device_get_index(device);
147         wifi->flags = 0;
148
149         wifi->watch = connman_rtnl_add_newlink_watch(wifi->index,
150                                                         wifi_newlink, device);
151
152         iface_list = g_list_append(iface_list, wifi);
153
154         return 0;
155 }
156
157 static void wifi_remove(struct connman_device *device)
158 {
159         struct wifi_data *wifi = connman_device_get_data(device);
160
161         DBG("device %p", device);
162
163         if (wifi == NULL)
164                 return;
165
166         iface_list = g_list_remove(iface_list, wifi);
167
168         if (wifi->pending_network != NULL) {
169                 connman_network_unref(wifi->pending_network);
170                 wifi->pending_network = NULL;
171         }
172
173         connman_device_set_data(device, NULL);
174         connman_device_unref(wifi->device);
175         connman_rtnl_remove_watch(wifi->watch);
176
177         g_supplicant_interface_set_data(wifi->interface, NULL);
178
179         g_free(wifi->identifier);
180         g_free(wifi);
181 }
182
183 static void interface_create_callback(int result,
184                                         GSupplicantInterface *interface,
185                                                         void *user_data)
186 {
187         struct wifi_data *wifi = user_data;
188
189         DBG("result %d ifname %s", result,
190                                 g_supplicant_interface_get_ifname(interface));
191
192         if (result < 0)
193                 return;
194
195         wifi->interface = interface;
196         g_supplicant_interface_set_data(interface, wifi);
197 }
198
199 static void interface_remove_callback(int result,
200                                         GSupplicantInterface *interface,
201                                                         void *user_data)
202 {
203         struct wifi_data *wifi = user_data;
204
205         DBG("result %d", result);
206
207         if (result < 0)
208                 return;
209
210         wifi->interface = NULL;
211 }
212
213
214 static int wifi_enable(struct connman_device *device)
215 {
216         struct wifi_data *wifi = connman_device_get_data(device);
217         const char *interface = connman_device_get_string(device, "Interface");
218         const char *driver = connman_option_get_string("wifi");
219         int ret;
220
221         DBG("device %p %p", device, wifi);
222
223         ret = g_supplicant_interface_create(interface, driver, NULL,
224                                                 interface_create_callback,
225                                                         wifi);
226         if (ret < 0)
227                 return ret;
228
229         return -EINPROGRESS;
230 }
231
232 static int wifi_disable(struct connman_device *device)
233 {
234         struct wifi_data *wifi = connman_device_get_data(device);
235         int ret;
236
237         DBG("device %p", device);
238
239         wifi->connected = FALSE;
240         wifi->disconnecting = FALSE;
241
242         if (wifi->pending_network != NULL) {
243                 connman_network_unref(wifi->pending_network);
244                 wifi->pending_network = NULL;
245         }
246
247         ret = g_supplicant_interface_remove(wifi->interface,
248                                                 interface_remove_callback,
249                                                         wifi);
250         if (ret < 0)
251                 return ret;
252
253         return -EINPROGRESS;
254 }
255
256 static void scan_callback(int result, GSupplicantInterface *interface,
257                                                 void *user_data)
258 {
259         struct connman_device *device = user_data;
260
261         DBG("result %d", result);
262
263         if (result < 0)
264                 connman_device_reset_scanning(device);
265         else
266                 connman_device_set_scanning(device, FALSE);
267 }
268
269 static int wifi_scan(struct connman_device *device)
270 {
271         struct wifi_data *wifi = connman_device_get_data(device);
272         int ret;
273
274         DBG("device %p %p", device, wifi->interface);
275
276         if (wifi->tethering == TRUE)
277                 return 0;
278
279         ret = g_supplicant_interface_scan(wifi->interface, scan_callback,
280                                                                 device);
281         if (ret == 0)
282                 connman_device_set_scanning(device, TRUE);
283
284         return ret;
285 }
286
287 static struct connman_device_driver wifi_ng_driver = {
288         .name           = "wifi",
289         .type           = CONNMAN_DEVICE_TYPE_WIFI,
290         .priority       = CONNMAN_DEVICE_PRIORITY_LOW,
291         .probe          = wifi_probe,
292         .remove         = wifi_remove,
293         .enable         = wifi_enable,
294         .disable        = wifi_disable,
295         .scan           = wifi_scan,
296 };
297
298 static void system_ready(void)
299 {
300         DBG("");
301
302         if (connman_device_driver_register(&wifi_ng_driver) < 0)
303                 connman_error("Failed to register WiFi driver");
304 }
305
306 static void system_killed(void)
307 {
308         DBG("");
309
310         connman_device_driver_unregister(&wifi_ng_driver);
311 }
312
313 static int network_probe(struct connman_network *network)
314 {
315         DBG("network %p", network);
316
317         return 0;
318 }
319
320 static void network_remove(struct connman_network *network)
321 {
322         DBG("network %p", network);
323 }
324
325 static void connect_callback(int result, GSupplicantInterface *interface,
326                                                         void *user_data)
327 {
328         struct connman_network *network = user_data;
329
330         DBG("network %p result %d", network, result);
331
332         if (result == -ENOKEY) {
333                 connman_network_set_error(network,
334                                         CONNMAN_NETWORK_ERROR_INVALID_KEY);
335         } else if (result < 0) {
336                 connman_network_set_error(network,
337                                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
338         }
339 }
340
341 static GSupplicantSecurity network_security(const char *security)
342 {
343         if (g_str_equal(security, "none") == TRUE)
344                 return G_SUPPLICANT_SECURITY_NONE;
345         else if (g_str_equal(security, "wep") == TRUE)
346                 return G_SUPPLICANT_SECURITY_WEP;
347         else if (g_str_equal(security, "psk") == TRUE)
348                 return G_SUPPLICANT_SECURITY_PSK;
349         else if (g_str_equal(security, "wpa") == TRUE)
350                 return G_SUPPLICANT_SECURITY_PSK;
351         else if (g_str_equal(security, "rsn") == TRUE)
352                 return G_SUPPLICANT_SECURITY_PSK;
353         else if (g_str_equal(security, "ieee8021x") == TRUE)
354                 return G_SUPPLICANT_SECURITY_IEEE8021X;
355
356         return G_SUPPLICANT_SECURITY_UNKNOWN;
357 }
358
359 static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
360 {
361         const char *security, *passphrase;
362
363         memset(ssid, 0, sizeof(*ssid));
364         ssid->mode = G_SUPPLICANT_MODE_INFRA;
365         ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
366                                                 &ssid->ssid_len);
367         ssid->scan_ssid = 1;
368         security = connman_network_get_string(network, "WiFi.Security");
369         ssid->security = network_security(security);
370         passphrase = connman_network_get_string(network,
371                                                 "WiFi.Passphrase");
372         if (passphrase == NULL || strlen(passphrase) == 0)
373                 ssid->passphrase = NULL;
374         else
375                 ssid->passphrase = passphrase;
376
377         ssid->eap = connman_network_get_string(network, "WiFi.EAP");
378
379         /*
380          * If our private key password is unset,
381          * we use the supplied passphrase. That is needed
382          * for PEAP where 2 passphrases (identity and client
383          * cert may have to be provided.
384          */
385         if (connman_network_get_string(network,
386                                         "WiFi.PrivateKeyPassphrase") == NULL)
387                 connman_network_set_string(network,
388                                                 "WiFi.PrivateKeyPassphrase",
389                                                 ssid->passphrase);
390         /* We must have an identity for both PEAP and TLS */
391         ssid->identity = connman_network_get_string(network, "WiFi.Identity");
392         ssid->ca_cert_path = connman_network_get_string(network,
393                                                         "WiFi.CACertFile");
394         ssid->client_cert_path = connman_network_get_string(network,
395                                                         "WiFi.ClientCertFile");
396         ssid->private_key_path = connman_network_get_string(network,
397                                                         "WiFi.PrivateKeyFile");
398         ssid->private_key_passphrase = connman_network_get_string(network,
399                                                 "WiFi.PrivateKeyPassphrase");
400         ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
401
402         ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS");
403         ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS");
404
405 }
406
407 static int network_connect(struct connman_network *network)
408 {
409         struct connman_device *device = connman_network_get_device(network);
410         struct wifi_data *wifi;
411         GSupplicantInterface *interface;
412         GSupplicantSSID *ssid;
413
414         DBG("network %p", network);
415
416         if (device == NULL)
417                 return -ENODEV;
418
419         wifi = connman_device_get_data(device);
420         if (wifi == NULL)
421                 return -ENODEV;
422
423         ssid = g_try_malloc0(sizeof(GSupplicantSSID));
424         if (ssid == NULL)
425                 return -ENOMEM;
426
427         interface = wifi->interface;
428
429         ssid_init(ssid, network);
430
431         if (wifi->disconnecting == TRUE)
432                 wifi->pending_network = connman_network_ref(network);
433         else {
434                 wifi->network = connman_network_ref(network);
435
436                 return g_supplicant_interface_connect(interface, ssid,
437                                                 connect_callback, network);
438         }
439
440         return -EINPROGRESS;
441 }
442
443 static void disconnect_callback(int result, GSupplicantInterface *interface,
444                                                                 void *user_data)
445 {
446         struct wifi_data *wifi = user_data;
447
448         if (wifi->network != NULL) {
449                 /*
450                  * if result < 0 supplican return an error because
451                  * the network is not current.
452                  * we wont receive G_SUPPLICANT_STATE_DISCONNECTED since it
453                  * failed, call connman_network_set_connected to report
454                  * disconnect is completed.
455                  */
456                 if (result < 0)
457                         connman_network_set_connected(wifi->network, FALSE);
458
459                 connman_network_unref(wifi->network);
460         }
461
462         wifi->network = NULL;
463
464         wifi->disconnecting = FALSE;
465
466         if (wifi->pending_network != NULL) {
467                 network_connect(wifi->pending_network);
468                 connman_network_unref(wifi->pending_network);
469                 wifi->pending_network = NULL;
470         }
471
472 }
473
474 static int network_disconnect(struct connman_network *network)
475 {
476         struct connman_device *device = connman_network_get_device(network);
477         struct wifi_data *wifi;
478         int err;
479
480         DBG("network %p", network);
481
482         wifi = connman_device_get_data(device);
483         if (wifi == NULL || wifi->interface == NULL)
484                 return -ENODEV;
485
486         connman_network_set_associating(network, FALSE);
487
488         if (wifi->disconnecting == TRUE)
489                 return -EALREADY;
490
491         wifi->disconnecting = TRUE;
492
493         err = g_supplicant_interface_disconnect(wifi->interface,
494                                                 disconnect_callback, wifi);
495         if (err < 0)
496                 wifi->disconnecting = FALSE;
497
498         return err;
499 }
500
501 static struct connman_network_driver network_driver = {
502         .name           = "wifi",
503         .type           = CONNMAN_NETWORK_TYPE_WIFI,
504         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
505         .probe          = network_probe,
506         .remove         = network_remove,
507         .connect        = network_connect,
508         .disconnect     = network_disconnect,
509 };
510
511 static void interface_added(GSupplicantInterface *interface)
512 {
513         const char *ifname = g_supplicant_interface_get_ifname(interface);
514         const char *driver = g_supplicant_interface_get_driver(interface);
515         struct wifi_data *wifi;
516
517         wifi = g_supplicant_interface_get_data(interface);
518
519         /*
520          * We can get here with a NULL wifi pointer when
521          * the interface added signal is sent before the
522          * interface creation callback is called.
523          */
524         if (wifi == NULL)
525                 return;
526
527         DBG("ifname %s driver %s wifi %p tethering %d",
528                         ifname, driver, wifi, wifi->tethering);
529
530         if (wifi->device == NULL) {
531                 connman_error("WiFi device not set");
532                 return;
533         }
534
535         connman_device_set_powered(wifi->device, TRUE);
536
537         if (wifi->tethering == TRUE)
538                 return;
539
540         wifi_scan(wifi->device);
541 }
542
543 static connman_bool_t is_idle(struct wifi_data *wifi)
544 {
545         DBG("state %d", wifi->state);
546
547         switch (wifi->state) {
548         case G_SUPPLICANT_STATE_UNKNOWN:
549         case G_SUPPLICANT_STATE_DISCONNECTED:
550         case G_SUPPLICANT_STATE_INACTIVE:
551         case G_SUPPLICANT_STATE_SCANNING:
552                 return TRUE;
553
554         case G_SUPPLICANT_STATE_AUTHENTICATING:
555         case G_SUPPLICANT_STATE_ASSOCIATING:
556         case G_SUPPLICANT_STATE_ASSOCIATED:
557         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
558         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
559         case G_SUPPLICANT_STATE_COMPLETED:
560                 return FALSE;
561         }
562
563         return FALSE;
564 }
565
566 static connman_bool_t is_idle_wps(GSupplicantInterface *interface,
567                                                 struct wifi_data *wifi)
568 {
569         /* First, let's check if WPS processing did not went wrong */
570         if (g_supplicant_interface_get_wps_state(interface) ==
571                 G_SUPPLICANT_WPS_STATE_FAIL)
572                 return FALSE;
573
574         /* Unlike normal connection, being associated while processing wps
575          * actually means that we are idling. */
576         switch (wifi->state) {
577         case G_SUPPLICANT_STATE_UNKNOWN:
578         case G_SUPPLICANT_STATE_DISCONNECTED:
579         case G_SUPPLICANT_STATE_INACTIVE:
580         case G_SUPPLICANT_STATE_SCANNING:
581         case G_SUPPLICANT_STATE_ASSOCIATED:
582                 return TRUE;
583         case G_SUPPLICANT_STATE_AUTHENTICATING:
584         case G_SUPPLICANT_STATE_ASSOCIATING:
585         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
586         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
587         case G_SUPPLICANT_STATE_COMPLETED:
588                 return FALSE;
589         }
590
591         return FALSE;
592 }
593
594 static connman_bool_t handle_wps_completion(GSupplicantInterface *interface,
595                                         struct connman_network *network,
596                                         struct connman_device *device,
597                                         struct wifi_data *wifi)
598 {
599         connman_bool_t wps;
600
601         wps = connman_network_get_bool(network, "WiFi.UseWPS");
602         if (wps == TRUE) {
603                 const unsigned char *ssid, *wps_ssid;
604                 unsigned int ssid_len, wps_ssid_len;
605                 const char *wps_key;
606
607                 /* Checking if we got associated with requested
608                  * network */
609                 ssid = connman_network_get_blob(network, "WiFi.SSID",
610                                                 &ssid_len);
611
612                 wps_ssid = g_supplicant_interface_get_wps_ssid(
613                         interface, &wps_ssid_len);
614
615                 if (wps_ssid == NULL || wps_ssid_len != ssid_len ||
616                                 memcmp(ssid, wps_ssid, ssid_len) != 0) {
617                         connman_network_set_associating(network, FALSE);
618                         g_supplicant_interface_disconnect(wifi->interface,
619                                                 disconnect_callback, wifi);
620                         return FALSE;
621                 }
622
623                 wps_key = g_supplicant_interface_get_wps_key(interface);
624                 connman_network_set_string(network, "WiFi.Passphrase",
625                                         wps_key);
626
627                 connman_network_set_string(network, "WiFi.PinWPS", NULL);
628         }
629
630         return TRUE;
631 }
632
633 static void interface_state(GSupplicantInterface *interface)
634 {
635         struct connman_network *network;
636         struct connman_device *device;
637         struct wifi_data *wifi;
638         GSupplicantState state = g_supplicant_interface_get_state(interface);
639         connman_bool_t wps;
640
641         wifi = g_supplicant_interface_get_data(interface);
642
643         DBG("wifi %p interface state %d", wifi, state);
644
645         if (wifi == NULL)
646                 return;
647
648         network = wifi->network;
649         device = wifi->device;
650
651         if (device == NULL || network == NULL)
652                 return;
653
654         switch (state) {
655         case G_SUPPLICANT_STATE_SCANNING:
656                 break;
657
658         case G_SUPPLICANT_STATE_AUTHENTICATING:
659         case G_SUPPLICANT_STATE_ASSOCIATING:
660                 connman_network_set_associating(network, TRUE);
661                 break;
662
663         case G_SUPPLICANT_STATE_COMPLETED:
664                 if (handle_wps_completion(interface, network, device, wifi) ==
665                                                                         FALSE)
666                         break;
667
668                 /* reset scan trigger and schedule background scan */
669                 connman_device_schedule_scan(device);
670
671                 connman_network_set_connected(network, TRUE);
672                 break;
673
674         case G_SUPPLICANT_STATE_DISCONNECTED:
675                 /*
676                  * If we're in one of the idle modes, we have
677                  * not started association yet and thus setting
678                  * those ones to FALSE could cancel an association
679                  * in progress.
680                  */
681                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
682                 if (wps == TRUE)
683                         if (is_idle_wps(interface, wifi) == TRUE)
684                                 break;
685
686                 if (is_idle(wifi))
687                         break;
688                 connman_network_set_associating(network, FALSE);
689                 connman_network_set_connected(network, FALSE);
690                 break;
691
692         case G_SUPPLICANT_STATE_INACTIVE:
693                 connman_network_set_associating(network, FALSE);
694                 break;
695
696         case G_SUPPLICANT_STATE_UNKNOWN:
697         case G_SUPPLICANT_STATE_ASSOCIATED:
698         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
699         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
700                 break;
701         }
702
703         wifi->state = state;
704
705         DBG("DONE");
706 }
707
708 static void interface_removed(GSupplicantInterface *interface)
709 {
710         const char *ifname = g_supplicant_interface_get_ifname(interface);
711         struct wifi_data *wifi;
712
713         DBG("ifname %s", ifname);
714
715         wifi = g_supplicant_interface_get_data(interface);
716
717         if (wifi != NULL && wifi->tethering == TRUE)
718                 return;
719
720         if (wifi == NULL || wifi->device == NULL) {
721                 connman_error("Wrong wifi pointer");
722                 return;
723         }
724
725         connman_device_set_powered(wifi->device, FALSE);
726 }
727
728 static void scan_started(GSupplicantInterface *interface)
729 {
730         struct wifi_data *wifi;
731
732         DBG("");
733
734         wifi = g_supplicant_interface_get_data(interface);
735
736         if (wifi == NULL)
737                 return;
738 }
739
740 static void scan_finished(GSupplicantInterface *interface)
741 {
742         struct wifi_data *wifi;
743
744         DBG("");
745
746         wifi = g_supplicant_interface_get_data(interface);
747
748         if (wifi == NULL)
749                 return;
750 }
751
752 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
753 {
754         unsigned char strength;
755
756         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
757         if (strength > 100)
758                 strength = 100;
759
760         return strength;
761 }
762
763 static void network_added(GSupplicantNetwork *supplicant_network)
764 {
765         struct connman_network *network;
766         GSupplicantInterface *interface;
767         struct wifi_data *wifi;
768         const char *name, *identifier, *security, *group;
769         const unsigned char *ssid;
770         unsigned int ssid_len;
771         connman_bool_t wps;
772
773         DBG("");
774
775         interface = g_supplicant_network_get_interface(supplicant_network);
776         wifi = g_supplicant_interface_get_data(interface);
777         name = g_supplicant_network_get_name(supplicant_network);
778         identifier = g_supplicant_network_get_identifier(supplicant_network);
779         security = g_supplicant_network_get_security(supplicant_network);
780         group = g_supplicant_network_get_identifier(supplicant_network);
781         wps = g_supplicant_network_get_wps(supplicant_network);
782
783         if (wifi == NULL)
784                 return;
785
786         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
787
788         network = connman_device_get_network(wifi->device, identifier);
789
790         if (network == NULL) {
791                 network = connman_network_create(identifier,
792                                                 CONNMAN_NETWORK_TYPE_WIFI);
793                 if (network == NULL)
794                         return;
795
796                 connman_network_set_index(network, wifi->index);
797
798                 if (connman_device_add_network(wifi->device, network) < 0) {
799                         connman_network_unref(network);
800                         return;
801                 }
802         }
803
804         if (name != NULL && name[0] != '\0')
805                 connman_network_set_name(network, name);
806
807         connman_network_set_blob(network, "WiFi.SSID",
808                                                 ssid, ssid_len);
809         connman_network_set_string(network, "WiFi.Security", security);
810         connman_network_set_strength(network,
811                                 calculate_strength(supplicant_network));
812         connman_network_set_bool(network, "WiFi.WPS", wps);
813
814         connman_network_set_available(network, TRUE);
815
816         if (ssid != NULL)
817                 connman_network_set_group(network, group);
818 }
819
820 static void network_removed(GSupplicantNetwork *network)
821 {
822         GSupplicantInterface *interface;
823         struct wifi_data *wifi;
824         const char *name, *identifier;
825         struct connman_network *connman_network;
826
827         interface = g_supplicant_network_get_interface(network);
828         wifi = g_supplicant_interface_get_data(interface);
829         identifier = g_supplicant_network_get_identifier(network);
830         name = g_supplicant_network_get_name(network);
831
832         DBG("name %s", name);
833
834         if (wifi == NULL)
835                 return;
836
837         connman_network = connman_device_get_network(wifi->device, identifier);
838         if (connman_network == NULL)
839                 return;
840
841         connman_device_remove_network(wifi->device, connman_network);
842         connman_network_unref(connman_network);
843 }
844
845 static void debug(const char *str)
846 {
847         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
848                 connman_debug("%s", str);
849 }
850
851 static const GSupplicantCallbacks callbacks = {
852         .system_ready           = system_ready,
853         .system_killed          = system_killed,
854         .interface_added        = interface_added,
855         .interface_state        = interface_state,
856         .interface_removed      = interface_removed,
857         .scan_started           = scan_started,
858         .scan_finished          = scan_finished,
859         .network_added          = network_added,
860         .network_removed        = network_removed,
861         .debug                  = debug,
862 };
863
864
865 static int tech_probe(struct connman_technology *technology)
866 {
867         wifi_technology = technology;
868
869         return 0;
870 }
871
872 static void tech_remove(struct connman_technology *technology)
873 {
874         wifi_technology = NULL;
875 }
876
877 struct wifi_tethering_info {
878         struct wifi_data *wifi;
879         struct connman_technology *technology;
880         char *ifname;
881         GSupplicantSSID *ssid;
882 };
883
884 static GSupplicantSSID *ssid_ap_init(const char *ssid, const char *passphrase)
885 {
886         GSupplicantSSID *ap;
887
888         ap = g_try_malloc0(sizeof(GSupplicantSSID));
889         if (ap == NULL)
890                 return NULL;
891
892         ap->mode = G_SUPPLICANT_MODE_MASTER;
893         ap->ssid = ssid;
894         ap->ssid_len = strlen(ssid);
895         ap->scan_ssid = 0;
896         ap->freq = 2412;
897
898         if (passphrase == NULL || strlen(passphrase) == 0) {
899                 ap->security = G_SUPPLICANT_SECURITY_NONE;
900                 ap->passphrase = NULL;
901         } else {
902                ap->security = G_SUPPLICANT_SECURITY_PSK;
903                ap->protocol = G_SUPPLICANT_PROTO_RSN;
904                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
905                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
906                ap->passphrase = passphrase;
907         }
908
909         return ap;
910 }
911
912 static void ap_start_callback(int result, GSupplicantInterface *interface,
913                                                         void *user_data)
914 {
915         struct wifi_tethering_info *info = user_data;
916
917         DBG("result %d index %d bridge %s",
918                 result, info->wifi->index, info->wifi->bridge);
919
920         if (result < 0) {
921                 connman_inet_remove_from_bridge(info->wifi->index,
922                                                         info->wifi->bridge);
923                 connman_technology_tethering_notify(info->technology, FALSE);
924         }
925
926         g_free(info->ifname);
927         g_free(info);
928 }
929
930 static void ap_create_callback(int result,
931                                 GSupplicantInterface *interface,
932                                         void *user_data)
933 {
934         struct wifi_tethering_info *info = user_data;
935
936         DBG("result %d ifname %s", result,
937                                 g_supplicant_interface_get_ifname(interface));
938
939         if (result < 0) {
940                 connman_inet_remove_from_bridge(info->wifi->index,
941                                                         info->wifi->bridge);
942                 connman_technology_tethering_notify(info->technology, FALSE);
943
944                 g_free(info->ifname);
945                 g_free(info);
946                 return;
947         }
948
949         info->wifi->interface = interface;
950         g_supplicant_interface_set_data(interface, info->wifi);
951
952         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
953                 connman_error("Failed to set interface ap_scan property");
954
955         g_supplicant_interface_connect(interface, info->ssid,
956                                                 ap_start_callback, info);
957 }
958
959 static void sta_remove_callback(int result,
960                                 GSupplicantInterface *interface,
961                                         void *user_data)
962 {
963         struct wifi_tethering_info *info = user_data;
964         const char *driver = connman_option_get_string("wifi");
965
966         DBG("ifname %s result %d ", info->ifname, result);
967
968         if (result < 0) {
969                 info->wifi->tethering = TRUE;
970
971                 g_free(info->ifname);
972                 g_free(info);
973                 return;
974         }
975
976         info->wifi->interface = NULL;
977
978         connman_technology_tethering_notify(info->technology, TRUE);
979
980         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
981                                                 ap_create_callback,
982                                                         info);
983 }
984
985 static int tech_set_tethering(struct connman_technology *technology,
986                                 const char *identifier, const char *passphrase,
987                                 const char *bridge, connman_bool_t enabled)
988 {
989         GList *list;
990         GSupplicantInterface *interface;
991         struct wifi_data *wifi;
992         struct wifi_tethering_info *info;
993         const char *ifname;
994         unsigned int mode;
995         int err;
996
997         DBG("");
998
999         if (enabled == FALSE) {
1000                 for (list = iface_list; list; list = list->next) {
1001                         wifi = list->data;
1002
1003                         if (wifi->tethering == TRUE) {
1004                                 wifi->tethering = FALSE;
1005
1006                                 connman_inet_remove_from_bridge(wifi->index,
1007                                                                         bridge);
1008                                 wifi->bridged = FALSE;
1009                         }
1010                 }
1011
1012                 connman_technology_tethering_notify(technology, FALSE);
1013
1014                 return 0;
1015         }
1016
1017         for (list = iface_list; list; list = list->next) {
1018                 wifi = list->data;
1019
1020                 interface = wifi->interface;
1021
1022                 if (interface == NULL)
1023                         continue;
1024
1025                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
1026
1027                 mode = g_supplicant_interface_get_mode(interface);
1028                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
1029                         DBG("%s does not support AP mode", ifname);
1030                         continue;
1031                 }
1032
1033                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
1034                 if (info == NULL)
1035                         return -ENOMEM;
1036
1037                 info->wifi = wifi;
1038                 info->technology = technology;
1039                 info->wifi->bridge = bridge;
1040                 info->ssid = ssid_ap_init(identifier, passphrase);
1041                 if (info->ssid == NULL) {
1042                         g_free(info);
1043                         continue;
1044                 }
1045                 info->ifname = g_strdup(ifname);
1046                 if (info->ifname == NULL) {
1047                         g_free(info);
1048                         continue;
1049                 }
1050
1051                 info->wifi->tethering = TRUE;
1052
1053                 err = g_supplicant_interface_remove(interface,
1054                                                 sta_remove_callback,
1055                                                         info);
1056                 if (err == 0)
1057                         return err;
1058         }
1059
1060         return -EOPNOTSUPP;
1061 }
1062
1063 static void regdom_callback(void *user_data)
1064 {
1065         char *alpha2 = user_data;
1066
1067         DBG("");
1068
1069         if (wifi_technology == NULL)
1070                 return;
1071
1072         connman_technology_regdom_notify(wifi_technology, alpha2);
1073 }
1074
1075 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
1076 {
1077         return g_supplicant_set_country(alpha2, regdom_callback, alpha2);
1078 }
1079
1080 static struct connman_technology_driver tech_driver = {
1081         .name           = "wifi",
1082         .type           = CONNMAN_SERVICE_TYPE_WIFI,
1083         .probe          = tech_probe,
1084         .remove         = tech_remove,
1085         .set_tethering  = tech_set_tethering,
1086         .set_regdom     = tech_set_regdom,
1087 };
1088
1089 static int wifi_init(void)
1090 {
1091         int err;
1092
1093         err = connman_network_driver_register(&network_driver);
1094         if (err < 0)
1095                 return err;
1096
1097         err = g_supplicant_register(&callbacks);
1098         if (err < 0) {
1099                 connman_network_driver_unregister(&network_driver);
1100                 return err;
1101         }
1102
1103         err = connman_technology_driver_register(&tech_driver);
1104         if (err < 0) {
1105                 g_supplicant_unregister(&callbacks);
1106                 connman_network_driver_unregister(&network_driver);
1107                 return err;
1108         }
1109
1110         return 0;
1111 }
1112
1113 static void wifi_exit(void)
1114 {
1115         DBG();
1116
1117         connman_technology_driver_unregister(&tech_driver);
1118
1119         g_supplicant_unregister(&callbacks);
1120
1121         connman_network_driver_unregister(&network_driver);
1122 }
1123
1124 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
1125                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)