Rename connect/disconnect to enable/disable for better semantics
[connman] / 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->connected = 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->connected = 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();
144
145                 dhcp->type = CONNMAN_ELEMENT_TYPE_DHCP;
146                 dhcp->netdev.index = element->netdev.index;
147                 dhcp->netdev.name = g_strdup(element->netdev.name);
148
149                 dhcp_element = dhcp;
150
151                 element->connected = TRUE;
152
153                 connman_element_update(element);
154
155                 connman_element_register(dhcp, element);
156         }
157 }
158
159 static void scan_result(struct connman_element *parent,
160                                         struct supplicant_network *network)
161 {
162         struct wifi_data *data = connman_element_get_data(parent);
163         struct connman_element *element;
164         gchar *temp;
165         int i;
166
167         DBG("network %p identifier %s", network, network->identifier);
168
169         if (data == NULL)
170                 return;
171
172         if (network->identifier == NULL)
173                 return;
174
175         if (network->identifier[0] == '\0')
176                 return;
177
178         temp = g_strdup(network->identifier);
179
180         for (i = 0; i < strlen(temp); i++) {
181                 if (temp[i] == ' ' || temp[i] == '.' || temp[i] == '-')
182                         temp[i] = '_';
183                 if (temp[i] == '(' || temp[i] == ')')
184                         temp[i] = '_';
185                 if (g_ascii_isprint(temp[i]) == FALSE)
186                         temp[i] = '_';
187                 temp[i] = g_ascii_tolower(temp[i]);
188         }
189
190         g_static_mutex_lock(&data->mutex);
191
192         element = find_element(data, network->identifier);
193         if (element == NULL) {
194                 element = connman_element_create();
195
196                 element->type = CONNMAN_ELEMENT_TYPE_NETWORK;
197                 element->name = temp;
198
199                 element->network.identifier = g_strdup(network->identifier);
200
201                 element->netdev.index = parent->netdev.index;
202                 element->netdev.name = g_strdup(parent->netdev.name);
203
204                 data->list = g_slist_append(data->list, element);
205
206                 connman_element_add_static_property(element, "SSID",
207                                 DBUS_TYPE_STRING, &network->identifier);
208
209                 connman_element_register(element, parent);
210         } else
211                 g_free(temp);
212
213         g_static_mutex_unlock(&data->mutex);
214 }
215
216 static struct supplicant_callback wifi_callback = {
217         .state_change   = state_change,
218         .scan_result    = scan_result,
219 };
220
221 static int wifi_probe(struct connman_element *element)
222 {
223         struct wifi_data *data;
224         int err;
225
226         DBG("element %p name %s", element, element->name);
227
228         data = g_try_new0(struct wifi_data, 1);
229         if (data == NULL)
230                 return -ENOMEM;
231
232         g_static_mutex_init(&data->mutex);
233
234         connman_element_set_data(element, data);
235
236         err = __supplicant_start(element, &wifi_callback);
237         if (err < 0)
238                 return err;
239
240         __supplicant_scan(element);
241
242         return 0;
243 }
244
245 static void wifi_remove(struct connman_element *element)
246 {
247         struct wifi_data *data = connman_element_get_data(element);
248         GSList *list;
249
250         DBG("element %p name %s", element, element->name);
251
252         __supplicant_stop(element);
253
254         connman_element_set_data(element, NULL);
255
256         if (data == NULL)
257                 return;
258
259         g_static_mutex_lock(&data->mutex);
260
261         for (list = data->list; list; list = list->next) {
262                 struct connman_element *network = list->data;
263
264                 connman_element_unregister(network);
265                 connman_element_unref(network);
266         }
267
268         g_slist_free(data->list);
269
270         g_static_mutex_unlock(&data->mutex);
271
272         g_free(data);
273 }
274
275 static int wifi_update(struct connman_element *element)
276 {
277         DBG("element %p name %s", element, element->name);
278
279         __supplicant_scan(element);
280
281         return 0;
282 }
283
284 static struct connman_driver wifi_driver = {
285         .name           = "wifi-device",
286         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
287         .subtype        = CONNMAN_ELEMENT_SUBTYPE_WIFI,
288         .probe          = wifi_probe,
289         .remove         = wifi_remove,
290         .update         = wifi_update,
291 };
292
293 static int wifi_init(void)
294 {
295         int err;
296
297         err = connman_driver_register(&network_driver);
298         if (err < 0)
299                 return err;
300
301         err = connman_driver_register(&wifi_driver);
302         if (err < 0) {
303                 connman_driver_unregister(&network_driver);
304                 return err;
305         }
306
307         return 0;
308 }
309
310 static void wifi_exit(void)
311 {
312         connman_driver_unregister(&network_driver);
313         connman_driver_unregister(&wifi_driver);
314 }
315
316 CONNMAN_PLUGIN_DEFINE("wifi", "WiFi interface plugin", VERSION,
317                                                         wifi_init, wifi_exit)