wifi: The remove interface callback used stale pointer.
[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 <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/log.h>
51 #include <connman/option.h>
52 #include <connman/storage.h>
53
54 #include <gsupplicant/gsupplicant.h>
55
56 #define CLEANUP_TIMEOUT   8     /* in seconds */
57 #define INACTIVE_TIMEOUT  12    /* in seconds */
58 #define MAXIMUM_RETRIES   4
59
60 struct connman_technology *wifi_technology = NULL;
61
62 struct wifi_data {
63         char *identifier;
64         struct connman_device *device;
65         struct connman_network *network;
66         struct connman_network *pending_network;
67         GSList *networks;
68         GSupplicantInterface *interface;
69         GSupplicantState state;
70         connman_bool_t connected;
71         connman_bool_t disconnecting;
72         connman_bool_t tethering;
73         connman_bool_t bridged;
74         const char *bridge;
75         int index;
76         unsigned flags;
77         unsigned int watch;
78         int retries;
79 };
80
81 static GList *iface_list = NULL;
82
83 static void handle_tethering(struct wifi_data *wifi)
84 {
85         if (wifi->tethering == FALSE)
86                 return;
87
88         if (wifi->bridge == NULL)
89                 return;
90
91         if (wifi->bridged == TRUE)
92                 return;
93
94         DBG("index %d bridge %s", wifi->index, wifi->bridge);
95
96         if (connman_inet_add_to_bridge(wifi->index, wifi->bridge) < 0)
97                 return;
98
99         wifi->bridged = TRUE;
100 }
101
102 static void wifi_newlink(unsigned flags, unsigned change, void *user_data)
103 {
104         struct connman_device *device = user_data;
105         struct wifi_data *wifi = connman_device_get_data(device);
106
107         DBG("index %d flags %d change %d", wifi->index, flags, change);
108
109         if (!change)
110                 return;
111
112         if ((wifi->flags & IFF_UP) != (flags & IFF_UP)) {
113                 if (flags & IFF_UP)
114                         DBG("interface up");
115                 else
116                         DBG("interface down");
117         }
118
119         if ((wifi->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
120                 if (flags & IFF_LOWER_UP) {
121                         DBG("carrier on");
122
123                         handle_tethering(wifi);
124                 } else
125                         DBG("carrier off");
126         }
127
128         wifi->flags = flags;
129 }
130
131 static int wifi_probe(struct connman_device *device)
132 {
133         struct wifi_data *wifi;
134
135         DBG("device %p", device);
136
137         wifi = g_try_new0(struct wifi_data, 1);
138         if (wifi == NULL)
139                 return -ENOMEM;
140
141         wifi->connected = FALSE;
142         wifi->disconnecting = FALSE;
143         wifi->tethering = FALSE;
144         wifi->bridged = FALSE;
145         wifi->bridge = NULL;
146         wifi->state = G_SUPPLICANT_STATE_INACTIVE;
147
148         connman_device_set_data(device, wifi);
149         wifi->device = connman_device_ref(device);
150
151         wifi->index = connman_device_get_index(device);
152         wifi->flags = 0;
153
154         wifi->watch = connman_rtnl_add_newlink_watch(wifi->index,
155                                                         wifi_newlink, device);
156
157         iface_list = g_list_append(iface_list, wifi);
158
159         return 0;
160 }
161
162 static void remove_networks(struct connman_device *device,
163                                 struct wifi_data *wifi)
164 {
165         GSList *list;
166
167         for (list = wifi->networks; list != NULL; list = list->next) {
168                 struct connman_network *network = list->data;
169
170                 connman_device_remove_network(device, network);
171                 connman_network_unref(network);
172         }
173
174         g_slist_free(wifi->networks);
175         wifi->networks = NULL;
176 }
177
178 static void wifi_remove(struct connman_device *device)
179 {
180         struct wifi_data *wifi = connman_device_get_data(device);
181
182         DBG("device %p wifi %p", device, wifi);
183
184         if (wifi == NULL)
185                 return;
186
187         iface_list = g_list_remove(iface_list, wifi);
188
189         remove_networks(device, wifi);
190
191         connman_device_set_data(device, NULL);
192         connman_device_unref(wifi->device);
193         connman_rtnl_remove_watch(wifi->watch);
194
195         g_supplicant_interface_set_data(wifi->interface, NULL);
196
197         g_free(wifi->identifier);
198         g_free(wifi);
199 }
200
201 static void interface_create_callback(int result,
202                                         GSupplicantInterface *interface,
203                                                         void *user_data)
204 {
205         struct wifi_data *wifi = user_data;
206
207         DBG("result %d ifname %s, wifi %p", result,
208                                 g_supplicant_interface_get_ifname(interface),
209                                 wifi);
210
211         if (result < 0 || wifi == NULL)
212                 return;
213
214         wifi->interface = interface;
215         g_supplicant_interface_set_data(interface, wifi);
216 }
217
218 static void interface_remove_callback(int result,
219                                         GSupplicantInterface *interface,
220                                                         void *user_data)
221 {
222         struct wifi_data *wifi;
223
224         wifi = g_supplicant_interface_get_data(interface);
225
226         DBG("result %d wifi %p", result, wifi);
227
228         if (result < 0 || wifi == NULL)
229                 return;
230
231         wifi->interface = NULL;
232 }
233
234
235 static int wifi_enable(struct connman_device *device)
236 {
237         struct wifi_data *wifi = connman_device_get_data(device);
238         const char *interface = connman_device_get_string(device, "Interface");
239         const char *driver = connman_option_get_string("wifi");
240         int ret;
241
242         DBG("device %p %p", device, wifi);
243
244         ret = g_supplicant_interface_create(interface, driver, NULL,
245                                                 interface_create_callback,
246                                                         wifi);
247         if (ret < 0)
248                 return ret;
249
250         return -EINPROGRESS;
251 }
252
253 static int wifi_disable(struct connman_device *device)
254 {
255         struct wifi_data *wifi = connman_device_get_data(device);
256         int ret;
257
258         DBG("device %p", device);
259
260         wifi->connected = FALSE;
261         wifi->disconnecting = FALSE;
262
263         if (wifi->pending_network != NULL)
264                 wifi->pending_network = NULL;
265
266         remove_networks(device, wifi);
267
268         ret = g_supplicant_interface_remove(wifi->interface,
269                                                 interface_remove_callback,
270                                                 NULL);
271         if (ret < 0)
272                 return ret;
273
274         return -EINPROGRESS;
275 }
276
277 static void scan_callback(int result, GSupplicantInterface *interface,
278                                                 void *user_data)
279 {
280         struct connman_device *device = user_data;
281
282         DBG("result %d", result);
283
284         if (result < 0)
285                 connman_device_reset_scanning(device);
286         else
287                 connman_device_set_scanning(device, FALSE);
288         connman_device_unref(device);
289 }
290
291 static int add_scan_param(gchar *hex_ssid, int freq,
292                         GSupplicantScanParams *scan_data,
293                         int driver_max_scan_ssids)
294 {
295         unsigned int i;
296
297         if (driver_max_scan_ssids > scan_data->num_ssids && hex_ssid != NULL) {
298                 gchar *ssid;
299                 unsigned int j = 0, hex;
300                 size_t hex_ssid_len = strlen(hex_ssid);
301
302                 ssid = g_try_malloc0(hex_ssid_len / 2);
303                 if (ssid == NULL)
304                         return -ENOMEM;
305
306                 for (i = 0; i < hex_ssid_len; i += 2) {
307                         sscanf(hex_ssid + i, "%02x", &hex);
308                         ssid[j++] = hex;
309                 }
310
311                 memcpy(scan_data->ssids[scan_data->num_ssids].ssid, ssid, j);
312                 scan_data->ssids[scan_data->num_ssids].ssid_len = j;
313                 scan_data->num_ssids++;
314
315                 g_free(ssid);
316         }
317
318         /* Don't add duplicate entries */
319         for (i = 0; i < G_SUPPLICANT_MAX_FAST_SCAN; i++) {
320                 if (scan_data->freqs[i] == 0) {
321                         scan_data->freqs[i] = freq;
322                         break;
323                 } else if (scan_data->freqs[i] == freq)
324                         break;
325         }
326
327         return 0;
328 }
329
330 struct last_connected {
331         GTimeVal modified;
332         gchar *ssid;
333         int freq;
334 };
335
336 static gint sort_entry(gconstpointer a, gconstpointer b, gpointer user_data)
337 {
338         GTimeVal *aval = (GTimeVal *)a;
339         GTimeVal *bval = (GTimeVal *)b;
340
341         /* Note that the sort order is descending */
342         if (aval->tv_sec < bval->tv_sec)
343                 return 1;
344
345         if (aval->tv_sec > bval->tv_sec)
346                 return -1;
347
348         return 0;
349 }
350
351 static void free_entry(gpointer data)
352 {
353         struct last_connected *entry = data;
354
355         g_free(entry->ssid);
356         g_free(entry);
357 }
358
359 static int get_latest_connections(int max_ssids,
360                                 GSupplicantScanParams *scan_data)
361 {
362         GSequenceIter *iter;
363         GSequence *latest_list;
364         struct last_connected *entry;
365         GKeyFile *keyfile;
366         GTimeVal modified;
367         gchar **services;
368         gchar *str;
369         char *ssid;
370         int i, freq;
371         int num_ssids = 0;
372
373         latest_list = g_sequence_new(free_entry);
374         if (latest_list == NULL)
375                 return -ENOMEM;
376
377         services = connman_storage_get_services();
378         for (i = 0; services && services[i]; i++) {
379                 if (strncmp(services[i], "wifi_", 5) != 0)
380                         continue;
381
382                 keyfile = connman_storage_load_service(services[i]);
383
384                 str = g_key_file_get_string(keyfile,
385                                         services[i], "Favorite", NULL);
386                 if (str == NULL || g_strcmp0(str, "true")) {
387                         if (str)
388                                 g_free(str);
389                         g_key_file_free(keyfile);
390                         continue;
391                 }
392                 g_free(str);
393
394                 str = g_key_file_get_string(keyfile,
395                                         services[i], "AutoConnect", NULL);
396                 if (str == NULL || g_strcmp0(str, "true")) {
397                         if (str)
398                                 g_free(str);
399                         g_key_file_free(keyfile);
400                         continue;
401                 }
402                 g_free(str);
403
404                 str = g_key_file_get_string(keyfile,
405                                         services[i], "Modified", NULL);
406                 if (str != NULL) {
407                         g_time_val_from_iso8601(str, &modified);
408                         g_free(str);
409                 }
410
411                 ssid = g_key_file_get_string(keyfile,
412                                         services[i], "SSID", NULL);
413
414                 freq = g_key_file_get_integer(keyfile, services[i],
415                                         "Frequency", NULL);
416                 if (freq) {
417                         entry = g_try_new(struct last_connected, 1);
418                         if (entry == NULL) {
419                                 g_sequence_free(latest_list);
420                                 g_key_file_free(keyfile);
421                                 g_free(ssid);
422                                 return -ENOMEM;
423                         }
424
425                         entry->ssid = ssid;
426                         entry->modified = modified;
427                         entry->freq = freq;
428
429                         g_sequence_insert_sorted(latest_list, entry,
430                                                 sort_entry, NULL);
431                         num_ssids++;
432                 } else
433                         g_free(ssid);
434
435                 g_key_file_free(keyfile);
436         }
437
438         g_strfreev(services);
439
440         num_ssids = num_ssids > G_SUPPLICANT_MAX_FAST_SCAN ?
441                 G_SUPPLICANT_MAX_FAST_SCAN : num_ssids;
442
443         iter = g_sequence_get_begin_iter(latest_list);
444
445         for (i = 0; i < num_ssids; i++) {
446                 entry = g_sequence_get(iter);
447
448                 DBG("ssid %s freq %d modified %lu", entry->ssid, entry->freq,
449                                                 entry->modified.tv_sec);
450
451                 add_scan_param(entry->ssid, entry->freq, scan_data, max_ssids);
452
453                 iter = g_sequence_iter_next(iter);
454         }
455
456         g_sequence_free(latest_list);
457         return num_ssids;
458 }
459
460 static int wifi_scan(struct connman_device *device)
461 {
462         struct wifi_data *wifi = connman_device_get_data(device);
463         int ret;
464
465         DBG("device %p %p", device, wifi->interface);
466
467         if (wifi->tethering == TRUE)
468                 return 0;
469
470         connman_device_ref(device);
471         ret = g_supplicant_interface_scan(wifi->interface, NULL,
472                                         scan_callback, device);
473         if (ret == 0)
474                 connman_device_set_scanning(device, TRUE);
475         else
476                 connman_device_unref(device);
477
478         return ret;
479 }
480
481 static int wifi_scan_fast(struct connman_device *device)
482 {
483         struct wifi_data *wifi = connman_device_get_data(device);
484         GSupplicantScanParams *scan_params = NULL;
485         int ret;
486         int driver_max_ssids = 0;
487
488         DBG("device %p %p", device, wifi->interface);
489
490         if (wifi->tethering == TRUE)
491                 return 0;
492
493         driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
494                                                         wifi->interface);
495         DBG("max ssids %d", driver_max_ssids);
496         if (driver_max_ssids == 0)
497                 return wifi_scan(device);
498
499         scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
500         if (scan_params == NULL)
501                 return -ENOMEM;
502
503         ret = get_latest_connections(driver_max_ssids, scan_params);
504         if (ret <= 0) {
505                 g_free(scan_params);
506                 return wifi_scan(device);
507         }
508
509         connman_device_ref(device);
510         ret = g_supplicant_interface_scan(wifi->interface, scan_params,
511                                                 scan_callback, device);
512         if (ret == 0)
513                 connman_device_set_scanning(device, TRUE);
514         else {
515                 g_free(scan_params);
516                 connman_device_unref(device);
517         }
518
519         return ret;
520 }
521
522 static struct connman_device_driver wifi_ng_driver = {
523         .name           = "wifi",
524         .type           = CONNMAN_DEVICE_TYPE_WIFI,
525         .priority       = CONNMAN_DEVICE_PRIORITY_LOW,
526         .probe          = wifi_probe,
527         .remove         = wifi_remove,
528         .enable         = wifi_enable,
529         .disable        = wifi_disable,
530         .scan           = wifi_scan,
531         .scan_fast      = wifi_scan_fast,
532 };
533
534 static void system_ready(void)
535 {
536         DBG("");
537
538         if (connman_device_driver_register(&wifi_ng_driver) < 0)
539                 connman_error("Failed to register WiFi driver");
540 }
541
542 static void system_killed(void)
543 {
544         DBG("");
545
546         connman_device_driver_unregister(&wifi_ng_driver);
547 }
548
549 static int network_probe(struct connman_network *network)
550 {
551         DBG("network %p", network);
552
553         return 0;
554 }
555
556 static void network_remove(struct connman_network *network)
557 {
558         struct connman_device *device = connman_network_get_device(network);
559         struct wifi_data *wifi;
560
561         DBG("network %p", network);
562
563         wifi = connman_device_get_data(device);
564         if (wifi == NULL)
565                 return;
566
567         if (wifi->network != network)
568                 return;
569
570         wifi->network = NULL;
571 }
572
573 static void connect_callback(int result, GSupplicantInterface *interface,
574                                                         void *user_data)
575 {
576         struct connman_network *network = user_data;
577
578         DBG("network %p result %d", network, result);
579
580         if (result == -ENOKEY) {
581                 connman_network_set_error(network,
582                                         CONNMAN_NETWORK_ERROR_INVALID_KEY);
583         } else if (result < 0) {
584                 connman_network_set_error(network,
585                                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
586         }
587 }
588
589 static GSupplicantSecurity network_security(const char *security)
590 {
591         if (g_str_equal(security, "none") == TRUE)
592                 return G_SUPPLICANT_SECURITY_NONE;
593         else if (g_str_equal(security, "wep") == TRUE)
594                 return G_SUPPLICANT_SECURITY_WEP;
595         else if (g_str_equal(security, "psk") == TRUE)
596                 return G_SUPPLICANT_SECURITY_PSK;
597         else if (g_str_equal(security, "wpa") == TRUE)
598                 return G_SUPPLICANT_SECURITY_PSK;
599         else if (g_str_equal(security, "rsn") == TRUE)
600                 return G_SUPPLICANT_SECURITY_PSK;
601         else if (g_str_equal(security, "ieee8021x") == TRUE)
602                 return G_SUPPLICANT_SECURITY_IEEE8021X;
603
604         return G_SUPPLICANT_SECURITY_UNKNOWN;
605 }
606
607 static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
608 {
609         const char *security, *passphrase, *agent_passphrase;
610
611         memset(ssid, 0, sizeof(*ssid));
612         ssid->mode = G_SUPPLICANT_MODE_INFRA;
613         ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
614                                                 &ssid->ssid_len);
615         ssid->scan_ssid = 1;
616         security = connman_network_get_string(network, "WiFi.Security");
617         ssid->security = network_security(security);
618         passphrase = connman_network_get_string(network,
619                                                 "WiFi.Passphrase");
620         if (passphrase == NULL || strlen(passphrase) == 0) {
621
622                 /* Use agent provided passphrase as a fallback */
623                 agent_passphrase = connman_network_get_string(network,
624                                                 "WiFi.AgentPassphrase");
625
626                 if (agent_passphrase == NULL || strlen(agent_passphrase) == 0)
627                         ssid->passphrase = NULL;
628                 else
629                         ssid->passphrase = agent_passphrase;
630         } else
631                 ssid->passphrase = passphrase;
632
633         ssid->eap = connman_network_get_string(network, "WiFi.EAP");
634
635         /*
636          * If our private key password is unset,
637          * we use the supplied passphrase. That is needed
638          * for PEAP where 2 passphrases (identity and client
639          * cert may have to be provided.
640          */
641         if (connman_network_get_string(network,
642                                         "WiFi.PrivateKeyPassphrase") == NULL)
643                 connman_network_set_string(network,
644                                                 "WiFi.PrivateKeyPassphrase",
645                                                 ssid->passphrase);
646         /* We must have an identity for both PEAP and TLS */
647         ssid->identity = connman_network_get_string(network, "WiFi.Identity");
648
649         /* Use agent provided identity as a fallback */
650         if (ssid->identity == NULL || strlen(ssid->identity) == 0)
651                 ssid->identity = connman_network_get_string(network,
652                                                         "WiFi.AgentIdentity");
653
654         ssid->ca_cert_path = connman_network_get_string(network,
655                                                         "WiFi.CACertFile");
656         ssid->client_cert_path = connman_network_get_string(network,
657                                                         "WiFi.ClientCertFile");
658         ssid->private_key_path = connman_network_get_string(network,
659                                                         "WiFi.PrivateKeyFile");
660         ssid->private_key_passphrase = connman_network_get_string(network,
661                                                 "WiFi.PrivateKeyPassphrase");
662         ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
663
664         ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS");
665         ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS");
666
667 }
668
669 static int network_connect(struct connman_network *network)
670 {
671         struct connman_device *device = connman_network_get_device(network);
672         struct wifi_data *wifi;
673         GSupplicantInterface *interface;
674         GSupplicantSSID *ssid;
675
676         DBG("network %p", network);
677
678         if (device == NULL)
679                 return -ENODEV;
680
681         wifi = connman_device_get_data(device);
682         if (wifi == NULL)
683                 return -ENODEV;
684
685         ssid = g_try_malloc0(sizeof(GSupplicantSSID));
686         if (ssid == NULL)
687                 return -ENOMEM;
688
689         interface = wifi->interface;
690
691         ssid_init(ssid, network);
692
693         if (wifi->disconnecting == TRUE)
694                 wifi->pending_network = network;
695         else {
696                 wifi->network = network;
697                 wifi->retries = 0;
698
699                 return g_supplicant_interface_connect(interface, ssid,
700                                                 connect_callback, network);
701         }
702
703         return -EINPROGRESS;
704 }
705
706 static void disconnect_callback(int result, GSupplicantInterface *interface,
707                                                                 void *user_data)
708 {
709         struct wifi_data *wifi = user_data;
710
711         if (wifi->network != NULL) {
712                 /*
713                  * if result < 0 supplican return an error because
714                  * the network is not current.
715                  * we wont receive G_SUPPLICANT_STATE_DISCONNECTED since it
716                  * failed, call connman_network_set_connected to report
717                  * disconnect is completed.
718                  */
719                 if (result < 0)
720                         connman_network_set_connected(wifi->network, FALSE);
721         }
722
723         wifi->network = NULL;
724
725         wifi->disconnecting = FALSE;
726
727         if (wifi->pending_network != NULL) {
728                 network_connect(wifi->pending_network);
729                 wifi->pending_network = NULL;
730         }
731
732 }
733
734 static int network_disconnect(struct connman_network *network)
735 {
736         struct connman_device *device = connman_network_get_device(network);
737         struct wifi_data *wifi;
738         int err;
739
740         DBG("network %p", network);
741
742         wifi = connman_device_get_data(device);
743         if (wifi == NULL || wifi->interface == NULL)
744                 return -ENODEV;
745
746         connman_network_set_associating(network, FALSE);
747
748         if (wifi->disconnecting == TRUE)
749                 return -EALREADY;
750
751         wifi->disconnecting = TRUE;
752
753         err = g_supplicant_interface_disconnect(wifi->interface,
754                                                 disconnect_callback, wifi);
755         if (err < 0)
756                 wifi->disconnecting = FALSE;
757
758         return err;
759 }
760
761 static struct connman_network_driver network_driver = {
762         .name           = "wifi",
763         .type           = CONNMAN_NETWORK_TYPE_WIFI,
764         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
765         .probe          = network_probe,
766         .remove         = network_remove,
767         .connect        = network_connect,
768         .disconnect     = network_disconnect,
769 };
770
771 static void interface_added(GSupplicantInterface *interface)
772 {
773         const char *ifname = g_supplicant_interface_get_ifname(interface);
774         const char *driver = g_supplicant_interface_get_driver(interface);
775         struct wifi_data *wifi;
776
777         wifi = g_supplicant_interface_get_data(interface);
778
779         /*
780          * We can get here with a NULL wifi pointer when
781          * the interface added signal is sent before the
782          * interface creation callback is called.
783          */
784         if (wifi == NULL)
785                 return;
786
787         DBG("ifname %s driver %s wifi %p tethering %d",
788                         ifname, driver, wifi, wifi->tethering);
789
790         if (wifi->device == NULL) {
791                 connman_error("WiFi device not set");
792                 return;
793         }
794
795         connman_device_set_powered(wifi->device, TRUE);
796
797         if (wifi->tethering == TRUE)
798                 return;
799 }
800
801 static connman_bool_t is_idle(struct wifi_data *wifi)
802 {
803         DBG("state %d", wifi->state);
804
805         switch (wifi->state) {
806         case G_SUPPLICANT_STATE_UNKNOWN:
807         case G_SUPPLICANT_STATE_DISCONNECTED:
808         case G_SUPPLICANT_STATE_INACTIVE:
809         case G_SUPPLICANT_STATE_SCANNING:
810                 return TRUE;
811
812         case G_SUPPLICANT_STATE_AUTHENTICATING:
813         case G_SUPPLICANT_STATE_ASSOCIATING:
814         case G_SUPPLICANT_STATE_ASSOCIATED:
815         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
816         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
817         case G_SUPPLICANT_STATE_COMPLETED:
818                 return FALSE;
819         }
820
821         return FALSE;
822 }
823
824 static connman_bool_t is_idle_wps(GSupplicantInterface *interface,
825                                                 struct wifi_data *wifi)
826 {
827         /* First, let's check if WPS processing did not went wrong */
828         if (g_supplicant_interface_get_wps_state(interface) ==
829                 G_SUPPLICANT_WPS_STATE_FAIL)
830                 return FALSE;
831
832         /* Unlike normal connection, being associated while processing wps
833          * actually means that we are idling. */
834         switch (wifi->state) {
835         case G_SUPPLICANT_STATE_UNKNOWN:
836         case G_SUPPLICANT_STATE_DISCONNECTED:
837         case G_SUPPLICANT_STATE_INACTIVE:
838         case G_SUPPLICANT_STATE_SCANNING:
839         case G_SUPPLICANT_STATE_ASSOCIATED:
840                 return TRUE;
841         case G_SUPPLICANT_STATE_AUTHENTICATING:
842         case G_SUPPLICANT_STATE_ASSOCIATING:
843         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
844         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
845         case G_SUPPLICANT_STATE_COMPLETED:
846                 return FALSE;
847         }
848
849         return FALSE;
850 }
851
852 static connman_bool_t handle_wps_completion(GSupplicantInterface *interface,
853                                         struct connman_network *network,
854                                         struct connman_device *device,
855                                         struct wifi_data *wifi)
856 {
857         connman_bool_t wps;
858
859         wps = connman_network_get_bool(network, "WiFi.UseWPS");
860         if (wps == TRUE) {
861                 const unsigned char *ssid, *wps_ssid;
862                 unsigned int ssid_len, wps_ssid_len;
863                 const char *wps_key;
864
865                 /* Checking if we got associated with requested
866                  * network */
867                 ssid = connman_network_get_blob(network, "WiFi.SSID",
868                                                 &ssid_len);
869
870                 wps_ssid = g_supplicant_interface_get_wps_ssid(
871                         interface, &wps_ssid_len);
872
873                 if (wps_ssid == NULL || wps_ssid_len != ssid_len ||
874                                 memcmp(ssid, wps_ssid, ssid_len) != 0) {
875                         connman_network_set_associating(network, FALSE);
876                         g_supplicant_interface_disconnect(wifi->interface,
877                                                 disconnect_callback, wifi);
878                         return FALSE;
879                 }
880
881                 wps_key = g_supplicant_interface_get_wps_key(interface);
882                 connman_network_set_string(network, "WiFi.Passphrase",
883                                         wps_key);
884
885                 connman_network_set_string(network, "WiFi.PinWPS", NULL);
886         }
887
888         return TRUE;
889 }
890
891 static connman_bool_t handle_4way_handshake_failure(GSupplicantInterface *interface,
892                                         struct connman_network *network,
893                                         struct wifi_data *wifi)
894 {
895         if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
896                 return FALSE;
897
898         wifi->retries++;
899
900         if (wifi->retries < MAXIMUM_RETRIES)
901                 return TRUE;
902
903         /* We disable the selected network, if not then
904          * wpa_supplicant will loop retrying */
905         if (g_supplicant_interface_enable_selected_network(interface,
906                                                                 FALSE) != 0)
907                 DBG("Could not disables selected network");
908
909         connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
910
911         return FALSE;
912 }
913
914 static void interface_state(GSupplicantInterface *interface)
915 {
916         struct connman_network *network;
917         struct connman_device *device;
918         struct wifi_data *wifi;
919         GSupplicantState state = g_supplicant_interface_get_state(interface);
920         connman_bool_t wps;
921
922         wifi = g_supplicant_interface_get_data(interface);
923
924         DBG("wifi %p interface state %d", wifi, state);
925
926         if (wifi == NULL)
927                 return;
928
929         network = wifi->network;
930         device = wifi->device;
931
932         if (device == NULL || network == NULL)
933                 return;
934
935         switch (state) {
936         case G_SUPPLICANT_STATE_SCANNING:
937                 break;
938
939         case G_SUPPLICANT_STATE_AUTHENTICATING:
940         case G_SUPPLICANT_STATE_ASSOCIATING:
941                 connman_network_set_associating(network, TRUE);
942                 break;
943
944         case G_SUPPLICANT_STATE_COMPLETED:
945                 if (handle_wps_completion(interface, network, device, wifi) ==
946                                                                         FALSE)
947                         break;
948
949                 /* reset scan trigger and schedule background scan */
950                 connman_device_schedule_scan(device);
951
952                 connman_network_set_connected(network, TRUE);
953                 break;
954
955         case G_SUPPLICANT_STATE_DISCONNECTED:
956                 /*
957                  * If we're in one of the idle modes, we have
958                  * not started association yet and thus setting
959                  * those ones to FALSE could cancel an association
960                  * in progress.
961                  */
962                 wps = connman_network_get_bool(network, "WiFi.UseWPS");
963                 if (wps == TRUE)
964                         if (is_idle_wps(interface, wifi) == TRUE)
965                                 break;
966
967                 if (is_idle(wifi))
968                         break;
969
970                 /* If previous state was 4way-handshake, then
971                  * it's either: psk was incorrect and thus we retry
972                  * or if we reach the maximum retries we declare the
973                  * psk as wrong */
974                 if (handle_4way_handshake_failure(interface,
975                                                 network, wifi) == TRUE)
976                         break;
977
978                 connman_network_set_associating(network, FALSE);
979                 connman_network_set_connected(network, FALSE);
980                 break;
981
982         case G_SUPPLICANT_STATE_INACTIVE:
983                 connman_network_set_associating(network, FALSE);
984                 break;
985
986         case G_SUPPLICANT_STATE_UNKNOWN:
987         case G_SUPPLICANT_STATE_ASSOCIATED:
988         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
989         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
990                 break;
991         }
992
993         wifi->state = state;
994
995         DBG("DONE");
996 }
997
998 static void interface_removed(GSupplicantInterface *interface)
999 {
1000         const char *ifname = g_supplicant_interface_get_ifname(interface);
1001         struct wifi_data *wifi;
1002
1003         DBG("ifname %s", ifname);
1004
1005         wifi = g_supplicant_interface_get_data(interface);
1006
1007         if (wifi != NULL && wifi->tethering == TRUE)
1008                 return;
1009
1010         if (wifi == NULL || wifi->device == NULL) {
1011                 connman_error("Wrong wifi pointer");
1012                 return;
1013         }
1014
1015         connman_device_set_powered(wifi->device, FALSE);
1016 }
1017
1018 static void scan_started(GSupplicantInterface *interface)
1019 {
1020         DBG("");
1021 }
1022
1023 static void scan_finished(GSupplicantInterface *interface)
1024 {
1025         DBG("");
1026 }
1027
1028 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
1029 {
1030         unsigned char strength;
1031
1032         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
1033         if (strength > 100)
1034                 strength = 100;
1035
1036         return strength;
1037 }
1038
1039 static void network_added(GSupplicantNetwork *supplicant_network)
1040 {
1041         struct connman_network *network;
1042         GSupplicantInterface *interface;
1043         struct wifi_data *wifi;
1044         const char *name, *identifier, *security, *group;
1045         const unsigned char *ssid;
1046         unsigned int ssid_len;
1047         connman_bool_t wps;
1048
1049         DBG("");
1050
1051         interface = g_supplicant_network_get_interface(supplicant_network);
1052         wifi = g_supplicant_interface_get_data(interface);
1053         name = g_supplicant_network_get_name(supplicant_network);
1054         identifier = g_supplicant_network_get_identifier(supplicant_network);
1055         security = g_supplicant_network_get_security(supplicant_network);
1056         group = g_supplicant_network_get_identifier(supplicant_network);
1057         wps = g_supplicant_network_get_wps(supplicant_network);
1058
1059         if (wifi == NULL)
1060                 return;
1061
1062         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
1063
1064         network = connman_device_get_network(wifi->device, identifier);
1065
1066         if (network == NULL) {
1067                 network = connman_network_create(identifier,
1068                                                 CONNMAN_NETWORK_TYPE_WIFI);
1069                 if (network == NULL)
1070                         return;
1071
1072                 connman_network_set_index(network, wifi->index);
1073
1074                 if (connman_device_add_network(wifi->device, network) < 0) {
1075                         connman_network_unref(network);
1076                         return;
1077                 }
1078
1079                 wifi->networks = g_slist_append(wifi->networks, network);
1080         }
1081
1082         if (name != NULL && name[0] != '\0')
1083                 connman_network_set_name(network, name);
1084
1085         connman_network_set_blob(network, "WiFi.SSID",
1086                                                 ssid, ssid_len);
1087         connman_network_set_string(network, "WiFi.Security", security);
1088         connman_network_set_strength(network,
1089                                 calculate_strength(supplicant_network));
1090         connman_network_set_bool(network, "WiFi.WPS", wps);
1091
1092         connman_network_set_frequency(network,
1093                         g_supplicant_network_get_frequency(supplicant_network));
1094
1095         connman_network_set_available(network, TRUE);
1096
1097         if (ssid != NULL)
1098                 connman_network_set_group(network, group);
1099 }
1100
1101 static void network_removed(GSupplicantNetwork *network)
1102 {
1103         GSupplicantInterface *interface;
1104         struct wifi_data *wifi;
1105         const char *name, *identifier;
1106         struct connman_network *connman_network;
1107
1108         interface = g_supplicant_network_get_interface(network);
1109         wifi = g_supplicant_interface_get_data(interface);
1110         identifier = g_supplicant_network_get_identifier(network);
1111         name = g_supplicant_network_get_name(network);
1112
1113         DBG("name %s", name);
1114
1115         if (wifi == NULL)
1116                 return;
1117
1118         connman_network = connman_device_get_network(wifi->device, identifier);
1119         if (connman_network == NULL)
1120                 return;
1121
1122         wifi->networks = g_slist_remove(wifi->networks, connman_network);
1123
1124         connman_device_remove_network(wifi->device, connman_network);
1125         connman_network_unref(connman_network);
1126 }
1127
1128 static void network_changed(GSupplicantNetwork *network, const char *property)
1129 {
1130         GSupplicantInterface *interface;
1131         struct wifi_data *wifi;
1132         const char *name, *identifier;
1133         struct connman_network *connman_network;
1134
1135         interface = g_supplicant_network_get_interface(network);
1136         wifi = g_supplicant_interface_get_data(interface);
1137         identifier = g_supplicant_network_get_identifier(network);
1138         name = g_supplicant_network_get_name(network);
1139
1140         DBG("name %s", name);
1141
1142         if (wifi == NULL)
1143                 return;
1144
1145         connman_network = connman_device_get_network(wifi->device, identifier);
1146         if (connman_network == NULL)
1147                 return;
1148
1149         if (g_str_equal(property, "Signal") == TRUE) {
1150                connman_network_set_strength(connman_network,
1151                                         calculate_strength(network));
1152                connman_network_update(connman_network);
1153         }
1154 }
1155
1156 static void debug(const char *str)
1157 {
1158         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
1159                 connman_debug("%s", str);
1160 }
1161
1162 static const GSupplicantCallbacks callbacks = {
1163         .system_ready           = system_ready,
1164         .system_killed          = system_killed,
1165         .interface_added        = interface_added,
1166         .interface_state        = interface_state,
1167         .interface_removed      = interface_removed,
1168         .scan_started           = scan_started,
1169         .scan_finished          = scan_finished,
1170         .network_added          = network_added,
1171         .network_removed        = network_removed,
1172         .network_changed        = network_changed,
1173         .debug                  = debug,
1174 };
1175
1176
1177 static int tech_probe(struct connman_technology *technology)
1178 {
1179         wifi_technology = technology;
1180
1181         return 0;
1182 }
1183
1184 static void tech_remove(struct connman_technology *technology)
1185 {
1186         wifi_technology = NULL;
1187 }
1188
1189 struct wifi_tethering_info {
1190         struct wifi_data *wifi;
1191         struct connman_technology *technology;
1192         char *ifname;
1193         GSupplicantSSID *ssid;
1194 };
1195
1196 static GSupplicantSSID *ssid_ap_init(const char *ssid, const char *passphrase)
1197 {
1198         GSupplicantSSID *ap;
1199
1200         ap = g_try_malloc0(sizeof(GSupplicantSSID));
1201         if (ap == NULL)
1202                 return NULL;
1203
1204         ap->mode = G_SUPPLICANT_MODE_MASTER;
1205         ap->ssid = ssid;
1206         ap->ssid_len = strlen(ssid);
1207         ap->scan_ssid = 0;
1208         ap->freq = 2412;
1209
1210         if (passphrase == NULL || strlen(passphrase) == 0) {
1211                 ap->security = G_SUPPLICANT_SECURITY_NONE;
1212                 ap->passphrase = NULL;
1213         } else {
1214                ap->security = G_SUPPLICANT_SECURITY_PSK;
1215                ap->protocol = G_SUPPLICANT_PROTO_RSN;
1216                ap->pairwise_cipher = G_SUPPLICANT_PAIRWISE_CCMP;
1217                ap->group_cipher = G_SUPPLICANT_GROUP_CCMP;
1218                ap->passphrase = passphrase;
1219         }
1220
1221         return ap;
1222 }
1223
1224 static void ap_start_callback(int result, GSupplicantInterface *interface,
1225                                                         void *user_data)
1226 {
1227         struct wifi_tethering_info *info = user_data;
1228
1229         DBG("result %d index %d bridge %s",
1230                 result, info->wifi->index, info->wifi->bridge);
1231
1232         if (result < 0) {
1233                 connman_inet_remove_from_bridge(info->wifi->index,
1234                                                         info->wifi->bridge);
1235                 connman_technology_tethering_notify(info->technology, FALSE);
1236         }
1237
1238         g_free(info->ifname);
1239         g_free(info);
1240 }
1241
1242 static void ap_create_callback(int result,
1243                                 GSupplicantInterface *interface,
1244                                         void *user_data)
1245 {
1246         struct wifi_tethering_info *info = user_data;
1247
1248         DBG("result %d ifname %s", result,
1249                                 g_supplicant_interface_get_ifname(interface));
1250
1251         if (result < 0) {
1252                 connman_inet_remove_from_bridge(info->wifi->index,
1253                                                         info->wifi->bridge);
1254                 connman_technology_tethering_notify(info->technology, FALSE);
1255
1256                 g_free(info->ifname);
1257                 g_free(info);
1258                 return;
1259         }
1260
1261         info->wifi->interface = interface;
1262         g_supplicant_interface_set_data(interface, info->wifi);
1263
1264         if (g_supplicant_interface_set_apscan(interface, 2) < 0)
1265                 connman_error("Failed to set interface ap_scan property");
1266
1267         g_supplicant_interface_connect(interface, info->ssid,
1268                                                 ap_start_callback, info);
1269 }
1270
1271 static void sta_remove_callback(int result,
1272                                 GSupplicantInterface *interface,
1273                                         void *user_data)
1274 {
1275         struct wifi_tethering_info *info = user_data;
1276         const char *driver = connman_option_get_string("wifi");
1277
1278         DBG("ifname %s result %d ", info->ifname, result);
1279
1280         if (result < 0) {
1281                 info->wifi->tethering = TRUE;
1282
1283                 g_free(info->ifname);
1284                 g_free(info);
1285                 return;
1286         }
1287
1288         info->wifi->interface = NULL;
1289
1290         connman_technology_tethering_notify(info->technology, TRUE);
1291
1292         g_supplicant_interface_create(info->ifname, driver, info->wifi->bridge,
1293                                                 ap_create_callback,
1294                                                         info);
1295 }
1296
1297 static int tech_set_tethering(struct connman_technology *technology,
1298                                 const char *identifier, const char *passphrase,
1299                                 const char *bridge, connman_bool_t enabled)
1300 {
1301         GList *list;
1302         GSupplicantInterface *interface;
1303         struct wifi_data *wifi;
1304         struct wifi_tethering_info *info;
1305         const char *ifname;
1306         unsigned int mode;
1307         int err;
1308
1309         DBG("");
1310
1311         if (enabled == FALSE) {
1312                 for (list = iface_list; list; list = list->next) {
1313                         wifi = list->data;
1314
1315                         if (wifi->tethering == TRUE) {
1316                                 wifi->tethering = FALSE;
1317
1318                                 connman_inet_remove_from_bridge(wifi->index,
1319                                                                         bridge);
1320                                 wifi->bridged = FALSE;
1321                         }
1322                 }
1323
1324                 connman_technology_tethering_notify(technology, FALSE);
1325
1326                 return 0;
1327         }
1328
1329         for (list = iface_list; list; list = list->next) {
1330                 wifi = list->data;
1331
1332                 interface = wifi->interface;
1333
1334                 if (interface == NULL)
1335                         continue;
1336
1337                 ifname = g_supplicant_interface_get_ifname(wifi->interface);
1338
1339                 mode = g_supplicant_interface_get_mode(interface);
1340                 if ((mode & G_SUPPLICANT_CAPABILITY_MODE_AP) == 0) {
1341                         DBG("%s does not support AP mode", ifname);
1342                         continue;
1343                 }
1344
1345                 info = g_try_malloc0(sizeof(struct wifi_tethering_info));
1346                 if (info == NULL)
1347                         return -ENOMEM;
1348
1349                 info->wifi = wifi;
1350                 info->technology = technology;
1351                 info->wifi->bridge = bridge;
1352                 info->ssid = ssid_ap_init(identifier, passphrase);
1353                 if (info->ssid == NULL) {
1354                         g_free(info);
1355                         continue;
1356                 }
1357                 info->ifname = g_strdup(ifname);
1358                 if (info->ifname == NULL) {
1359                         g_free(info);
1360                         continue;
1361                 }
1362
1363                 info->wifi->tethering = TRUE;
1364
1365                 err = g_supplicant_interface_remove(interface,
1366                                                 sta_remove_callback,
1367                                                         info);
1368                 if (err == 0)
1369                         return err;
1370         }
1371
1372         return -EOPNOTSUPP;
1373 }
1374
1375 static void regdom_callback(void *user_data)
1376 {
1377         char *alpha2 = user_data;
1378
1379         DBG("");
1380
1381         if (wifi_technology == NULL)
1382                 return;
1383
1384         connman_technology_regdom_notify(wifi_technology, alpha2);
1385 }
1386
1387 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
1388 {
1389         return g_supplicant_set_country(alpha2, regdom_callback, alpha2);
1390 }
1391
1392 static struct connman_technology_driver tech_driver = {
1393         .name           = "wifi",
1394         .type           = CONNMAN_SERVICE_TYPE_WIFI,
1395         .probe          = tech_probe,
1396         .remove         = tech_remove,
1397         .set_tethering  = tech_set_tethering,
1398         .set_regdom     = tech_set_regdom,
1399 };
1400
1401 static int wifi_init(void)
1402 {
1403         int err;
1404
1405         err = connman_network_driver_register(&network_driver);
1406         if (err < 0)
1407                 return err;
1408
1409         err = g_supplicant_register(&callbacks);
1410         if (err < 0) {
1411                 connman_network_driver_unregister(&network_driver);
1412                 return err;
1413         }
1414
1415         err = connman_technology_driver_register(&tech_driver);
1416         if (err < 0) {
1417                 g_supplicant_unregister(&callbacks);
1418                 connman_network_driver_unregister(&network_driver);
1419                 return err;
1420         }
1421
1422         return 0;
1423 }
1424
1425 static void wifi_exit(void)
1426 {
1427         DBG();
1428
1429         connman_technology_driver_unregister(&tech_driver);
1430
1431         g_supplicant_unregister(&callbacks);
1432
1433         connman_network_driver_unregister(&network_driver);
1434 }
1435
1436 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
1437                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)