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