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