wifi: Remove misleading error string
[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         /*
288          * We can get here with a NULL wifi pointer when
289          * the interface added signal is sent before the
290          * interface creation callback is called.
291          */
292         if (wifi == NULL)
293                 return;
294
295         DBG("ifname %s driver %s wifi %p", ifname, driver, wifi);
296
297         if (wifi->device == NULL) {
298                 connman_error("WiFi device not set");
299                 return;
300         }
301
302         connman_device_set_powered(wifi->device, TRUE);
303         wifi_scan(wifi->device);
304 }
305
306 static void interface_state(GSupplicantInterface *interface)
307 {
308         struct connman_network *network;
309         struct connman_device *device;
310         struct wifi_data *wifi;
311         GSupplicantState state = g_supplicant_interface_get_state(interface);
312         unsigned char bssid[ETH_ALEN];
313         unsigned int bssid_len;
314
315         wifi = g_supplicant_interface_get_data(interface);
316
317         DBG("wifi %p interface state %d", wifi, state);
318
319         if (wifi == NULL)
320                 return;
321
322         network = wifi->network;
323         device = wifi->device;
324
325         if (device == NULL || network == NULL)
326                 return;
327
328         switch (state) {
329         case G_SUPPLICANT_STATE_SCANNING:
330                 connman_device_set_scanning(device, TRUE);
331                 break;
332
333         case G_SUPPLICANT_STATE_AUTHENTICATING:
334         case G_SUPPLICANT_STATE_ASSOCIATING:
335                 connman_network_set_associating(network, TRUE);
336                 break;
337
338         case G_SUPPLICANT_STATE_COMPLETED:
339                 /* reset scan trigger and schedule background scan */
340                 connman_device_schedule_scan(device);
341
342                 if (get_bssid(device, bssid, &bssid_len) == 0)
343                         connman_network_set_address(network,
344                                                         bssid, bssid_len);
345                 connman_network_set_connected(network, TRUE);
346                 break;
347
348         case G_SUPPLICANT_STATE_DISCONNECTED:
349                 connman_network_set_associating(network, FALSE);
350                 connman_network_set_connected(network, FALSE);
351                 break;
352
353         case G_SUPPLICANT_STATE_INACTIVE:
354                 connman_network_set_associating(network, FALSE);
355                 break;
356
357         case G_SUPPLICANT_STATE_UNKNOWN:
358         case G_SUPPLICANT_STATE_ASSOCIATED:
359         case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
360         case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
361                 break;
362         }
363
364         DBG("DONE");
365 }
366
367 static void interface_removed(GSupplicantInterface *interface)
368 {
369         const char *ifname = g_supplicant_interface_get_ifname(interface);
370         struct wifi_data *wifi;
371
372         DBG("ifname %s", ifname);
373
374         wifi = g_supplicant_interface_get_data(interface);
375
376         if (wifi == NULL || wifi->device == NULL) {
377                 connman_error("Wrong wifi pointer");
378                 return;
379         }
380
381         connman_device_set_powered(wifi->device, FALSE);
382 }
383
384 static void scan_started(GSupplicantInterface *interface)
385 {
386         struct wifi_data *wifi;
387
388         DBG("");
389
390         wifi = g_supplicant_interface_get_data(interface);
391
392         if (wifi == NULL)
393                 return;
394
395         if (wifi->device)
396                 connman_device_set_scanning(wifi->device, TRUE);
397 }
398
399 static void scan_finished(GSupplicantInterface *interface)
400 {
401         struct wifi_data *wifi;
402
403         DBG("");
404
405         wifi = g_supplicant_interface_get_data(interface);
406
407         if (wifi == NULL)
408                 return;
409 }
410
411 static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
412 {
413         unsigned char strength;
414
415         strength = 120 + g_supplicant_network_get_signal(supplicant_network);
416         if (strength > 100)
417                 strength = 100;
418
419         return strength;
420 }
421
422 static void network_added(GSupplicantNetwork *supplicant_network)
423 {
424         struct connman_network *network;
425         GSupplicantInterface *interface;
426         struct wifi_data *wifi;
427         const char *name, *identifier, *mode, *security, *group;
428         const unsigned char *ssid;
429         unsigned int ssid_len;
430
431         DBG("");
432
433         interface = g_supplicant_network_get_interface(supplicant_network);
434         wifi = g_supplicant_interface_get_data(interface);
435         name = g_supplicant_network_get_name(supplicant_network);
436         identifier = g_supplicant_network_get_identifier(supplicant_network);
437         mode = g_supplicant_network_get_mode(supplicant_network);
438         security = g_supplicant_network_get_security(supplicant_network);
439         group = g_supplicant_network_get_identifier(supplicant_network);
440
441         if (wifi == NULL)
442                 return;
443
444         ssid = g_supplicant_network_get_ssid(supplicant_network, &ssid_len);
445
446         network = connman_device_get_network(wifi->device, identifier);
447
448         if (network == NULL) {
449                 network = connman_network_create(identifier,
450                                                 CONNMAN_NETWORK_TYPE_WIFI);
451                 if (network == NULL)
452                         return;
453
454                 connman_network_set_index(network, wifi->index);
455
456                 if (connman_device_add_network(wifi->device, network) < 0) {
457                         connman_network_unref(network);
458                         return;
459                 }
460         }
461
462         if (name != NULL && name[0] != '\0')
463                 connman_network_set_name(network, name);
464
465         connman_network_set_blob(network, "WiFi.SSID",
466                                                 ssid, ssid_len);
467         connman_network_set_string(network, "WiFi.Mode", mode);
468         connman_network_set_string(network, "WiFi.Security", security);
469         connman_network_set_strength(network,
470                                 calculate_strength(supplicant_network));
471
472         connman_network_set_available(network, TRUE);
473
474         if (ssid != NULL)
475                 connman_network_set_group(network, group);
476 }
477
478 static void network_removed(GSupplicantNetwork *network)
479 {
480         const char *name = g_supplicant_network_get_name(network);
481
482         DBG("* name %s", name);
483 }
484
485 static void debug(const char *str)
486 {
487         if (getenv("CONNMAN_SUPPLICANT_DEBUG"))
488                 connman_debug("%s", str);
489 }
490
491 static const GSupplicantCallbacks callbacks = {
492         .system_ready           = system_ready,
493         .system_killed          = system_killed,
494         .interface_added        = interface_added,
495         .interface_state        = interface_state,
496         .interface_removed      = interface_removed,
497         .scan_started           = scan_started,
498         .scan_finished          = scan_finished,
499         .network_added          = network_added,
500         .network_removed        = network_removed,
501         .debug                  = debug,
502 };
503
504
505 static int network_probe(struct connman_network *network)
506 {
507         DBG("network %p", network);
508
509         return 0;
510 }
511
512 static void network_remove(struct connman_network *network)
513 {
514         DBG("network %p", network);
515 }
516
517 static void connect_callback(int result, GSupplicantInterface *interface,
518                                                         void *user_data)
519 {
520         connman_error("%s", __func__);
521 }
522
523 static void disconnect_callback(int result, GSupplicantInterface *interface,
524                                                         void *user_data)
525 {
526         struct wifi_data *wifi = user_data;
527
528         if (result < 0) {
529                 connman_error("%s", __func__);
530                 return;
531         }
532
533         connman_network_unref(wifi->network);
534
535         wifi->network = NULL;
536 }
537
538
539 static GSupplicantSecurity network_security(const char *security)
540 {
541         if (g_str_equal(security, "none") == TRUE)
542                 return G_SUPPLICANT_SECURITY_NONE;
543         else if (g_str_equal(security, "wep") == TRUE)
544                 return G_SUPPLICANT_SECURITY_WEP;
545         else if (g_str_equal(security, "psk") == TRUE)
546                 return G_SUPPLICANT_SECURITY_PSK;
547         else if (g_str_equal(security, "wpa") == TRUE)
548                 return G_SUPPLICANT_SECURITY_PSK;
549         else if (g_str_equal(security, "rsn") == TRUE)
550                 return G_SUPPLICANT_SECURITY_PSK;
551         else if (g_str_equal(security, "ieee8021x") == TRUE)
552                 return G_SUPPLICANT_SECURITY_IEEE8021X;
553
554         return G_SUPPLICANT_SECURITY_UNKNOWN;
555 }
556
557 static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network)
558 {
559         const char *security;
560
561         memset(ssid, 0, sizeof(*ssid));
562         ssid->ssid = connman_network_get_blob(network, "WiFi.SSID",
563                                                 &ssid->ssid_len);
564         security = connman_network_get_string(network, "WiFi.Security");
565         ssid->security = network_security(security);
566         ssid->passphrase = connman_network_get_string(network,
567                                                         "WiFi.Passphrase");
568         ssid->eap = connman_network_get_string(network, "WiFi.EAP");
569
570         /*
571          * If our private key password is unset,
572          * we use the supplied passphrase. That is needed
573          * for PEAP where 2 passphrases (identity and client
574          * cert may have to be provided.
575          */
576         if (connman_network_get_string(network,
577                                         "WiFi.PrivateKeyPassphrase") == NULL)
578                 connman_network_set_string(network,
579                                                 "WiFi.PrivateKeyPassphrase",
580                                                 ssid->passphrase);
581         /* We must have an identity for both PEAP and TLS */
582         ssid->identity = connman_network_get_string(network, "WiFi.Identity");
583         ssid->ca_cert_path = connman_network_get_string(network,
584                                                         "WiFi.CACertFile");
585         ssid->client_cert_path = connman_network_get_string(network,
586                                                         "WiFi.ClientCertFile");
587         ssid->private_key_path = connman_network_get_string(network,
588                                                         "WiFi.PrivateKeyFile");
589         ssid->private_key_passphrase = connman_network_get_string(network,
590                                                 "WiFi.PrivateKeyPassphrase");
591         ssid->phase2_auth = connman_network_get_string(network, "WiFi.Phase2");
592
593 }
594
595 static int network_connect(struct connman_network *network)
596 {
597         struct connman_device *device = connman_network_get_device(network);
598         struct wifi_data *wifi;
599         GSupplicantInterface *interface;
600         GSupplicantSSID ssid;
601
602         DBG("network %p", network);
603
604         if (device == NULL)
605                 return -ENODEV;
606
607         wifi = connman_device_get_data(device);
608         if (wifi == NULL)
609                 return -ENODEV;
610
611         interface = wifi->interface;
612
613         ssid_init(&ssid, network);
614
615         wifi->network = connman_network_ref(network);
616
617         return g_supplicant_interface_connect(interface, &ssid,
618                                                 connect_callback, NULL);
619 }
620
621 static int network_disconnect(struct connman_network *network)
622 {
623         struct connman_device *device = connman_network_get_device(network);
624         struct wifi_data *wifi;
625
626         DBG("network %p", network);
627
628         wifi = connman_device_get_data(device);
629         if (wifi == NULL || wifi->interface == NULL)
630                 return -ENODEV;
631
632         connman_network_set_associating(network, FALSE);
633
634         return g_supplicant_interface_disconnect(wifi->interface,
635                                                 disconnect_callback, wifi);
636 }
637
638 static struct connman_network_driver network_driver = {
639         .name           = "wifi",
640         .type           = CONNMAN_NETWORK_TYPE_WIFI,
641         .priority       = CONNMAN_NETWORK_PRIORITY_LOW,
642         .probe          = network_probe,
643         .remove         = network_remove,
644         .connect        = network_connect,
645         .disconnect     = network_disconnect,
646 };
647
648 static int tech_probe(struct connman_technology *technology)
649 {
650         wifi_technology = technology;
651
652         return 0;
653 }
654
655 static void tech_remove(struct connman_technology *technology)
656 {
657         wifi_technology = NULL;
658 }
659
660 static void regdom_callback(void *user_data)
661 {
662         char *alpha2 = user_data;
663
664         DBG("");
665
666         if (wifi_technology == NULL)
667                 return;
668
669         connman_technology_regdom_notify(wifi_technology, alpha2);
670 }
671
672 static int tech_set_regdom(struct connman_technology *technology, const char *alpha2)
673 {
674         return g_supplicant_set_country(alpha2, regdom_callback, alpha2);
675 }
676
677 static struct connman_technology_driver tech_driver = {
678         .name           = "wifi",
679         .type           = CONNMAN_SERVICE_TYPE_WIFI,
680         .probe          = tech_probe,
681         .remove         = tech_remove,
682         .set_regdom     = tech_set_regdom,
683 };
684
685 static int wifi_init(void)
686 {
687         int err;
688
689         err = connman_network_driver_register(&network_driver);
690         if (err < 0)
691                 return err;
692
693         err = g_supplicant_register(&callbacks);
694         if (err < 0) {
695                 connman_network_driver_unregister(&network_driver);
696                 return err;
697         }
698
699         err = connman_technology_driver_register(&tech_driver);
700         if (err < 0) {
701                 g_supplicant_unregister(&callbacks);
702                 connman_network_driver_unregister(&network_driver);
703                 return err;
704         }
705
706         return 0;
707 }
708
709 static void wifi_exit(void)
710 {
711         DBG();
712
713         connman_technology_driver_unregister(&tech_driver);
714
715         g_supplicant_unregister(&callbacks);
716
717         connman_network_driver_unregister(&network_driver);
718 }
719
720 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
721                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)