Fix handling of WiFi SSID values
[framework/connectivity/connman.git] / plugins / wifi.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  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 <string.h>
27 #include <dbus/dbus.h>
28
29 #include <connman/plugin.h>
30 #include <connman/driver.h>
31 #include <connman/log.h>
32
33 #include "supplicant.h"
34
35 struct wifi_data {
36         GStaticMutex mutex;
37         GSList *list;
38         gchar *identifier;
39 };
40
41 static int network_probe(struct connman_element *element)
42 {
43         DBG("element %p name %s", element, element->name);
44
45         return 0;
46 }
47
48 static void network_remove(struct connman_element *element)
49 {
50         DBG("element %p name %s", element, element->name);
51 }
52
53 static int network_enable(struct connman_element *element)
54 {
55         char *identifier, *passphrase = NULL;
56         unsigned char *ssid;
57         int ssid_len;
58
59         DBG("element %p name %s", element, element->name);
60
61         if (connman_element_get_static_property(element,
62                                         "Identifier", &identifier) == FALSE)
63                 return -EIO;
64
65         if (connman_element_get_static_array_property(element,
66                                         "SSID", &ssid, &ssid_len) == FALSE)
67                 return -EIO;
68
69         if (element->parent != NULL) {
70                 struct wifi_data *data = connman_element_get_data(element->parent);
71
72                 if (data != NULL) {
73                         g_free(data->identifier);
74                         data->identifier = g_strdup(identifier);
75                 }
76         }
77
78         DBG("identifier %s passhprase %s", identifier, passphrase);
79
80         if (__supplicant_connect(element, ssid, ssid_len, passphrase) < 0)
81                 connman_error("Failed to initiate connect");
82
83         return 0;
84 }
85
86 static int network_disable(struct connman_element *element)
87 {
88         DBG("element %p name %s", element, element->name);
89
90         connman_element_unregister_children(element);
91
92         __supplicant_disconnect(element);
93
94         return 0;
95 }
96
97 static struct connman_driver network_driver = {
98         .name           = "wifi-network",
99         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
100         .subtype        = CONNMAN_ELEMENT_SUBTYPE_WIFI,
101         .probe          = network_probe,
102         .remove         = network_remove,
103         .enable         = network_enable,
104         .disable        = network_disable,
105 };
106
107 static struct connman_element *find_element(struct wifi_data *data,
108                                                 const char *identifier)
109 {
110         GSList *list;
111
112         for (list = data->list; list; list = list->next) {
113                 struct connman_element *element = list->data;
114
115                 if (connman_element_match_static_property(element,
116                                         "Identifier", &identifier) == TRUE)
117                         return element;
118         }
119
120         return NULL;
121 }
122
123 static void state_change(struct connman_element *parent,
124                                                 enum supplicant_state state)
125 {
126         struct wifi_data *data = connman_element_get_data(parent);
127         struct connman_element *element;
128
129         DBG("state %d", state);
130
131         if (data->identifier == NULL)
132                 return;
133
134         element = find_element(data, data->identifier);
135         if (element == NULL)
136                 return;
137
138         if (state == STATE_COMPLETED) {
139                 struct connman_element *dhcp;
140
141                 dhcp = connman_element_create(NULL);
142
143                 dhcp->type = CONNMAN_ELEMENT_TYPE_DHCP;
144                 dhcp->index = element->index;
145
146                 connman_element_register(dhcp, element);
147         }
148 }
149
150 static void scan_result(struct connman_element *parent,
151                                         struct supplicant_network *network)
152 {
153         struct wifi_data *data = connman_element_get_data(parent);
154         struct connman_element *element;
155         gchar *temp;
156         int i;
157
158         DBG("network %p identifier %s", network, network->identifier);
159
160         if (data == NULL)
161                 return;
162
163         if (network->identifier == NULL)
164                 return;
165
166         if (network->identifier[0] == '\0')
167                 return;
168
169         temp = g_strdup(network->identifier);
170
171         for (i = 0; i < strlen(temp); i++) {
172                 if (temp[i] == ' ' || temp[i] == '.' || temp[i] == '-')
173                         temp[i] = '_';
174                 if (temp[i] == '(' || temp[i] == ')')
175                         temp[i] = '_';
176                 if (g_ascii_isprint(temp[i]) == FALSE)
177                         temp[i] = '_';
178                 temp[i] = g_ascii_tolower(temp[i]);
179         }
180
181         g_static_mutex_lock(&data->mutex);
182
183         element = find_element(data, network->identifier);
184         if (element == NULL) {
185                 element = connman_element_create(temp);
186
187                 element->type = CONNMAN_ELEMENT_TYPE_NETWORK;
188                 element->index = parent->index;
189
190                 data->list = g_slist_append(data->list, element);
191
192                 connman_element_add_static_property(element, "Identifier",
193                                 DBUS_TYPE_STRING, &network->identifier);
194
195                 connman_element_add_static_array_property(element, "SSID",
196                         DBUS_TYPE_BYTE, &network->ssid, network->ssid_len);
197
198                 connman_element_register(element, parent);
199         }
200
201         g_static_mutex_unlock(&data->mutex);
202
203         g_free(temp);
204 }
205
206 static struct supplicant_callback wifi_callback = {
207         .state_change   = state_change,
208         .scan_result    = scan_result,
209 };
210
211 static int wifi_probe(struct connman_element *element)
212 {
213         struct wifi_data *data;
214
215         DBG("element %p name %s", element, element->name);
216
217         data = g_try_new0(struct wifi_data, 1);
218         if (data == NULL)
219                 return -ENOMEM;
220
221         g_static_mutex_init(&data->mutex);
222
223         connman_element_set_data(element, data);
224
225         return 0;
226 }
227
228 static void wifi_remove(struct connman_element *element)
229 {
230         struct wifi_data *data = connman_element_get_data(element);
231
232         DBG("element %p name %s", element, element->name);
233
234         connman_element_set_data(element, NULL);
235
236         g_free(data->identifier);
237         g_free(data);
238 }
239
240 static int wifi_update(struct connman_element *element)
241 {
242         DBG("element %p name %s", element, element->name);
243
244         __supplicant_scan(element);
245
246         return 0;
247 }
248
249 static int wifi_enable(struct connman_element *element)
250 {
251         int err;
252
253         DBG("element %p name %s", element, element->name);
254
255         err = __supplicant_start(element, &wifi_callback);
256         if (err < 0)
257                 return err;
258
259         __supplicant_scan(element);
260
261         return 0;
262 }
263
264 static int wifi_disable(struct connman_element *element)
265 {
266         struct wifi_data *data = connman_element_get_data(element);
267         GSList *list;
268
269         DBG("element %p name %s", element, element->name);
270
271         __supplicant_disconnect(element);
272
273         g_static_mutex_lock(&data->mutex);
274
275         for (list = data->list; list; list = list->next) {
276                 struct connman_element *network = list->data;
277
278                 connman_element_unref(network);
279         }
280
281         g_slist_free(data->list);
282         data->list = NULL;
283
284         g_static_mutex_unlock(&data->mutex);
285
286         connman_element_unregister_children(element);
287
288         return 0;
289 }
290
291 static struct connman_driver wifi_driver = {
292         .name           = "wifi-device",
293         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
294         .subtype        = CONNMAN_ELEMENT_SUBTYPE_WIFI,
295         .probe          = wifi_probe,
296         .remove         = wifi_remove,
297         .update         = wifi_update,
298         .enable         = wifi_enable,
299         .disable        = wifi_disable,
300 };
301
302 static int wifi_init(void)
303 {
304         int err;
305
306         err = __supplicant_init();
307         if (err < 0)
308                 return err;
309
310         err = connman_driver_register(&network_driver);
311         if (err < 0) {
312                 __supplicant_exit();
313                 return err;
314         }
315
316         err = connman_driver_register(&wifi_driver);
317         if (err < 0) {
318                 connman_driver_unregister(&network_driver);
319                 __supplicant_exit();
320                 return err;
321         }
322
323         return 0;
324 }
325
326 static void wifi_exit(void)
327 {
328         connman_driver_unregister(&network_driver);
329         connman_driver_unregister(&wifi_driver);
330
331         __supplicant_exit();
332 }
333
334 CONNMAN_PLUGIN_DEFINE("wifi", "WiFi interface plugin", VERSION,
335                                                         wifi_init, wifi_exit)