Don't try to re-connect to networks out of range
[connman] / src / manager.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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 <gdbus.h>
27
28 #include "connman.h"
29
30 enum connman_policy {
31         CONNMAN_POLICY_UNKNOWN  = 0,
32         CONNMAN_POLICY_SINGLE   = 1,
33         CONNMAN_POLICY_MULTIPLE = 2,
34         CONNMAN_POLICY_ASK      = 3,
35 };
36
37 static enum connman_policy global_policy = CONNMAN_POLICY_SINGLE;
38 static connman_bool_t global_offlinemode = FALSE;
39
40 static const char *policy2string(enum connman_policy policy)
41 {
42         switch (policy) {
43         case CONNMAN_POLICY_UNKNOWN:
44                 break;
45         case CONNMAN_POLICY_SINGLE:
46                 return "single";
47         case CONNMAN_POLICY_MULTIPLE:
48                 return "multiple";
49         case CONNMAN_POLICY_ASK:
50                 return "ask";
51         }
52
53         return NULL;
54 }
55
56 static enum connman_policy string2policy(const char *policy)
57 {
58         if (g_str_equal(policy, "single") == TRUE)
59                 return CONNMAN_POLICY_SINGLE;
60         else if (g_str_equal(policy, "multiple") == TRUE)
61                 return CONNMAN_POLICY_MULTIPLE;
62         else if (g_str_equal(policy, "ask") == TRUE)
63                 return CONNMAN_POLICY_ASK;
64         else
65                 return CONNMAN_POLICY_UNKNOWN;
66 }
67
68 static void append_profiles(DBusMessageIter *dict)
69 {
70         DBusMessageIter entry, value, iter;
71         const char *key = "Profiles";
72
73         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
74                                                                 NULL, &entry);
75
76         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
77
78         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
79                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
80                                                                 &value);
81
82         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
83                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
84
85         __connman_profile_list(&iter);
86
87         dbus_message_iter_close_container(&value, &iter);
88
89         dbus_message_iter_close_container(&entry, &value);
90
91         dbus_message_iter_close_container(dict, &entry);
92 }
93
94 static void append_devices(DBusMessageIter *dict)
95 {
96         DBusMessageIter entry, value, iter;
97         const char *key = "Devices";
98
99         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
100                                                                 NULL, &entry);
101
102         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
103
104         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
105                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
106                                                                 &value);
107
108         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
109                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
110
111         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
112
113         dbus_message_iter_close_container(&value, &iter);
114
115         dbus_message_iter_close_container(&entry, &value);
116
117         dbus_message_iter_close_container(dict, &entry);
118 }
119
120 static void append_connections(DBusMessageIter *dict)
121 {
122         DBusMessageIter entry, value, iter;
123         const char *key = "Connections";
124
125         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
126                                                                 NULL, &entry);
127
128         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
129
130         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
131                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
132                                                                 &value);
133
134         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
135                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
136
137         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
138
139         dbus_message_iter_close_container(&value, &iter);
140
141         dbus_message_iter_close_container(&entry, &value);
142
143         dbus_message_iter_close_container(dict, &entry);
144 }
145
146 static DBusMessage *get_properties(DBusConnection *conn,
147                                         DBusMessage *msg, void *data)
148 {
149         DBusMessage *reply;
150         DBusMessageIter array, dict;
151         const char *str;
152
153         DBG("conn %p", conn);
154
155         if (__connman_security_check_privilege(msg,
156                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
157                 return __connman_error_permission_denied(msg);
158
159         reply = dbus_message_new_method_return(msg);
160         if (reply == NULL)
161                 return NULL;
162
163         dbus_message_iter_init_append(reply, &array);
164
165         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
166                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
167                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
168                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
169
170         append_profiles(&dict);
171
172         append_devices(&dict);
173         append_connections(&dict);
174
175         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
176                 str = "online";
177         else
178                 str = "offline";
179
180         connman_dbus_dict_append_variant(&dict, "State",
181                                                 DBUS_TYPE_STRING, &str);
182
183         str = policy2string(global_policy);
184         if (str != NULL)
185                 connman_dbus_dict_append_variant(&dict, "Policy",
186                                                 DBUS_TYPE_STRING, &str);
187
188         connman_dbus_dict_append_variant(&dict, "OfflineMode",
189                                 DBUS_TYPE_BOOLEAN, &global_offlinemode);
190
191         dbus_message_iter_close_container(&array, &dict);
192
193         return reply;
194 }
195
196 static DBusMessage *set_property(DBusConnection *conn,
197                                         DBusMessage *msg, void *data)
198 {
199         DBusMessageIter iter, value;
200         const char *name;
201
202         DBG("conn %p", conn);
203
204         if (dbus_message_iter_init(msg, &iter) == FALSE)
205                 return __connman_error_invalid_arguments(msg);
206
207         dbus_message_iter_get_basic(&iter, &name);
208         dbus_message_iter_next(&iter);
209         dbus_message_iter_recurse(&iter, &value);
210
211         if (__connman_security_check_privilege(msg,
212                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
213                 return __connman_error_permission_denied(msg);
214
215         if (g_str_equal(name, "Policy") == TRUE) {
216                 enum connman_policy policy;
217                 const char *str;
218
219                 dbus_message_iter_get_basic(&value, &str);
220                 policy = string2policy(str);
221                 if (policy == CONNMAN_POLICY_UNKNOWN)
222                         return __connman_error_invalid_arguments(msg);
223
224                 global_policy = policy;
225         } else if (g_str_equal(name, "OfflineMode") == TRUE) {
226                 connman_bool_t offlinemode;
227
228                 dbus_message_iter_get_basic(&value, &offlinemode);
229
230                 if (global_offlinemode == offlinemode)
231                         return __connman_error_invalid_arguments(msg);
232
233                 global_offlinemode = offlinemode;
234
235                 __connman_device_set_offlinemode(offlinemode);
236         }
237
238         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
239 }
240
241 static DBusMessage *register_agent(DBusConnection *conn,
242                                         DBusMessage *msg, void *data)
243 {
244         DBusMessage *reply;
245         const char *sender, *path;
246
247         DBG("conn %p", conn);
248
249         sender = dbus_message_get_sender(msg);
250
251         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
252                                                         DBUS_TYPE_INVALID);
253
254         reply = dbus_message_new_method_return(msg);
255         if (reply == NULL)
256                 return NULL;
257
258         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
259
260         __connman_agent_register(sender, path);
261
262         return reply;
263 }
264
265 static DBusMessage *unregister_agent(DBusConnection *conn,
266                                         DBusMessage *msg, void *data)
267 {
268         DBusMessage *reply;
269         const char *sender, *path;
270
271         DBG("conn %p", conn);
272
273         sender = dbus_message_get_sender(msg);
274
275         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
276                                                         DBUS_TYPE_INVALID);
277
278         reply = dbus_message_new_method_return(msg);
279         if (reply == NULL)
280                 return NULL;
281
282         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
283
284         __connman_agent_unregister(sender, path);
285
286         return reply;
287 }
288
289 static GDBusMethodTable manager_methods[] = {
290         { "GetProperties",   "",   "a{sv}", get_properties   },
291         { "SetProperty",     "sv", "",      set_property     },
292         { "RegisterAgent",   "o",  "",      register_agent   },
293         { "UnregisterAgent", "o",  "",      unregister_agent },
294         { },
295 };
296
297 static GDBusSignalTable manager_signals[] = {
298         { "PropertyChanged", "sv" },
299         { },
300 };
301
302 static DBusMessage *nm_sleep(DBusConnection *conn,
303                                         DBusMessage *msg, void *data)
304 {
305         DBusMessage *reply;
306
307         DBG("conn %p", conn);
308
309         reply = dbus_message_new_method_return(msg);
310         if (reply == NULL)
311                 return NULL;
312
313         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
314
315         return reply;
316 }
317
318 static DBusMessage *nm_wake(DBusConnection *conn,
319                                         DBusMessage *msg, void *data)
320 {
321         DBusMessage *reply;
322
323         DBG("conn %p", conn);
324
325         reply = dbus_message_new_method_return(msg);
326         if (reply == NULL)
327                 return NULL;
328
329         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
330
331         return reply;
332 }
333
334 enum {
335         NM_STATE_UNKNOWN = 0,
336         NM_STATE_ASLEEP,
337         NM_STATE_CONNECTING,
338         NM_STATE_CONNECTED,
339         NM_STATE_DISCONNECTED
340 };
341
342 static DBusMessage *nm_state(DBusConnection *conn,
343                                         DBusMessage *msg, void *data)
344 {
345         DBusMessage *reply;
346         dbus_uint32_t state;
347
348         DBG("conn %p", conn);
349
350         reply = dbus_message_new_method_return(msg);
351         if (reply == NULL)
352                 return NULL;
353
354         state = NM_STATE_DISCONNECTED;
355
356         dbus_message_append_args(reply, DBUS_TYPE_UINT32, &state,
357                                                         DBUS_TYPE_INVALID);
358
359         return reply;
360 }
361
362 static GDBusMethodTable nm_methods[] = {
363         { "sleep", "",  "",   nm_sleep        },
364         { "wake",  "",  "",   nm_wake         },
365         { "state", "",  "u",  nm_state        },
366         { },
367 };
368
369 static DBusConnection *connection = NULL;
370 static gboolean nm_compat = FALSE;
371
372 int __connman_manager_init(DBusConnection *conn, gboolean compat)
373 {
374         DBG("conn %p", conn);
375
376         connection = dbus_connection_ref(conn);
377         if (connection == NULL)
378                 return -1;
379
380         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
381                                         CONNMAN_MANAGER_INTERFACE,
382                                         manager_methods,
383                                         manager_signals, NULL, NULL, NULL);
384
385         if (compat == TRUE) {
386                 g_dbus_register_interface(connection, NM_PATH, NM_INTERFACE,
387                                         nm_methods, NULL, NULL, NULL, NULL);
388
389                 nm_compat = TRUE;
390         }
391
392         return 0;
393 }
394
395 void __connman_manager_cleanup(void)
396 {
397         DBG("conn %p", connection);
398
399         if (nm_compat == TRUE) {
400                 g_dbus_unregister_interface(connection, NM_PATH, NM_INTERFACE);
401         }
402
403         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
404                                                 CONNMAN_MANAGER_INTERFACE);
405
406         dbus_connection_unref(connection);
407 }