wifi: Use CONNMAN_SUPPLICANT_DEBUG for debugging
[framework/connectivity/connman.git] / plugins / wifi.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
32 #include <linux/if_arp.h>
33 #include <linux/wireless.h>
34 #include <net/ethernet.h>
35
36 #ifndef IFF_LOWER_UP
37 #define IFF_LOWER_UP    0x10000
38 #endif
39
40 #include <dbus/dbus.h>
41 #include <glib.h>
42
43 #define CONNMAN_API_SUBJECT_TO_CHANGE
44 #include <connman/plugin.h>
45 #include <connman/inet.h>
46 #include <connman/device.h>
47 #include <connman/rtnl.h>
48 #include <connman/technology.h>
49 #include <connman/log.h>
50 #include <connman/option.h>
51
52 #include <gsupplicant/gsupplicant.h>
53
54 #define CLEANUP_TIMEOUT   8     /* in seconds */
55 #define INACTIVE_TIMEOUT  12    /* in seconds */
56
57 struct connman_technology *wifi_technology = NULL;
58
59 struct wifi_data {
60         char *identifier;
61         struct connman_device *device;
62         struct connman_network *network;
63         GSupplicantInterface *interface;
64         connman_bool_t connected;
65         int index;
66         unsigned flags;
67         unsigned int watch;
68 };
69
70 static int get_bssid(struct connman_device *device,
71                                 unsigned char *bssid, unsigned int *bssid_len)
72 {
73         struct iwreq wrq;
74         char *ifname;
75         int ifindex;
76         int fd, err;
77
78         ifindex = connman_device_get_index(device);
79         if (ifindex < 0)
80                 return -EINVAL;
81
82         ifname = connman_inet_ifname(ifindex);
83         if (ifname == NULL)
84                 return -EINVAL;
85
86         fd = socket(PF_INET, SOCK_DGRAM, 0);
87         if (fd < 0) {
88                 g_free(ifname);
89                 return -EINVAL;
90         }
91
92         memset(&wrq, 0, sizeof(wrq));
93         strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
94
95         err = ioctl(fd, SIOCGIWAP, &wrq);
96
97         g_free(ifname);
98         close(fd);
99
100         if (err < 0)
101                 return -EIO;
102
103         memcpy(bssid, wrq.u.ap_addr.sa_data, ETH_ALEN);
104         *bssid_len = ETH_ALEN;
105
106         return 0;
107 }
108
109 static void wifi_newlink(unsigned flags, unsigned change, void *user_data)
110 {
111         struct connman_device *device = user_data;
112         struct wifi_data *wifi = connman_device_get_data(device);
113
114         DBG("index %d flags %d change %d", wifi->index, flags, change);
115
116         if (!change)
117                 return;
118
119         if ((wifi->flags & IFF_UP) != (flags & IFF_UP)) {
120                 if (flags & IFF_UP)
121                         DBG("interface up");
122                 else
123                         DBG("interface down");
124         }
125
126         if ((wifi->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
127                 if (flags & IFF_LOWER_UP)
128                         DBG("carrier on");
129                 else
130                         DBG("carrier off");
131         }
132
133         wifi->flags = flags;
134 }
135
136 static int wifi_probe(struct connman_device *device)
137 {
138         struct wifi_data *wifi;
139
140         DBG("device %p", device);
141
142         wifi = g_try_new0(struct wifi_data, 1);
143         if (wifi == NULL)
144                 return -ENOMEM;
145
146         wifi->connected = FALSE;
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         return 0;
158 }
159
160 static void wifi_remove(struct connman_device *device)
161 {
162         struct wifi_data *wifi = connman_device_get_data(device);
163
164         DBG("device %p", device);
165
166         connman_device_set_data(device, NULL);
167         connman_device_unref(wifi->device);
168         connman_rtnl_remove_watch(wifi->watch);
169
170         g_supplicant_interface_set_data(wifi->interface, NULL);
171
172         g_free(wifi->identifier);
173         g_free(wifi);
174 }
175
176 static void interface_create_callback(int result,
177                                         GSupplicantInterface *interface,
178                                                         void *user_data)
179 {
180         struct wifi_data *wifi = user_data;
181
182         DBG("result %d ifname %s", result,
183                                 g_supplicant_interface_get_ifname(interface));
184
185         if (result < 0)
186                 return;
187
188         wifi->interface = interface;
189         g_supplicant_interface_set_data(interface, wifi);
190 }
191
192 static void interface_remove_callback(int result,
193                                         GSupplicantInterface *interface,
194                                                         void *user_data)
195 {
196         struct wifi_data *wifi = user_data;
197
198         DBG("result %d", result);
199
200         if (result < 0)
201                 return;
202
203         wifi->interface = NULL;
204 }
205
206
207 static int wifi_enable(struct connman_device *device)
208 {
209         struct wifi_data *wifi = connman_device_get_data(device);
210         const char *interface = connman_device_get_string(device, "Interface");
211         const char *driver = connman_option_get_string("wifi");
212
213         DBG("device %p %p", device, wifi);
214
215         return g_supplicant_interface_create(interface, driver,
216                                                 interface_create_callback,
217                                                         wifi);
218 }
219
220 static int wifi_disable(struct connman_device *device)
221 {
222         struct wifi_data *wifi = connman_device_get_data(device);
223
224         DBG("device %p", device);
225
226         wifi->connected = FALSE;
227
228         return g_supplicant_interface_remove(wifi->interface,
229                                                 interface_remove_callback,
230                                                         wifi);
231 }
232
233 static void scan_callback(int result, GSupplicantInterface *interface,
234                                                 void *user_data)
235 {
236         struct connman_device *device = user_data;
237
238         DBG("result %d", result);
239
240         connman_device_set_scanning(device, FALSE);
241 }
242
243 static int wifi_scan(struct connman_device *device)
244 {
245         struct wifi_data *wifi = connman_device_get_data(device);
246
247         DBG("device %p %p", device, wifi->interface);
248
249         return g_supplicant_interface_scan(wifi->interface, scan_callback,
250                                                                 device);
251 }
252
253 static struct connman_device_driver wifi_ng_driver = {
254         .name           = "wifi",
255         .type           = CONNMAN_DEVICE_TYPE_WIFI,
256         .priority       = CONNMAN_DEVICE_PRIORITY_LOW,
257         .probe          = wifi_probe,
258         .remove         = wifi_remove,
259         .enable         = wifi_enable,
260         .disable        = wifi_disable,
261         .scan           = wifi_scan,
262 };
263
264 static void system_ready(void)
265 {
266         DBG("");
267
268         if (connman_device_driver_register(&wifi_ng_driver) < 0)
269                 connman_error("Failed to register WiFi driver");
270 }
271
272 static void system_killed(void)
273 {
274         DBG("");
275
276         connman_device_driver_unregister(&wifi_ng_driver);
277 }
278
279 static void interface_added(GSupplicantInterface *interface)
280 {
281         const char *ifname = g_supplicant_interface_get_ifname(interface);
282         const char *driver = g_supplicant_interface_get_driver(interface);
283         struct wifi_data *wifi;
284
285         wifi = g_supplicant_interface_get_data(interface);
286
287         DBG("ifname %s driver %s wifi %p", ifname, driver, wifi);
288
289         if (wifi == NULL || wifi->device == NULL) {
290                 connman_error("Wrong wifi pointer");
291                 return;
292         }
293
294         connman_device_set_powered(wifi->device, TRUE);
295         wifi_scan(wifi->device);
296 }
297
298 static void interface_state(GSupplicantInterface *interface)
299 {
300         struct connman_network *network;
301         struct connman_device *device;
302         struct wifi_data *wifi;
303         GSupplicantState state = g_supplicant_interface_get_state(interface);
304         unsigned char bssid[ETH_ALEN];
305         unsigned int bssid_len;
306
307         wifi = g_supplicant_interface_get_data(interface);
308
309         DBG("wifi %p interface state %d", wifi, state);
310
311         if (wifi == NULL)
312                 return;
313
314         network = wifi->network;
315         device = wifi->device;
316
317         if (device == NULL || network == NULL)
318                 return;
319
320         switch (state) {
321         case G_SUPPLICANT_STATE_SCANNING:
322                 connman_device_set_scanning(device, TRUE);
323                 break;
324
325         case G_SUPPLICANT_STATE_AUTHENTICATING:
326         case G_SUPPLICANT_STATE_ASSOCIATING:
327                 connman_network_set_associating(network, TRUE);
328                 break;
329
330         case G_SUPPLICANT_STATE_COMPLETED:
331                 /* reset scan trigger and schedule background scan */
332                 connman_device_schedule_scan(device);
333
334                 if (get_bssid(device, bssid, &bssid_len) == 0)
335                         connman_network_set_address(network,
336                                                         bssid, bssid_len);
337                 connman_network_set_connected(network, TRUE);
338                 break;
339
340         case G_SUPPLICANT_STATE_DISCONNECTED:
341                 connman_network_set_associating(network, FALSE);
342                 connman_network_set_connected(network, FALSE);
343                 break;
344
345         case G_SUPPLICANT_STATE_INACTIVE:
346                 connman_network_set_associating(network, FALSE);
347                 break;
348
349         case G_SUPPLICANT_STATE_UNKNOWN:
350         case G_SUPPLICANT_STATE_ASSOCIATED:
351         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
352         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
353                 break;
354         }
355
356         DBG("DONE");
357 }
358
359 static void interface_removed(GSupplicantInterface *interface)
360 {
361         const char *ifname = g_supplicant_interface_get_ifname(interface);
362         struct wifi_data *wifi;
363
364         DBG("ifname %s", ifname);
365
366         wifi = g_supplicant_interface_get_data(interface);
367
368         if (wifi == NULL || wifi->device == NULL) {
369                 connman_error("Wrong wifi pointer");
370                 return;
371         }
372
373         connman_device_set_powered(wifi->device, FALSE);
374 }
375
376 static void scan_started(GSupplicantInterface *interface)
377 {
378         struct wifi_data *wifi;
379
380         DBG("");
381
382         wifi = g_supplicant_interface_get_data(interface);
383
384         if (wifi == NULL)
385                 return;
386
387         if (wifi->device)
388                 connman_device_set_scanning(wifi->device, TRUE);
389 }
390
391 static void scan_finished(GSupplicantInterface *interface)
392 {
393         struct wifi_data *wifi;
394
395         DBG("");
396
397         wifi = g_supplicant_interface_get_data(interface);
398
399         if (wifi == NULL)
400                 return;
401 }
402
403 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
404 {
405         unsigned char strength;
406
407         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
408         if (strength > 100)
409                 strength = 100;
410
411         return strength;
412 }
413
414 static void network_added(GSupplicantNetwork *supplicant_network)
415 {
416         struct connman_network *network;
417         GSupplicantInterface *interface;
418         struct wifi_data *wifi;
419         const char *name, *identifier, *mode, *security, *group;
420         const unsigned char *ssid;
421         unsigned int ssid_len;
422
423         DBG("");
424
425         interface = g_supplicant_network_get_interface(supplicant_network);
426         wifi = g_supplicant_interface_get_data(interface);
427         name = g_supplicant_network_get_name(supplicant_network);
428         identifier = g_supplicant_network_get_identifier(supplicant_network);
429         mode = g_supplicant_network_get_mode(supplicant_network);
430         security = g_supplicant_network_get_security(supplicant_network);
431         group = g_supplicant_network_get_identifier(supplicant_network);
432
433         if (wifi == NULL)
434                 return;
435
436         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
437
438         network = connman_device_get_network(wifi->device, identifier);
439
440         if (network == NULL) {
441                 network = connman_network_create(identifier,
442                                                 CONNMAN_NETWORK_TYPE_WIFI);
443                 if (network == NULL)
444                         return;
445
446                 connman_network_set_index(network, wifi->index);
447
448                 if (connman_device_add_network(wifi->device, network) < 0) {
449                         connman_network_unref(network);
450                         return;
451                 }
452         }
453
454         if (name != NULL && name[0] != '\0')
455                 connman_network_set_name(network, name);
456
457         connman_network_set_blob(network, "WiFi.SSID",
458                                                 ssid, ssid_len);
459         connman_network_set_string(network, "WiFi.Mode", mode);
460         connman_network_set_string(network, "WiFi.Security", security);
461         connman_network_set_strength(network,
462                                 calculate_strength(supplicant_network));
463
464         connman_network_set_available(network, TRUE);
465
466         if (ssid != NULL)
467                 connman_network_set_group(network, group);
468 }
469
470 static void network_removed(GSupplicantNetwork *network)
471 {
472         const char *name = g_supplicant_network_get_name(network);
473
474         DBG("* name %s", name);
475 }
476
477 static void debug(const char *str)
478 {
479         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
480                 connman_debug("%s", str);
481 }
482
483 static const GSupplicantCallbacks callbacks = {
484         .system_ready           = system_ready,
485         .system_killed          = system_killed,
486         .interface_added        = interface_added,
487         .interface_state        = interface_state,
488         .interface_removed      = interface_removed,
489         .scan_started           = scan_started,
490         .scan_finished          = scan_finished,
491         .network_added          = network_added,
492         .network_removed        = network_removed,
493         .debug                  = debug,
494 };
495
496
497 static int network_probe(struct connman_network *network)
498 {
499         DBG("network %p", network);
500
501         return 0;
502 }
503
504 static void network_remove(struct connman_network *network)
505 {
506         DBG("network %p", network);
507 }
508
509 static void connect_callback(int result, GSupplicantInterface *interface,
510                                                         void *user_data)
511 {
512         connman_error("%s", __func__);
513 }
514
515 static void disconnect_callback(int result, GSupplicantInterface *interface,
516                                                         void *user_data)
517 {
518         struct wifi_data *wifi = user_data;
519
520         if (result < 0) {
521                 connman_error("%s", __func__);
522                 return;
523         }
524
525         connman_network_unref(wifi->network);
526
527         wifi->network = NULL;
528 }
529
530
531 static GSupplicantSecurity network_security(const char *security)
532 {
533         if (g_str_equal(security, "none") == TRUE)
534                 return G_SUPPLICANT_SECURITY_NONE;
535         else if (g_str_equal(security, "wep") == TRUE)
536                 return G_SUPPLICANT_SECURITY_WEP;
537         else if (g_str_equal(security, "psk") == TRUE)
538                 return G_SUPPLICANT_SECURITY_PSK;
539         else if (g_str_equal(security, "wpa") == TRUE)
540                 return G_SUPPLICANT_SECURITY_PSK;
541         else if (g_str_equal(security, "rsn") == TRUE)
542                 return G_SUPPLICANT_SECURITY_PSK;
543         else if (g_str_equal(security, "ieee8021x") == TRUE)
544                 return G_SUPPLICANT_SECURITY_IEEE8021X;
545
546         return G_SUPPLICANT_SECURITY_UNKNOWN;
547 }
548
549 static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
550 {
551         const char *security;
552
553         memset(ssid, 0, sizeof(*ssid));
554         ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
555                                                 &ssid->ssid_len);
556         security = connman_network_get_string(network, "WiFi.Security");
557         ssid->security = network_security(security);
558         ssid->passphrase = connman_network_get_string(network,
559                                                         "WiFi.Passphrase");
560         ssid->eap = connman_network_get_string(network, "WiFi.EAP");
561
562         /*
563          * If our private key password is unset,
564          * we use the supplied passphrase. That is needed
565          * for PEAP where 2 passphrases (identity and client
566          * cert may have to be provided.
567          */
568         if (connman_network_get_string(network,
569                                         "WiFi.PrivateKeyPassphrase") == NULL)
570                 connman_network_set_string(network,
571                                                 "WiFi.PrivateKeyPassphrase",
572                                                 ssid->passphrase);
573         /* We must have an identity for both PEAP and TLS */
574         ssid->identity = connman_network_get_string(network, "WiFi.Identity");
575         ssid->ca_cert_path = connman_network_get_string(network,
576                                                         "WiFi.CACertFile");
577         ssid->client_cert_path = connman_network_get_string(network,
578                                                         "WiFi.ClientCertFile");
579         ssid->private_key_path = connman_network_get_string(network,
580                                                         "WiFi.PrivateKeyFile");
581         ssid->private_key_passphrase = connman_network_get_string(network,
582                                                 "WiFi.PrivateKeyPassphrase");
583         ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
584
585 }
586
587 static int network_connect(struct connman_network *network)
588 {
589         struct connman_device *device = connman_network_get_device(network);
590         struct wifi_data *wifi;
591         GSupplicantInterface *interface;
592         GSupplicantSSID ssid;
593
594         DBG("network %p", network);
595
596         if (device == NULL)
597                 return -ENODEV;
598
599         wifi = connman_device_get_data(device);
600         if (wifi == NULL)
601                 return -ENODEV;
602
603         interface = wifi->interface;
604
605         ssid_init(&ssid, network);
606
607         wifi->network = connman_network_ref(network);
608
609         return g_supplicant_interface_connect(interface, &ssid,
610                                                 connect_callback, NULL);
611 }
612
613 static int network_disconnect(struct connman_network *network)
614 {
615         struct connman_device *device = connman_network_get_device(network);
616         struct wifi_data *wifi;
617
618         DBG("network %p", network);
619
620         wifi = connman_device_get_data(device);
621         if (wifi == NULL || wifi->interface == NULL)
622                 return -ENODEV;
623
624         connman_network_set_associating(network, FALSE);
625
626         return g_supplicant_interface_disconnect(wifi->interface,
627                                                 disconnect_callback, wifi);
628 }
629
630 static struct connman_network_driver network_driver = {
631         .name           = "wifi",
632         .type           = CONNMAN_NETWORK_TYPE_WIFI,
633         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
634         .probe          = network_probe,
635         .remove         = network_remove,
636         .connect        = network_connect,
637         .disconnect     = network_disconnect,
638 };
639
640 static int tech_probe(struct connman_technology *technology)
641 {
642         wifi_technology = technology;
643
644         return 0;
645 }
646
647 static void tech_remove(struct connman_technology *technology)
648 {
649         wifi_technology = NULL;
650 }
651
652 static void regdom_callback(void *user_data)
653 {
654         char *alpha2 = user_data;
655
656         DBG("");
657
658         if (wifi_technology == NULL)
659                 return;
660
661         connman_technology_regdom_notify(wifi_technology, alpha2);
662 }
663
664 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
665 {
666         return g_supplicant_set_country(alpha2, regdom_callback, alpha2);
667 }
668
669 static struct connman_technology_driver tech_driver = {
670         .name           = "wifi",
671         .type           = CONNMAN_SERVICE_TYPE_WIFI,
672         .probe          = tech_probe,
673         .remove         = tech_remove,
674         .set_regdom     = tech_set_regdom,
675 };
676
677 static int wifi_init(void)
678 {
679         int err;
680
681         err = connman_network_driver_register(&network_driver);
682         if (err < 0)
683                 return err;
684
685         err = g_supplicant_register(&callbacks);
686         if (err < 0) {
687                 connman_network_driver_unregister(&network_driver);
688                 return err;
689         }
690
691         err = connman_technology_driver_register(&tech_driver);
692         if (err < 0) {
693                 g_supplicant_unregister(&callbacks);
694                 connman_network_driver_unregister(&network_driver);
695                 return err;
696         }
697
698         return 0;
699 }
700
701 static void wifi_exit(void)
702 {
703         DBG();
704
705         connman_technology_driver_unregister(&tech_driver);
706
707         g_supplicant_unregister(&callbacks);
708
709         connman_network_driver_unregister(&network_driver);
710 }
711
712 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
713                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)