1
/* NetworkManager -- Network link manager
3
* Dan Williams <dcbw@redhat.com>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
* (C) Copyright 2004 Red Hat, Inc.
23
#include <dbus/dbus-glib.h>
26
extern gboolean debug;
28
#include "NetworkManager.h"
29
#include "NetworkManagerUtils.h"
30
#include "NetworkManagerDevice.h"
31
#include "NetworkManagerDbus.h"
32
#include "NetworkManagerAP.h"
36
* nm_dbus_create_error_message
38
* Make a DBus error message
41
static DBusMessage *nm_dbus_create_error_message (DBusMessage *message, const char *exception_namespace,
42
const char *exception, const char *format, ...)
44
DBusMessage *reply_message;
49
va_start (args, format);
50
vsnprintf (error_text, 512, format, args);
53
char *exception_text = g_strdup_printf ("%s.%s", exception_namespace, exception);
54
reply_message = dbus_message_new_error (message, exception_text, error_text);
55
g_free (exception_text);
57
return (reply_message);
62
* nm_dbus_get_object_path_from_device
64
* Copies the object path for a device object into a provided buffer
67
void nm_dbus_get_object_path_from_device (NMDevice *dev, unsigned char *buf, unsigned int buf_len, gboolean lock_dev_list)
69
NMData *data = nm_get_global_data ();
71
g_return_if_fail (buf != NULL);
72
g_return_if_fail (buf_len > 0);
73
memset (buf, 0, buf_len);
75
g_return_if_fail (dev != NULL);
76
g_return_if_fail (data != NULL);
78
/* Iterate over device list */
79
if (!lock_dev_list || nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__))
81
NMDevice *list_dev = NULL;
82
GSList *element = data->dev_list;
87
list_dev = (NMDevice *)(element->data);
90
snprintf (buf, buf_len-1, "%s/%d", NM_DBUS_DEVICES_OBJECT_PATH_PREFIX, i);
95
element = g_slist_next (element);
99
nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__);
105
* nm_dbus_get_device_from_object_path
107
* Returns the device associated with a dbus object path
110
NMDevice *nm_dbus_get_device_from_object_path (const char *path, int *dev_index)
112
NMData *data = nm_get_global_data ();
113
NMDevice *dev = NULL;
117
g_return_val_if_fail (path != NULL, NULL);
118
g_return_val_if_fail (data != NULL, NULL);
121
* This function could be much more efficient, for example we could
122
* actually _parse_ the object path, but that's a lot more code and
123
* stupid stuff. The approach below is slower, less efficient, but
124
* less code and less error-prone.
127
/* Iterate over device list */
128
if (nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__))
130
GSList *element = data->dev_list;
131
char compare_path[100];
136
snprintf (compare_path, 100, "%s/%d", NM_DBUS_DEVICES_OBJECT_PATH_PREFIX, i);
138
/* Compare against our constructed path, but ignore any trailing elements */
139
dev = (NMDevice *)(element->data);
140
if (dev && (strncmp (path, compare_path, strlen (compare_path)) == 0))
149
element = g_slist_next (element);
151
nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__);
159
* nm_dbus_get_network_by_object_path
161
* Returns the network (ap) associated with a dbus object path
164
NMAccessPoint *nm_dbus_get_network_by_object_path (const char *path, NMDevice *dev, int dev_index, int *ap_index)
167
NMAccessPoint *ap = NULL;
169
char compare_path[100];
173
g_return_val_if_fail (path != NULL, NULL);
175
while (ap = nm_device_ap_list_get_ap (dev, i))
177
snprintf (compare_path, 100, "%s/%d/Networks/%d", NM_DBUS_DEVICES_OBJECT_PATH_PREFIX, dev_index, i);
178
if (strncmp (path, compare_path, strlen (compare_path)) == 0)
194
* nm_dbus_nm_get_active_device
196
* Returns the object path of the currently active device
199
static DBusMessage *nm_dbus_nm_get_active_device (DBusConnection *connection, DBusMessage *message)
201
DBusMessage *reply_message = NULL;
202
DBusMessageIter iter;
205
data = nm_get_global_data ();
208
/* If we can't get our global data, something is really wrong... */
209
reply_message = nm_dbus_create_error_message (message, NM_DBUS_NM_NAMESPACE, "NoGlobalData",
210
"NetworkManager couldn't get its global data.");
214
if (!data->active_device)
216
reply_message = dbus_message_new_method_return (message);
217
dbus_message_iter_init (reply_message, &iter);
218
dbus_message_iter_append_string (&iter, "");
223
/* Iterate over device list and grab index of "active device" */
224
if (nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__))
226
GSList *element = data->dev_list;
231
NMDevice *dev = (NMDevice *)(element->data);
233
if (dev && (dev == data->active_device))
235
char *object_path = g_strdup_printf ("%s/%d", NM_DBUS_DEVICES_OBJECT_PATH_PREFIX, i);
237
reply_message = dbus_message_new_method_return (message);
238
dbus_message_iter_init (reply_message, &iter);
239
dbus_message_iter_append_string (&iter, object_path);
240
g_free (object_path);
246
element = g_slist_next (element);
251
/* If the active device wasn't in the list, its been removed. */
252
reply_message = dbus_message_new_method_return (message);
253
dbus_message_iter_init (reply_message, &iter);
254
dbus_message_iter_append_string (&iter, "");
257
nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__);
261
reply_message = nm_dbus_create_error_message (message, NM_DBUS_NM_NAMESPACE, "Retry",
262
"NetworkManager could not lock device list, try again.");
266
return (reply_message);
271
* nm_dbus_nm_get_devices
273
* Returns a string array of object paths corresponding to the
274
* devices in the device list.
277
static DBusMessage *nm_dbus_nm_get_devices (DBusConnection *connection, DBusMessage *message)
279
DBusMessage *reply_message = NULL;
280
DBusMessageIter iter;
281
DBusMessageIter iter_array;
284
data = nm_get_global_data ();
287
/* If we can't get our global data, something is really wrong... */
288
reply_message = nm_dbus_create_error_message (message, NM_DBUS_NM_NAMESPACE, "NoGlobalData",
289
"NetworkManager couldn't get its global data.");
293
/* Check for no devices */
296
reply_message = dbus_message_new_method_return (message);
297
dbus_message_iter_init (reply_message, &iter);
298
dbus_message_iter_append_array (&iter, &iter_array, DBUS_TYPE_STRING);
299
dbus_message_iter_append_string (&iter_array, "");
304
/* Iterate over device list and grab index of "active device" */
305
if (nm_try_acquire_mutex (data->dev_list_mutex, __FUNCTION__))
307
GSList *element = data->dev_list;
309
gboolean appended = FALSE;
311
reply_message = dbus_message_new_method_return (message);
312
dbus_message_iter_init (reply_message, &iter);
313
dbus_message_iter_append_array (&iter, &iter_array, DBUS_TYPE_STRING);
317
NMDevice *dev = (NMDevice *)(element->data);
321
char *object_path = g_strdup_printf ("%s/%d", NM_DBUS_DEVICES_OBJECT_PATH_PREFIX, i);
322
dbus_message_iter_append_string (&iter_array, object_path);
323
g_free (object_path);
328
element = g_slist_next (element);
331
/* If by some chance there is a device list, but it has no devices in it
332
* (something which should never happen), append an empty string like
333
* there are no devices in the list.
336
dbus_message_iter_append_string (&iter_array, "");
338
nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__);
342
reply_message = nm_dbus_create_error_message (message, NM_DBUS_NM_NAMESPACE, "Retry",
343
"NetworkManager could not lock device list, try again.");
347
return (reply_message);
351
/*-------------------------------------------------------------*/
353
/*-------------------------------------------------------------*/
357
* nm_dbus_signal_device_no_longer_active
359
* Notifies the bus that a particular device is no longer active.
362
void nm_dbus_signal_device_no_longer_active (DBusConnection *connection, NMDevice *dev)
364
DBusMessage *message;
365
unsigned char *object_path = g_new0 (unsigned char, 100);
367
g_return_if_fail (object_path != NULL);
369
message = dbus_message_new_signal (NM_DBUS_NM_OBJECT_PATH_PREFIX, NM_DBUS_NM_NAMESPACE, "DeviceNoLongerActive");
372
NM_DEBUG_PRINT ("nm_dbus_signal_device_no_longer_active(): Not enough memory for new dbus message!\n");
375
nm_dbus_get_object_path_from_device (dev, object_path, 100, FALSE);
376
dbus_message_append_args (message, DBUS_TYPE_STRING, object_path, DBUS_TYPE_INVALID);
377
g_free (object_path);
379
if (!dbus_connection_send (connection, message, NULL))
380
NM_DEBUG_PRINT ("nm_dbus_signal_device_no_longer_active(): Could not raise the DeviceNoLongerActive signal!\n");
382
dbus_message_unref (message);
387
* nm_dbus_signal_device_now_active
389
* Notifies the bus that a particular device is newly active.
392
void nm_dbus_signal_device_now_active (DBusConnection *connection, NMDevice *dev)
394
DBusMessage *message;
395
unsigned char *object_path = g_new0 (unsigned char, 100);
397
message = dbus_message_new_signal (NM_DBUS_NM_OBJECT_PATH_PREFIX, NM_DBUS_NM_NAMESPACE, "DeviceNowActive");
400
NM_DEBUG_PRINT ("nm_dbus_signal_device_now_active(): Not enough memory for new dbus message!\n");
403
nm_dbus_get_object_path_from_device (dev, object_path, 100, FALSE);
404
dbus_message_append_args (message, DBUS_TYPE_STRING, object_path, DBUS_TYPE_INVALID);
405
g_free (object_path);
407
if (!dbus_connection_send (connection, message, NULL))
408
NM_DEBUG_PRINT ("nm_dbus_signal_device_now_active(): Could not raise the DeviceNowActive signal!\n");
410
dbus_message_unref (message);
415
* nm_dbus_devices_handle_networks_request
417
* Converts a property request on a _network_ into a dbus message.
420
static DBusMessage *nm_dbus_devices_handle_networks_request (DBusConnection *connection, DBusMessage *message,
421
const char *path, const char *request, NMDevice *dev, int dev_index)
424
DBusMessage *reply_message = NULL;
425
DBusMessageIter iter;
428
ap = nm_dbus_get_network_by_object_path (path, dev, dev_index, &ap_index);
429
if (!ap || (ap_index == -1))
431
reply_message = nm_dbus_create_error_message (message, NM_DBUS_NM_NAMESPACE, "NetworkNotFound",
432
"The requested network does not exist for this device.");
433
return (reply_message);
436
reply_message = dbus_message_new_method_return (message);
437
dbus_message_iter_init (reply_message, &iter);
439
if (strcmp ("getName", request) == 0)
440
dbus_message_iter_append_string (&iter, nm_ap_get_essid (ap));
441
else if (strcmp ("getAddress", request) == 0)
442
dbus_message_iter_append_string (&iter, nm_ap_get_address (ap));
443
else if (strcmp ("getQuality", request) == 0)
444
dbus_message_iter_append_int32 (&iter, nm_ap_get_quality (ap));
445
else if (strcmp ("getFrequency", request) == 0)
446
dbus_message_iter_append_double (&iter, nm_ap_get_freq (ap));
447
else if (strcmp ("getRate", request) == 0)
448
dbus_message_iter_append_int32 (&iter, nm_ap_get_rate (ap));
449
else if (strcmp ("getStamp", request) == 0)
450
dbus_message_iter_append_int32 (&iter, nm_ap_get_stamp (ap));
453
/* Must destroy the allocated message */
454
dbus_message_unref (reply_message);
456
reply_message = nm_dbus_create_error_message (message, NM_DBUS_NM_NAMESPACE, "UnknownMethod",
457
"NetworkManager knows nothing about the method %s for object %s", request, path);
460
return (reply_message);
465
* nm_dbus_devices_handle_request
467
* Converts a property request into a dbus message.
470
static DBusMessage *nm_dbus_devices_handle_request (DBusConnection *connection, DBusMessage *message, const char *path, const char *request)
473
DBusMessage *reply_message = NULL;
474
DBusMessageIter iter;
478
dev = nm_dbus_get_device_from_object_path (path, &dev_index);
479
if (!dev || (dev_index == -1))
481
reply_message = nm_dbus_create_error_message (message, NM_DBUS_NM_NAMESPACE, "DeviceNotFound",
482
"The requested network device does not exist.");
483
return (reply_message);
486
/* Test whether or not the _networks_ of a device were queried instead of the device itself */
487
object_path = g_strdup_printf ("%s/%d/Networks/", NM_DBUS_DEVICES_OBJECT_PATH_PREFIX, dev_index);
488
if (strncmp (path, object_path, strlen (object_path)) == 0)
491
reply_message = nm_dbus_devices_handle_networks_request (connection, message, path, request, dev, dev_index);
492
return (reply_message);
496
reply_message = dbus_message_new_method_return (message);
497
dbus_message_iter_init (reply_message, &iter);
499
if (strcmp ("getName", request) == 0)
500
dbus_message_iter_append_string (&iter, nm_device_get_iface (dev));
501
else if (strcmp ("getType", request) == 0)
502
dbus_message_iter_append_int32 (&iter, nm_device_get_iface_type (dev));
503
else if (strcmp ("getActiveNetwork", request) == 0)
505
NMAccessPoint *ap = NULL;
508
while (ap = nm_device_ap_list_get_ap (dev, i))
510
if (nm_null_safe_strcmp (nm_ap_get_essid (ap), nm_device_get_essid (dev)) == 0)
512
object_path = g_strdup_printf ("%s/%d/Networks/%d", NM_DBUS_DEVICES_OBJECT_PATH_PREFIX, dev_index, i);
513
dbus_message_iter_append_string (&iter, object_path);
514
g_free (object_path);
521
/* If we didn't find the devices current network among the known networks, just append a blank item */
523
dbus_message_iter_append_string (&iter, "");
525
else if (strcmp ("getNetworks", request) == 0)
527
DBusMessageIter iter_array;
528
NMAccessPoint *ap = NULL;
531
dbus_message_iter_append_array (&iter, &iter_array, DBUS_TYPE_STRING);
533
while (ap = nm_device_ap_list_get_ap (dev, i))
535
object_path = g_strdup_printf ("%s/%d/Networks/%d", NM_DBUS_DEVICES_OBJECT_PATH_PREFIX, dev_index, i);
536
dbus_message_iter_append_string (&iter_array, object_path);
537
g_free (object_path);
544
/* Must destroy the allocated message */
545
dbus_message_unref (reply_message);
547
reply_message = nm_dbus_create_error_message (message, NM_DBUS_NM_NAMESPACE, "UnknownMethod",
548
"NetworkManager knows nothing about the method %s for object %s", request, path);
551
return (reply_message);
556
* nm_dbus_nm_message_handler
558
* Dispatch messages against our NetworkManager object
561
static DBusHandlerResult nm_dbus_nm_message_handler (DBusConnection *connection, DBusMessage *message, void *user_data)
565
DBusMessage *reply_message = NULL;
567
method = dbus_message_get_member (message);
568
path = dbus_message_get_path (message);
570
NM_DEBUG_PRINT_2 ("nm_dbus_devices_message_handler() got method %s for path %s\n", method, path);
572
if (strcmp ("getActiveDevice", method) == 0)
574
reply_message = nm_dbus_nm_get_active_device (connection, message);
576
else if (strcmp ("getDevices", method) == 0)
578
reply_message = nm_dbus_nm_get_devices (connection, message);
582
reply_message = nm_dbus_create_error_message (message, NM_DBUS_NM_NAMESPACE, "UnknownMethod",
583
"NetworkManager knows nothing about the method %s for object %s", method, path);
586
dbus_connection_send (connection, reply_message, NULL);
588
return DBUS_HANDLER_RESULT_HANDLED;
593
* nm_dbus_nm_unregister_handler
595
* Nothing happens here.
598
void nm_dbus_nm_unregister_handler (DBusConnection *connection, void *user_data)
605
* nm_dbus_devices_message_handler
607
* Dispatch messages against individual network devices
610
static DBusHandlerResult nm_dbus_devices_message_handler (DBusConnection *connection, DBusMessage *message, void *user_data)
614
DBusMessage *reply_message = NULL;
616
method = dbus_message_get_member (message);
617
path = dbus_message_get_path (message);
619
/* NM_DEBUG_PRINT_2 ("nm_dbus_nm_message_handler() got method %s for path %s\n", method, path); */
621
reply_message = nm_dbus_devices_handle_request (connection, message, path, method);
622
dbus_connection_send (connection, reply_message, NULL);
624
return DBUS_HANDLER_RESULT_HANDLED;
629
* nm_dbus_devices_unregister_handler
631
* Nothing happens here.
634
void nm_dbus_devices_unregister_handler (DBusConnection *connection, void *user_data)
643
* Connect to the system messagebus and register ourselves as a service.
646
DBusConnection *nm_dbus_init (void)
648
DBusError dbus_error;
650
DBusConnection *dbus_connection;
651
DBusObjectPathVTable nm_vtable = { &nm_dbus_nm_unregister_handler, &nm_dbus_nm_message_handler, NULL, NULL, NULL, NULL };
652
const char *nm_path[] = { "org", "freedesktop", "NetworkManager", NULL };
653
DBusObjectPathVTable devices_vtable = { &nm_dbus_devices_unregister_handler, &nm_dbus_devices_message_handler, NULL, NULL, NULL, NULL };
654
const char *devices_path[] = { "org", "freedesktop", "NetworkManager", "Devices", NULL };
656
dbus_connection_set_change_sigpipe (TRUE);
658
dbus_error_init (&dbus_error);
659
dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error);
660
if (dbus_connection == NULL)
662
NM_DEBUG_PRINT ("nm_dbus_init() could not get the system bus. Make sure the message bus daemon is running?\n");
666
dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
667
dbus_connection_setup_with_g_main (dbus_connection, NULL);
668
dbus_bus_acquire_service (dbus_connection, NM_DBUS_NM_NAMESPACE, 0, &dbus_error);
669
if (dbus_error_is_set (&dbus_error))
671
NM_DEBUG_PRINT_1 ("nm_dbus_init() could not acquire its service. dbus_bus_acquire_service() says: '%s'\n", dbus_error.message);
675
success = dbus_connection_register_object_path (dbus_connection, nm_path, &nm_vtable, NULL);
678
NM_DEBUG_PRINT ("nm_dbus_init() could not register a handler for NetworkManager. Not enough memory?\n");
682
success = dbus_connection_register_fallback (dbus_connection, devices_path, &devices_vtable, NULL);
685
NM_DEBUG_PRINT ("nm_dbus_init() could not register a handler for NetworkManager devices. Not enough memory?\n");
689
return (dbus_connection);