Use proper constants for service type
[connman] / src / profile.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 <glib.h>
27 #include <gdbus.h>
28
29 #include "connman.h"
30
31 #define PROFILE_DEFAULT  "/profile/default"
32
33 enum connman_service_type {
34         CONNMAN_SERVICE_TYPE_UNKNOWN  = 0,
35         CONNMAN_SERVICE_TYPE_ETHERNET = 1,
36         CONNMAN_SERVICE_TYPE_WIFI     = 2,
37         CONNMAN_SERVICE_TYPE_WIMAX    = 3,
38 };
39
40 enum connman_service_state {
41         CONNMAN_SERVICE_STATE_UNKNOWN = 0,
42         CONNMAN_SERVICE_STATE_IDLE    = 1,
43 };
44
45 struct connman_group {
46         GSequenceIter *iter;
47         char *id;
48         char *path;
49         char *name;
50         char *mode;
51         char *security;
52         connman_uint8_t strength;
53         connman_bool_t favorite;
54         enum connman_service_type type;
55         enum connman_service_state state;
56         struct connman_network *network;
57 };
58
59 static GSequence *groups = NULL;
60
61 static DBusConnection *connection = NULL;
62
63 static const char *type2string(enum connman_service_type type)
64 {
65         switch (type) {
66         case CONNMAN_SERVICE_TYPE_UNKNOWN:
67                 break;
68         case CONNMAN_SERVICE_TYPE_ETHERNET:
69                 return "ethernet";
70         case CONNMAN_SERVICE_TYPE_WIFI:
71                 return "wifi";
72         case CONNMAN_SERVICE_TYPE_WIMAX:
73                 return "wimax";
74         }
75
76         return NULL;
77 }
78
79 static const char *state2string(enum connman_service_state state)
80 {
81         switch (state) {
82         case CONNMAN_SERVICE_STATE_UNKNOWN:
83                 break;
84         case CONNMAN_SERVICE_STATE_IDLE:
85                 return "idle";
86         }
87
88         return NULL;
89 }
90
91 static DBusMessage *get_properties(DBusConnection *conn,
92                                         DBusMessage *msg, void *data)
93 {
94         struct connman_group *group = data;
95         DBusMessage *reply;
96         DBusMessageIter array, dict;
97         const char *str;
98
99         DBG("conn %p", conn);
100
101         reply = dbus_message_new_method_return(msg);
102         if (reply == NULL)
103                 return NULL;
104
105         dbus_message_iter_init_append(reply, &array);
106
107         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
108                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
109                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
110                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
111
112         str = type2string(group->type);
113         if (str != NULL)
114                 connman_dbus_dict_append_variant(&dict, "Type",
115                                                 DBUS_TYPE_STRING, &str);
116
117         str = state2string(group->state);
118         if (str != NULL)
119                 connman_dbus_dict_append_variant(&dict, "State",
120                                                 DBUS_TYPE_STRING, &str);
121
122         if (group->name != NULL)
123                 connman_dbus_dict_append_variant(&dict, "Name",
124                                         DBUS_TYPE_STRING, &group->name);
125
126         if (group->mode != NULL)
127                 connman_dbus_dict_append_variant(&dict, "Mode",
128                                         DBUS_TYPE_STRING, &group->mode);
129
130         if (group->security != NULL)
131                 connman_dbus_dict_append_variant(&dict, "Security",
132                                         DBUS_TYPE_STRING, &group->security);
133
134         if (group->strength > 0)
135                 connman_dbus_dict_append_variant(&dict, "Strength",
136                                         DBUS_TYPE_BYTE, &group->strength);
137
138         connman_dbus_dict_append_variant(&dict, "Favorite",
139                                         DBUS_TYPE_BOOLEAN, &group->favorite);
140
141         dbus_message_iter_close_container(&array, &dict);
142
143         return reply;
144 }
145
146 static DBusMessage *connect_service(DBusConnection *conn,
147                                         DBusMessage *msg, void *data)
148 {
149         return __connman_error_not_implemented(msg);
150 }
151
152 static DBusMessage *disconnect_service(DBusConnection *conn,
153                                         DBusMessage *msg, void *data)
154 {
155         return __connman_error_not_implemented(msg);
156 }
157
158 static DBusMessage *remove_service(DBusConnection *conn,
159                                         DBusMessage *msg, void *data)
160 {
161         struct connman_group *group = data;
162
163         group->favorite = FALSE;
164
165         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
166 }
167
168 static DBusMessage *move_before(DBusConnection *conn,
169                                         DBusMessage *msg, void *data)
170 {
171         return __connman_error_not_implemented(msg);
172 }
173
174 static DBusMessage *move_after(DBusConnection *conn,
175                                         DBusMessage *msg, void *data)
176 {
177         return __connman_error_not_implemented(msg);
178 }
179
180 static GDBusMethodTable service_methods[] = {
181         { "GetProperties", "",  "a{sv}", get_properties     },
182         { "Connect",       "",  "",      connect_service    },
183         { "Disconnect",    "",  "",      disconnect_service },
184         { "Remove",        "",  "",      remove_service     },
185         { "MoveBefore",    "o", "",      move_before        },
186         { "MoveAfter",     "o", "",      move_after         },
187         { },
188 };
189
190 static GDBusSignalTable service_signals[] = {
191         { "PropertyChanged", "sv" },
192         { },
193 };
194
195 const char *__connman_profile_active(void)
196 {
197         DBG("");
198
199         return PROFILE_DEFAULT;
200 }
201
202 static void append_path(gpointer value, gpointer user_data)
203 {
204         struct connman_group *group = value;
205         DBusMessageIter *iter = user_data;
206
207         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
208                                                         &group->path);
209 }
210
211 void __connman_profile_list_services(DBusMessageIter *iter)
212 {
213         DBG("");
214
215         g_sequence_foreach(groups, append_path, iter);
216 }
217
218 static void append_services(DBusMessageIter *entry)
219 {
220         DBusMessageIter value, iter;
221         const char *key = "Services";
222
223         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
224
225         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
226                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
227                                                                 &value);
228
229         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
230                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
231         __connman_profile_list_services(&iter);
232         dbus_message_iter_close_container(&value, &iter);
233
234         dbus_message_iter_close_container(entry, &value);
235 }
236
237 static void emit_services_signal(void)
238 {
239         const char *path = __connman_profile_active();
240         DBusMessage *signal;
241         DBusMessageIter entry;
242
243         signal = dbus_message_new_signal(path,
244                                 CONNMAN_PROFILE_INTERFACE, "PropertyChanged");
245         if (signal == NULL)
246                 return;
247
248         dbus_message_iter_init_append(signal, &entry);
249         append_services(&entry);
250         g_dbus_send_message(connection, signal);
251
252         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
253                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
254         if (signal == NULL)
255                 return;
256
257         dbus_message_iter_init_append(signal, &entry);
258         append_services(&entry);
259         g_dbus_send_message(connection, signal);
260 }
261
262 static void free_group(gpointer data)
263 {
264         struct connman_group *group = data;
265
266         DBG("group %p", group);
267
268         g_dbus_unregister_interface(connection, group->path,
269                                                 CONNMAN_SERVICE_INTERFACE);
270
271         g_free(group->security);
272         g_free(group->mode);
273         g_free(group->name);
274         g_free(group->path);
275         g_free(group->id);
276         g_free(group);
277 }
278
279 static gint compare_group(gconstpointer a, gconstpointer b, gpointer user_data)
280 {
281         struct connman_group *group_a = (void *) a;
282         struct connman_group *group_b = (void *) b;
283
284         if (group_a->favorite == TRUE && group_b->favorite == FALSE)
285                 return -1;
286
287         if (group_a->favorite == FALSE && group_b->favorite == TRUE)
288                 return 1;
289
290         return (gint) group_b->strength - (gint) group_a->strength;
291 }
292
293 static gint search_group(gconstpointer a, gconstpointer b, gpointer user_data)
294 {
295         struct connman_group *group = (void *) a;
296
297         return g_strcmp0(group->id, user_data);
298 }
299
300 static struct connman_group *lookup_group(const char *name)
301 {
302         GSequenceIter *iter;
303         struct connman_group *group;
304
305         DBG("name %s", name);
306
307         if (name == NULL)
308                 return NULL;
309
310         iter = g_sequence_search(groups, NULL, search_group, (char *) name);
311         if (g_sequence_iter_is_begin(iter) == FALSE &&
312                                 g_sequence_iter_is_end(iter) == FALSE) {
313                 group = g_sequence_get(iter);
314                 if (group != NULL)
315                         goto done;
316         }
317
318         group = g_try_new0(struct connman_group, 1);
319         if (group == NULL)
320                 return NULL;
321
322         group->id = g_strdup(name);
323
324         group->type = CONNMAN_SERVICE_TYPE_UNKNOWN;
325         group->path = g_strdup_printf("%s/%s", PROFILE_DEFAULT, name);
326
327         group->favorite = FALSE;
328
329         group->state = CONNMAN_SERVICE_STATE_IDLE;
330
331         group->iter = g_sequence_insert_sorted(groups, group,
332                                                 compare_group, NULL);
333
334         g_dbus_register_interface(connection, group->path,
335                                         CONNMAN_SERVICE_INTERFACE,
336                                         service_methods, service_signals,
337                                                         NULL, group, NULL);
338
339 done:
340         DBG("group %p", group);
341
342         return group;
343 }
344
345 static enum connman_service_type convert_device_type(struct connman_device *device)
346 {
347         enum connman_device_type type = connman_device_get_type(device);
348
349         switch (type) {
350         case CONNMAN_DEVICE_TYPE_UNKNOWN:
351         case CONNMAN_DEVICE_TYPE_VENDOR:
352         case CONNMAN_DEVICE_TYPE_WIFI:
353         case CONNMAN_DEVICE_TYPE_WIMAX:
354         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
355         case CONNMAN_DEVICE_TYPE_GPS:
356         case CONNMAN_DEVICE_TYPE_HSO:
357         case CONNMAN_DEVICE_TYPE_NOZOMI:
358         case CONNMAN_DEVICE_TYPE_HUAWEI:
359         case CONNMAN_DEVICE_TYPE_NOVATEL:
360                 break;
361         case CONNMAN_DEVICE_TYPE_ETHERNET:
362                 return CONNMAN_SERVICE_TYPE_ETHERNET;
363         }
364
365         return CONNMAN_SERVICE_TYPE_UNKNOWN;
366 }
367
368 int __connman_profile_add_device(struct connman_device *device)
369 {
370         struct connman_group *group;
371         char *name;
372
373         DBG("device %p", device);
374
375         name = g_strdup_printf("%s_%d", __connman_device_get_type(device),
376                                         connman_device_get_index(device));
377         group = lookup_group(name);
378         g_free(name);
379
380         if (group == NULL)
381                 return -EINVAL;
382
383         group->type = convert_device_type(device);
384
385         g_sequence_sort_changed(group->iter, compare_group, NULL);
386         emit_services_signal();
387
388         return 0;
389 }
390
391 int __connman_profile_remove_device(struct connman_device *device)
392 {
393         struct connman_group *group;
394         char *name;
395
396         DBG("device %p", device);
397
398         name = g_strdup_printf("%s_%d", __connman_device_get_type(device),
399                                         connman_device_get_index(device));
400         group = lookup_group(name);
401         g_free(name);
402
403         if (group == NULL)
404                 return -EINVAL;
405
406         group->type = CONNMAN_SERVICE_TYPE_UNKNOWN;
407
408         g_sequence_sort_changed(group->iter, compare_group, NULL);
409         emit_services_signal();
410
411         return 0;
412 }
413
414 static enum connman_service_type convert_network_type(struct connman_network *network)
415 {
416         enum connman_network_type type = connman_network_get_type(network);
417
418         switch (type) {
419         case CONNMAN_NETWORK_TYPE_UNKNOWN:
420         case CONNMAN_NETWORK_TYPE_VENDOR:
421         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
422         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
423         case CONNMAN_NETWORK_TYPE_HSO:
424                 break;
425         case CONNMAN_NETWORK_TYPE_WIFI:
426                 return CONNMAN_SERVICE_TYPE_WIFI;
427         case CONNMAN_NETWORK_TYPE_WIMAX:
428                 return CONNMAN_SERVICE_TYPE_WIMAX;
429         }
430
431         return CONNMAN_SERVICE_TYPE_UNKNOWN;
432 }
433
434 int __connman_profile_add_network(struct connman_network *network)
435 {
436         struct connman_group *group;
437         char *name;
438
439         DBG("network %p", network);
440
441         if (__connman_network_get_group(network) == NULL)
442                 return -EINVAL;
443
444         name = g_strdup_printf("%s_%s", __connman_network_get_type(network),
445                                         __connman_network_get_group(network));
446         group = lookup_group(name);
447         g_free(name);
448
449         if (group == NULL)
450                 return -EINVAL;
451
452         group->type = convert_network_type(network);
453
454         g_free(group->name);
455         group->name = g_strdup(connman_network_get_string(network, "Name"));
456
457         group->strength = connman_network_get_uint8(network, "Strength");
458
459         if (group->network == NULL) {
460                 group->network = network;
461
462                 group->mode = g_strdup(connman_network_get_string(network,
463                                                                 "WiFi.Mode"));
464                 group->security = g_strdup(connman_network_get_string(network,
465                                                         "WiFi.Security"));
466         }
467
468         g_sequence_sort_changed(group->iter, compare_group, NULL);
469         emit_services_signal();
470
471         return 0;
472 }
473
474 int __connman_profile_remove_network(struct connman_network *network)
475 {
476         struct connman_group *group;
477         char *name;
478
479         DBG("network %p", network);
480
481         if (__connman_network_get_group(network) == NULL)
482                 return -EINVAL;
483
484         name = g_strdup_printf("%s_%s", __connman_network_get_type(network),
485                                         __connman_network_get_group(network));
486         group = lookup_group(name);
487         g_free(name);
488
489         if (group == NULL)
490                 return -EINVAL;
491
492         if (group->network == network) {
493                 g_free(group->security);
494                 group->security = NULL;
495
496                 g_free(group->mode);
497                 group->mode = NULL;
498
499                 group->network = NULL;
500         }
501
502         group->type = CONNMAN_SERVICE_TYPE_UNKNOWN;
503
504         g_sequence_sort_changed(group->iter, compare_group, NULL);
505         emit_services_signal();
506
507         return 0;
508 }
509
510 void __connman_profile_list(DBusMessageIter *iter)
511 {
512         const char *path = __connman_profile_active();
513
514         DBG("");
515
516         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
517 }
518
519 static DBusMessage *profile_properties(DBusConnection *conn,
520                                         DBusMessage *msg, void *data)
521 {
522         const char *name = "Default";
523         DBusMessage *reply;
524         DBusMessageIter array, dict, entry;
525
526         DBG("conn %p", conn);
527
528         reply = dbus_message_new_method_return(msg);
529         if (reply == NULL)
530                 return NULL;
531
532         dbus_message_iter_init_append(reply, &array);
533
534         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
535                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
536                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
537                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
538
539         connman_dbus_dict_append_variant(&dict, "Name",
540                                                 DBUS_TYPE_STRING, &name);
541
542         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
543                                                                 NULL, &entry);
544         append_services(&entry);
545         dbus_message_iter_close_container(&dict, &entry);
546
547         dbus_message_iter_close_container(&array, &dict);
548
549         return reply;
550 }
551
552 static GDBusMethodTable profile_methods[] = {
553         { "GetProperties", "", "a{sv}", profile_properties },
554         { },
555 };
556
557 static GDBusSignalTable profile_signals[] = {
558         { "PropertyChanged", "sv" },
559         { },
560 };
561
562 int __connman_profile_init(DBusConnection *conn)
563 {
564         DBG("conn %p", conn);
565
566         connection = dbus_connection_ref(conn);
567         if (connection == NULL)
568                 return -1;
569
570         groups = g_sequence_new(free_group);
571
572         g_dbus_register_interface(connection, PROFILE_DEFAULT,
573                                         CONNMAN_PROFILE_INTERFACE,
574                                         profile_methods, profile_signals,
575                                                         NULL, NULL, NULL);
576
577         return 0;
578 }
579
580 void __connman_profile_cleanup(void)
581 {
582         DBG("conn %p", connection);
583
584         g_dbus_unregister_interface(connection, PROFILE_DEFAULT,
585                                                 CONNMAN_PROFILE_INTERFACE);
586
587         g_sequence_free(groups);
588         groups = NULL;
589
590         if (connection == NULL)
591                 return;
592
593         dbus_connection_unref(connection);
594 }