befc3733a70a09cbf88f11b67d704b68df3457f7
[platform/upstream/connman.git] / src / manager.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  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 <errno.h>
27
28 #include <gdbus.h>
29
30 #include <connman/agent.h>
31
32 #include "connman.h"
33
34 static bool connman_state_idle;
35 static dbus_bool_t sessionmode;
36
37 #if defined TIZEN_EXT
38 static void append_wifi_vsies_structs(DBusMessageIter *iter, void *user_data)
39 {
40         __connman_wifi_vsie_list_struct(iter);
41 }
42
43 static DBusMessage *get_wifi_vsies(DBusConnection *conn,
44                                         DBusMessage *msg, void *data)
45 {
46         DBusMessage *reply;
47
48         DBG("ConnMan, get_wifi_vsies API called");
49
50         reply = dbus_message_new_method_return(msg);
51         if (!reply)
52                 return NULL;
53
54         __connman_dbus_append_objpath_dict_array(reply,
55                         append_wifi_vsies_structs, NULL);
56
57         return reply;
58 }
59 #endif
60
61 static DBusMessage *get_properties(DBusConnection *conn,
62                                         DBusMessage *msg, void *data)
63 {
64         DBusMessage *reply;
65         DBusMessageIter array, dict;
66         dbus_bool_t offlinemode;
67         const char *str;
68 #if defined TIZEN_EXT
69         dbus_bool_t autoconnectmode;
70 #endif
71
72         DBG("conn %p", conn);
73
74         reply = dbus_message_new_method_return(msg);
75         if (!reply)
76                 return NULL;
77
78         dbus_message_iter_init_append(reply, &array);
79
80         connman_dbus_dict_open(&array, &dict);
81
82         str = __connman_notifier_get_state();
83         connman_dbus_dict_append_basic(&dict, "State",
84                                                 DBUS_TYPE_STRING, &str);
85
86         offlinemode = __connman_technology_get_offlinemode();
87         connman_dbus_dict_append_basic(&dict, "OfflineMode",
88                                         DBUS_TYPE_BOOLEAN, &offlinemode);
89
90         connman_dbus_dict_append_basic(&dict, "SessionMode",
91                                         DBUS_TYPE_BOOLEAN,
92                                         &sessionmode);
93 #if defined TIZEN_EXT
94         autoconnectmode = __connman_service_get_auto_connect_mode();
95         connman_dbus_dict_append_basic(&dict, "AutoConnectMode",
96                                         DBUS_TYPE_BOOLEAN,
97                                         &autoconnectmode);
98 #endif
99
100         connman_dbus_dict_close(&array, &dict);
101
102         return reply;
103 }
104
105 static DBusMessage *set_property(DBusConnection *conn,
106                                         DBusMessage *msg, void *data)
107 {
108         DBusMessageIter iter, value;
109         const char *name;
110         int type;
111
112         DBG("conn %p", conn);
113
114         if (!dbus_message_iter_init(msg, &iter))
115                 return __connman_error_invalid_arguments(msg);
116
117         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
118                 return __connman_error_invalid_arguments(msg);
119
120         dbus_message_iter_get_basic(&iter, &name);
121         dbus_message_iter_next(&iter);
122
123         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
124                 return __connman_error_invalid_arguments(msg);
125
126         dbus_message_iter_recurse(&iter, &value);
127
128         type = dbus_message_iter_get_arg_type(&value);
129
130         if (g_str_equal(name, "OfflineMode")) {
131                 dbus_bool_t offlinemode;
132
133                 if (type != DBUS_TYPE_BOOLEAN)
134                         return __connman_error_invalid_arguments(msg);
135
136                 dbus_message_iter_get_basic(&value, &offlinemode);
137
138                 if (offlinemode) {
139                         uid_t uid;
140                         if (connman_dbus_get_connection_unix_user_sync(conn,
141                                                 dbus_message_get_sender(msg),
142                                                 &uid) < 0) {
143                                 DBG("Can not get unix user id!");
144                                 return __connman_error_permission_denied(msg);
145                         }
146
147                         if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
148                                 DBG("Not allow this user to turn on offlinemode now!");
149                                 return __connman_error_permission_denied(msg);
150                         }
151                 }
152                 __connman_technology_set_offlinemode(offlinemode);
153         } else if (g_str_equal(name, "SessionMode")) {
154
155                 if (type != DBUS_TYPE_BOOLEAN)
156                         return __connman_error_invalid_arguments(msg);
157
158                 dbus_message_iter_get_basic(&value, &sessionmode);
159         }
160 #if defined TIZEN_EXT
161         else if (g_str_equal(name, "AutoConnectMode") == TRUE) {
162                 bool automode;
163
164                 if (type != DBUS_TYPE_BOOLEAN)
165                         return __connman_error_invalid_arguments(msg);
166
167                 dbus_message_iter_get_basic(&value, &automode);
168
169                 __connman_service_set_auto_connect_mode(automode);
170         }
171 #endif
172         else
173                 return __connman_error_invalid_property(msg);
174
175         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
176 }
177
178 static void append_technology_structs(DBusMessageIter *iter, void *user_data)
179 {
180         __connman_technology_list_struct(iter);
181 }
182
183 static DBusMessage *get_technologies(DBusConnection *conn,
184                 DBusMessage *msg, void *data)
185 {
186         DBusMessage *reply;
187
188 #if !defined TIZEN_EXT
189         DBG("");
190 #endif
191
192         reply = dbus_message_new_method_return(msg);
193         if (!reply)
194                 return NULL;
195
196         __connman_dbus_append_objpath_dict_array(reply,
197                         append_technology_structs, NULL);
198
199         return reply;
200 }
201
202 static DBusMessage *remove_provider(DBusConnection *conn,
203                                     DBusMessage *msg, void *data)
204 {
205         const char *path;
206         int err;
207
208         DBG("conn %p", conn);
209
210         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
211                                                         DBUS_TYPE_INVALID);
212
213         err = __connman_provider_remove_by_path(path);
214         if (err < 0)
215                 return __connman_error_failed(msg, -err);
216
217         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
218 }
219
220 static DBusConnection *connection = NULL;
221
222 static void idle_state(bool idle)
223 {
224
225         DBG("idle %d", idle);
226
227         connman_state_idle = idle;
228
229         if (!connman_state_idle)
230                 return;
231 }
232
233 static struct connman_notifier technology_notifier = {
234         .name           = "manager",
235         .priority       = CONNMAN_NOTIFIER_PRIORITY_HIGH,
236         .idle_state     = idle_state,
237 };
238
239 static void append_service_structs(DBusMessageIter *iter, void *user_data)
240 {
241         __connman_service_list_struct(iter);
242 }
243
244 static DBusMessage *get_services(DBusConnection *conn,
245                                         DBusMessage *msg, void *data)
246 {
247         DBusMessage *reply;
248
249         reply = dbus_message_new_method_return(msg);
250         if (!reply)
251                 return NULL;
252
253         __connman_dbus_append_objpath_dict_array(reply,
254                         append_service_structs, NULL);
255
256         return reply;
257 }
258
259 static void append_peer_structs(DBusMessageIter *iter, void *user_data)
260 {
261         __connman_peer_list_struct(iter);
262 }
263
264 static DBusMessage *get_peers(DBusConnection *conn,
265                                         DBusMessage *msg, void *data)
266 {
267         DBusMessage *reply;
268
269         reply = dbus_message_new_method_return(msg);
270         if (!reply)
271                 return NULL;
272
273         __connman_dbus_append_objpath_dict_array(reply,
274                                         append_peer_structs, NULL);
275         return reply;
276 }
277
278 static DBusMessage *connect_provider(DBusConnection *conn,
279                                         DBusMessage *msg, void *data)
280 {
281         int err;
282
283         DBG("conn %p", conn);
284
285         err = __connman_provider_create_and_connect(msg);
286         if (err < 0)
287                 return __connman_error_failed(msg, -err);
288
289         return NULL;
290 }
291
292 static DBusMessage *register_agent(DBusConnection *conn,
293                                         DBusMessage *msg, void *data)
294 {
295         const char *sender, *path;
296         int err;
297
298         DBG("conn %p", conn);
299
300         sender = dbus_message_get_sender(msg);
301
302         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
303                                                         DBUS_TYPE_INVALID);
304
305         err = connman_agent_register(sender, path);
306         if (err < 0)
307                 return __connman_error_failed(msg, -err);
308
309         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
310 }
311
312 static DBusMessage *unregister_agent(DBusConnection *conn,
313                                         DBusMessage *msg, void *data)
314 {
315         const char *sender, *path;
316         int err;
317
318         DBG("conn %p", conn);
319
320         sender = dbus_message_get_sender(msg);
321
322         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
323                                                         DBUS_TYPE_INVALID);
324
325         err = connman_agent_unregister(sender, path);
326         if (err < 0)
327                 return __connman_error_failed(msg, -err);
328
329         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
330 }
331
332 static DBusMessage *register_counter(DBusConnection *conn,
333                                         DBusMessage *msg, void *data)
334 {
335         const char *sender, *path;
336         unsigned int accuracy, period;
337         int err;
338
339         DBG("conn %p", conn);
340
341         sender = dbus_message_get_sender(msg);
342
343         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
344                                                 DBUS_TYPE_UINT32, &accuracy,
345                                                 DBUS_TYPE_UINT32, &period,
346                                                         DBUS_TYPE_INVALID);
347
348         /* FIXME: add handling of accuracy parameter */
349
350         err = __connman_counter_register(sender, path, period);
351         if (err < 0)
352                 return __connman_error_failed(msg, -err);
353
354         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
355 }
356
357 static DBusMessage *unregister_counter(DBusConnection *conn,
358                                         DBusMessage *msg, void *data)
359 {
360         const char *sender, *path;
361         int err;
362
363         DBG("conn %p", conn);
364
365         sender = dbus_message_get_sender(msg);
366
367         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
368                                                         DBUS_TYPE_INVALID);
369
370         err = __connman_counter_unregister(sender, path);
371         if (err < 0)
372                 return __connman_error_failed(msg, -err);
373
374         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
375 }
376
377 static DBusMessage *create_session(DBusConnection *conn,
378                                         DBusMessage *msg, void *data)
379 {
380         int err;
381
382         DBG("conn %p", conn);
383
384         err = __connman_session_create(msg);
385         if (err < 0) {
386                 if (err == -EINPROGRESS)
387                         return NULL;
388
389                 return __connman_error_failed(msg, -err);
390         }
391
392         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
393 }
394
395 static DBusMessage *destroy_session(DBusConnection *conn,
396                                         DBusMessage *msg, void *data)
397 {
398         int err;
399
400         DBG("conn %p", conn);
401
402         err = __connman_session_destroy(msg);
403         if (err < 0)
404                 return __connman_error_failed(msg, -err);
405
406         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
407 }
408
409 static DBusMessage *request_private_network(DBusConnection *conn,
410                                         DBusMessage *msg, void *data)
411 {
412         const char *sender;
413         int  err;
414
415         DBG("conn %p", conn);
416
417         sender = dbus_message_get_sender(msg);
418
419         err = __connman_private_network_request(msg, sender);
420         if (err < 0)
421                 return __connman_error_failed(msg, -err);
422
423         return NULL;
424 }
425
426 static DBusMessage *release_private_network(DBusConnection *conn,
427                                         DBusMessage *msg, void *data)
428 {
429         const char *path;
430         int err;
431
432         DBG("conn %p", conn);
433
434         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
435                                                         DBUS_TYPE_INVALID);
436
437         err = __connman_private_network_release(path);
438         if (err < 0)
439                 return __connman_error_failed(msg, -err);
440
441         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
442 }
443
444 static int parse_peers_service_specs(DBusMessageIter *array,
445                         const unsigned char **spec, int *spec_len,
446                         const unsigned char **query, int *query_len,
447                         int *version)
448 {
449         *spec = *query = NULL;
450         *spec_len = *query_len = *version = 0;
451
452         while (dbus_message_iter_get_arg_type(array) ==
453                                                         DBUS_TYPE_DICT_ENTRY) {
454                 DBusMessageIter entry, inter, value;
455                 const char *key;
456
457                 dbus_message_iter_recurse(array, &entry);
458                 dbus_message_iter_get_basic(&entry, &key);
459
460                 dbus_message_iter_next(&entry);
461
462                 dbus_message_iter_recurse(&entry, &inter);
463
464                 if  (!g_strcmp0(key, "BonjourResponse")) {
465                         dbus_message_iter_recurse(&inter, &value);
466                         dbus_message_iter_get_fixed_array(&value,
467                                                         spec, spec_len);
468                 } else if (!g_strcmp0(key, "BonjourQuery")) {
469                         dbus_message_iter_recurse(&inter, &value);
470                         dbus_message_iter_get_fixed_array(&value,
471                                                         query, query_len);
472                 } else if (!g_strcmp0(key, "UpnpService")) {
473                         dbus_message_iter_get_basic(&inter, spec);
474                         *spec_len = strlen((const char *)*spec)+1;
475                 } else if (!g_strcmp0(key, "UpnpVersion")) {
476                         dbus_message_iter_get_basic(&inter, version);
477                 } else if (!g_strcmp0(key, "WiFiDisplayIEs")) {
478                         if (*spec || *query)
479                                 return -EINVAL;
480
481                         dbus_message_iter_recurse(&inter, &value);
482                         dbus_message_iter_get_fixed_array(&value,
483                                                         spec, spec_len);
484                 } else
485                         return -EINVAL;
486
487                 dbus_message_iter_next(array);
488         }
489
490         if ((*query && !*spec && !*version) ||
491                                 (!*spec && !*query) || (!*spec && *version))
492                 return -EINVAL;
493
494         return 0;
495 }
496
497 static DBusMessage *register_peer_service(DBusConnection *conn,
498                                                 DBusMessage *msg, void *data)
499 {
500         const unsigned char *spec, *query;
501         DBusMessageIter iter, array;
502         int spec_len, query_len;
503         dbus_bool_t master;
504         const char *owner;
505         int version;
506         int ret;
507
508         DBG("");
509
510         owner = dbus_message_get_sender(msg);
511
512         dbus_message_iter_init(msg, &iter);
513         dbus_message_iter_recurse(&iter, &array);
514
515         ret = parse_peers_service_specs(&array, &spec, &spec_len,
516                                                 &query, &query_len, &version);
517         if (ret)
518                 goto error;
519
520         dbus_message_iter_next(&iter);
521         dbus_message_iter_get_basic(&iter, &master);
522
523         ret = __connman_peer_service_register(owner, msg, spec, spec_len,
524                                         query, query_len, version,master);
525         if (!ret)
526                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
527         if (ret == -EINPROGRESS)
528                 return NULL;
529 error:
530         return __connman_error_failed(msg, -ret);
531 }
532
533 static DBusMessage *unregister_peer_service(DBusConnection *conn,
534                                                 DBusMessage *msg, void *data)
535 {
536         const unsigned char *spec, *query;
537         DBusMessageIter iter, array;
538         int spec_len, query_len;
539         const char *owner;
540         int version;
541         int ret;
542
543         DBG("");
544
545         owner = dbus_message_get_sender(msg);
546
547         dbus_message_iter_init(msg, &iter);
548         dbus_message_iter_recurse(&iter, &array);
549
550         ret = parse_peers_service_specs(&array, &spec, &spec_len,
551                                                 &query, &query_len, &version);
552         if (ret)
553                 goto error;
554
555         ret = __connman_peer_service_unregister(owner, spec, spec_len,
556                                                 query, query_len, version);
557         if (!ret)
558                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
559 error:
560         return __connman_error_failed(msg, -ret);
561
562 }
563
564 static const GDBusMethodTable manager_methods[] = {
565         { GDBUS_METHOD("GetProperties",
566                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
567                         get_properties) },
568         { GDBUS_ASYNC_METHOD("SetProperty",
569                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
570                         NULL, set_property) },
571         { GDBUS_METHOD("GetTechnologies",
572                         NULL, GDBUS_ARGS({ "technologies", "a(oa{sv})" }),
573                         get_technologies) },
574         { GDBUS_DEPRECATED_METHOD("RemoveProvider",
575                         GDBUS_ARGS({ "provider", "o" }), NULL,
576                         remove_provider) },
577         { GDBUS_METHOD("GetServices",
578                         NULL, GDBUS_ARGS({ "services", "a(oa{sv})" }),
579                         get_services) },
580         { GDBUS_METHOD("GetPeers",
581                         NULL, GDBUS_ARGS({ "peers", "a(oa{sv})" }),
582                         get_peers) },
583         { GDBUS_DEPRECATED_ASYNC_METHOD("ConnectProvider",
584                               GDBUS_ARGS({ "provider", "a{sv}" }),
585                               GDBUS_ARGS({ "path", "o" }),
586                               connect_provider) },
587         { GDBUS_METHOD("RegisterAgent",
588                         GDBUS_ARGS({ "path", "o" }), NULL,
589                         register_agent) },
590         { GDBUS_METHOD("UnregisterAgent",
591                         GDBUS_ARGS({ "path", "o" }), NULL,
592                         unregister_agent) },
593         { GDBUS_METHOD("RegisterCounter",
594                         GDBUS_ARGS({ "path", "o" }, { "accuracy", "u" },
595                                         { "period", "u" }),
596                         NULL, register_counter) },
597         { GDBUS_METHOD("UnregisterCounter",
598                         GDBUS_ARGS({ "path", "o" }), NULL,
599                         unregister_counter) },
600         { GDBUS_ASYNC_METHOD("CreateSession",
601                         GDBUS_ARGS({ "settings", "a{sv}" },
602                                                 { "notifier", "o" }),
603                         GDBUS_ARGS({ "session", "o" }),
604                         create_session) },
605         { GDBUS_METHOD("DestroySession",
606                         GDBUS_ARGS({ "session", "o" }), NULL,
607                         destroy_session) },
608         { GDBUS_ASYNC_METHOD("RequestPrivateNetwork",
609                               NULL, GDBUS_ARGS({ "path", "o" },
610                                                { "settings", "a{sv}" },
611                                                { "socket", "h" }),
612                               request_private_network) },
613         { GDBUS_METHOD("ReleasePrivateNetwork",
614                         GDBUS_ARGS({ "path", "o" }), NULL,
615                         release_private_network) },
616         { GDBUS_ASYNC_METHOD("RegisterPeerService",
617                         GDBUS_ARGS({ "specification", "a{sv}" },
618                                    { "master", "b" }), NULL,
619                         register_peer_service) },
620         { GDBUS_METHOD("UnregisterPeerService",
621                         GDBUS_ARGS({ "specification", "a{sv}" }), NULL,
622                         unregister_peer_service) },
623 #if defined TIZEN_EXT
624         { GDBUS_METHOD("GetVsies",
625                         NULL, GDBUS_ARGS({ "Vsie", "a(oa{sv})" }),
626                         get_wifi_vsies) },
627 #endif
628         { },
629 };
630
631 static const GDBusSignalTable manager_signals[] = {
632         { GDBUS_SIGNAL("PropertyChanged",
633                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
634         { GDBUS_SIGNAL("TechnologyAdded",
635                         GDBUS_ARGS({ "path", "o" },
636                                    { "properties", "a{sv}" })) },
637         { GDBUS_SIGNAL("TechnologyRemoved",
638                         GDBUS_ARGS({ "path", "o" })) },
639         { GDBUS_SIGNAL("ServicesChanged",
640                         GDBUS_ARGS({ "changed", "a(oa{sv})" },
641                                         { "removed", "ao" })) },
642         { GDBUS_SIGNAL("PeersChanged",
643                         GDBUS_ARGS({ "changed", "a(oa{sv})" },
644                                         { "removed", "ao" })) },
645         { },
646 };
647
648 int __connman_manager_init(void)
649 {
650         DBG("");
651
652         connection = connman_dbus_get_connection();
653         if (!connection)
654                 return -1;
655
656         if (connman_notifier_register(&technology_notifier) < 0)
657                 connman_error("Failed to register technology notifier");
658
659         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
660                                         CONNMAN_MANAGER_INTERFACE,
661                                         manager_methods,
662                                         manager_signals, NULL, NULL, NULL);
663
664         connman_state_idle = true;
665
666         return 0;
667 }
668
669 void __connman_manager_cleanup(void)
670 {
671         DBG("");
672
673         if (!connection)
674                 return;
675
676         connman_notifier_unregister(&technology_notifier);
677
678         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
679                                                 CONNMAN_MANAGER_INTERFACE);
680
681         dbus_connection_unref(connection);
682 }