~ubuntu-branches/ubuntu/vivid/wpasupplicant/vivid

« back to all changes in this revision

Viewing changes to wpa_supplicant/ctrl_iface_dbus.c

  • Committer: Bazaar Package Importer
  • Author(s): Kel Modderman
  • Date: 2008-03-12 20:03:04 UTC
  • mfrom: (1.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080312200304-4331y9wj46pdd34z
Tags: 0.6.3-1
* New upstream release.
* Drop patches applied upstream:
  - debian/patches/30_wpa_gui_qt4_eventhistoryui_rework.patch
  - debian/patches/31_wpa_gui_qt4_eventhistory_always_scrollbar.patch
  - debian/patches/32_wpa_gui_qt4_eventhistory_scroll_with_events.patch
  - debian/patches/40_dbus_ssid_data.patch
* Tidy up the clean target of debian/rules. Now that the madwifi headers are
  handled differently we no longer need to do any cleanup.
* Fix formatting error in debian/ifupdown/wpa_action.8 to make lintian
  quieter.
* Add patch to fix formatting errors in manpages build from sgml source. Use
  <emphasis> tags to hightlight keywords instead of surrounding them in
  strong quotes.
  - debian/patches/41_manpage_format_fixes.patch
* wpasupplicant binary package no longer suggests pcscd, guessnet, iproute
  or wireless-tools, nor does it recommend dhcp3-client. These are not
  needed.
* Add debian/patches/10_silence_siocsiwauth_icotl_failure.patch to disable
  ioctl failure messages that occur under normal conditions.
* Cherry pick two upstream git commits concerning the dbus interface:
  - debian/patches/11_avoid_dbus_version_namespace.patch
  - debian/patches/12_fix_potential_use_after_free.patch
* Add debian/patches/42_manpage_explain_available_drivers.patch to explain
  that not all of the driver backends are available in the provided
  wpa_supplicant binary, and that the canonical list of supported driver
  backends can be retrieved from the wpa_supplicant -h (help) output.
  (Closes: #466910)
* Add debian/patches/20_wpa_gui_qt4_disable_link_prl.patch to remove
  link_prl CONFIG compile flag added by qmake-qt4 >= 4.3.4-2 to avoid excess
  linking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * WPA Supplicant / dbus-based control interface
 
3
 * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License version 2 as
 
7
 * published by the Free Software Foundation.
 
8
 *
 
9
 * Alternatively, this software may be distributed under the terms of BSD
 
10
 * license.
 
11
 *
 
12
 * See README and COPYING for more details.
 
13
 */
 
14
 
 
15
#include "includes.h"
 
16
 
 
17
#include "common.h"
 
18
#include "eloop.h"
 
19
#include "config.h"
 
20
#include "wpa_supplicant_i.h"
 
21
#include "ctrl_iface_dbus.h"
 
22
#include "ctrl_iface_dbus_handlers.h"
 
23
 
 
24
#define DBUS_VERSION (DBUS_VERSION_MAJOR << 8 | DBUS_VERSION_MINOR)
 
25
#define DBUS_VER(major, minor) ((major) << 8 | (minor))
 
26
 
 
27
#if DBUS_VERSION < DBUS_VER(1,1)
 
28
#define dbus_watch_get_unix_fd dbus_watch_get_fd
 
29
#endif
 
30
 
 
31
 
 
32
struct ctrl_iface_dbus_priv {
 
33
        DBusConnection *con;
 
34
        int should_dispatch;
 
35
        struct wpa_global *global;
 
36
 
 
37
        u32 next_objid;
 
38
};
 
39
 
 
40
 
 
41
static void process_watch(struct ctrl_iface_dbus_priv *iface,
 
42
                          DBusWatch *watch, eloop_event_type type)
 
43
{
 
44
        dbus_connection_ref(iface->con);
 
45
 
 
46
        iface->should_dispatch = 0;
 
47
 
 
48
        if (type == EVENT_TYPE_READ)
 
49
                dbus_watch_handle(watch, DBUS_WATCH_READABLE);
 
50
        else if (type == EVENT_TYPE_WRITE)
 
51
                dbus_watch_handle(watch, DBUS_WATCH_WRITABLE);
 
52
        else if (type == EVENT_TYPE_EXCEPTION)
 
53
                dbus_watch_handle(watch, DBUS_WATCH_ERROR);
 
54
 
 
55
        if (iface->should_dispatch) {
 
56
                while (dbus_connection_get_dispatch_status(iface->con) ==
 
57
                       DBUS_DISPATCH_DATA_REMAINS)
 
58
                        dbus_connection_dispatch(iface->con);
 
59
                iface->should_dispatch = 0;
 
60
        }
 
61
 
 
62
        dbus_connection_unref(iface->con);
 
63
}
 
64
 
 
65
 
 
66
static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx)
 
67
{
 
68
        process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION);
 
69
}
 
70
 
 
71
 
 
72
static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx)
 
73
{
 
74
        process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ);
 
75
}
 
76
 
 
77
 
 
78
static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx)
 
79
{
 
80
        process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE);
 
81
}
 
82
 
 
83
 
 
84
static void connection_setup_add_watch(struct ctrl_iface_dbus_priv *iface,
 
85
                                       DBusWatch *watch)
 
86
{
 
87
        unsigned int flags;
 
88
        int fd;
 
89
 
 
90
        if (!dbus_watch_get_enabled(watch))
 
91
                return;
 
92
 
 
93
        flags = dbus_watch_get_flags(watch);
 
94
        fd = dbus_watch_get_unix_fd(watch);
 
95
 
 
96
        eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception,
 
97
                            iface, watch);
 
98
 
 
99
        if (flags & DBUS_WATCH_READABLE) {
 
100
                eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
 
101
                                    iface, watch);
 
102
        }
 
103
        if (flags & DBUS_WATCH_WRITABLE) {
 
104
                eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
 
105
                                    iface, watch);
 
106
        }
 
107
 
 
108
        dbus_watch_set_data(watch, iface, NULL);
 
109
}
 
110
 
 
111
 
 
112
static void connection_setup_remove_watch(struct ctrl_iface_dbus_priv *iface,
 
113
                                          DBusWatch *watch)
 
114
{
 
115
        unsigned int flags;
 
116
        int fd;
 
117
 
 
118
        flags = dbus_watch_get_flags(watch);
 
119
        fd = dbus_watch_get_unix_fd(watch);
 
120
 
 
121
        eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION);
 
122
 
 
123
        if (flags & DBUS_WATCH_READABLE)
 
124
                eloop_unregister_sock(fd, EVENT_TYPE_READ);
 
125
        if (flags & DBUS_WATCH_WRITABLE)
 
126
                eloop_unregister_sock(fd, EVENT_TYPE_WRITE);
 
127
 
 
128
        dbus_watch_set_data(watch, NULL, NULL);
 
129
}
 
130
 
 
131
 
 
132
static dbus_bool_t add_watch(DBusWatch *watch, void *data)
 
133
{
 
134
        connection_setup_add_watch(data, watch);
 
135
        return TRUE;
 
136
}
 
137
 
 
138
 
 
139
static void remove_watch(DBusWatch *watch, void *data)
 
140
{
 
141
        connection_setup_remove_watch(data, watch);
 
142
}
 
143
 
 
144
 
 
145
static void watch_toggled(DBusWatch *watch, void *data)
 
146
{
 
147
        if (dbus_watch_get_enabled(watch))
 
148
                add_watch(watch, data);
 
149
        else
 
150
                remove_watch(watch, data);
 
151
}
 
152
 
 
153
 
 
154
static void process_timeout(void *eloop_ctx, void *sock_ctx)
 
155
{
 
156
        DBusTimeout *timeout = sock_ctx;
 
157
 
 
158
        dbus_timeout_handle(timeout);
 
159
}
 
160
 
 
161
 
 
162
static void connection_setup_add_timeout(struct ctrl_iface_dbus_priv *iface,
 
163
                                         DBusTimeout *timeout)
 
164
{
 
165
        if (!dbus_timeout_get_enabled(timeout))
 
166
                return;
 
167
 
 
168
        eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000,
 
169
                               process_timeout, iface, timeout);
 
170
 
 
171
        dbus_timeout_set_data(timeout, iface, NULL);
 
172
}
 
173
 
 
174
 
 
175
static void connection_setup_remove_timeout(struct ctrl_iface_dbus_priv *iface,
 
176
                                            DBusTimeout *timeout)
 
177
{
 
178
        eloop_cancel_timeout(process_timeout, iface, timeout);
 
179
        dbus_timeout_set_data(timeout, NULL, NULL);
 
180
}
 
181
 
 
182
 
 
183
static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
 
184
{
 
185
        if (!dbus_timeout_get_enabled(timeout))
 
186
                return TRUE;
 
187
 
 
188
        connection_setup_add_timeout(data, timeout);
 
189
 
 
190
        return TRUE;
 
191
}
 
192
 
 
193
 
 
194
static void remove_timeout(DBusTimeout *timeout, void *data)
 
195
{
 
196
        connection_setup_remove_timeout(data, timeout);
 
197
}
 
198
 
 
199
 
 
200
static void timeout_toggled(DBusTimeout *timeout, void *data)
 
201
{
 
202
        if (dbus_timeout_get_enabled(timeout))
 
203
                add_timeout(timeout, data);
 
204
        else
 
205
                remove_timeout(timeout, data);
 
206
}
 
207
 
 
208
 
 
209
static void process_wakeup_main(int sig, void *eloop_ctx, void *signal_ctx)
 
210
{
 
211
        struct ctrl_iface_dbus_priv *iface = signal_ctx;
 
212
 
 
213
        if (sig != SIGPOLL || !iface->con)
 
214
                return;
 
215
 
 
216
        if (dbus_connection_get_dispatch_status(iface->con) !=
 
217
            DBUS_DISPATCH_DATA_REMAINS)
 
218
                return;
 
219
 
 
220
        /* Only dispatch once - we do not want to starve other events */
 
221
        dbus_connection_ref(iface->con);
 
222
        dbus_connection_dispatch(iface->con);
 
223
        dbus_connection_unref(iface->con);
 
224
}
 
225
 
 
226
 
 
227
/**
 
228
 * wakeup_main - Attempt to wake our mainloop up
 
229
 * @data: dbus control interface private data
 
230
 *
 
231
 * Try to wake up the main eloop so it will process
 
232
 * dbus events that may have happened.
 
233
 */
 
234
static void wakeup_main(void *data)
 
235
{
 
236
        struct ctrl_iface_dbus_priv *iface = data;
 
237
 
 
238
        /* Use SIGPOLL to break out of the eloop select() */
 
239
        raise(SIGPOLL);
 
240
        iface->should_dispatch = 1;
 
241
}
 
242
 
 
243
 
 
244
/**
 
245
 * connection_setup_wakeup_main - Tell dbus about our wakeup_main function
 
246
 * @iface: dbus control interface private data
 
247
 * Returns: 0 on success, -1 on failure
 
248
 *
 
249
 * Register our wakeup_main handler with dbus
 
250
 */
 
251
static int connection_setup_wakeup_main(struct ctrl_iface_dbus_priv *iface)
 
252
{
 
253
        if (eloop_register_signal(SIGPOLL, process_wakeup_main, iface))
 
254
                return -1;
 
255
 
 
256
        dbus_connection_set_wakeup_main_function(iface->con, wakeup_main,
 
257
                                                 iface, NULL);
 
258
 
 
259
        return 0;
 
260
}
 
261
 
 
262
 
 
263
/**
 
264
 * wpa_supplicant_dbus_next_objid - Return next available object id
 
265
 * @iface: dbus control interface private data
 
266
 * Returns: Object id
 
267
 */
 
268
u32 wpa_supplicant_dbus_next_objid (struct ctrl_iface_dbus_priv *iface)
 
269
{
 
270
        return iface->next_objid++;
 
271
}
 
272
 
 
273
 
 
274
/**
 
275
 * wpas_dbus_decompose_object_path - Decompose an interface object path into parts
 
276
 * @path: The dbus object path
 
277
 * @network: (out) the configured network this object path refers to, if any
 
278
 * @bssid: (out) the scanned bssid this object path refers to, if any
 
279
 * Returns: The object path of the network interface this path refers to
 
280
 *
 
281
 * For a given object path, decomposes the object path into object id, network,
 
282
 * and BSSID parts, if those parts exist.
 
283
 */
 
284
char * wpas_dbus_decompose_object_path(const char *path, char **network,
 
285
                                       char **bssid)
 
286
{
 
287
        const unsigned int dev_path_prefix_len =
 
288
                strlen(WPAS_DBUS_PATH_INTERFACES "/");
 
289
        char *obj_path_only;
 
290
        char *next_sep;
 
291
 
 
292
        /* Be a bit paranoid about path */
 
293
        if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/",
 
294
                             dev_path_prefix_len))
 
295
                return NULL;
 
296
 
 
297
        /* Ensure there's something at the end of the path */
 
298
        if ((path + dev_path_prefix_len)[0] == '\0')
 
299
                return NULL;
 
300
 
 
301
        obj_path_only = strdup(path);
 
302
        if (obj_path_only == NULL)
 
303
                return NULL;
 
304
 
 
305
        next_sep = strchr(obj_path_only + dev_path_prefix_len, '/');
 
306
        if (next_sep != NULL) {
 
307
                const char *net_part = strstr(next_sep,
 
308
                                              WPAS_DBUS_NETWORKS_PART "/");
 
309
                const char *bssid_part = strstr(next_sep,
 
310
                                                WPAS_DBUS_BSSIDS_PART "/");
 
311
 
 
312
                if (network && net_part) {
 
313
                        /* Deal with a request for a configured network */
 
314
                        const char *net_name = net_part +
 
315
                                strlen(WPAS_DBUS_NETWORKS_PART "/");
 
316
                        *network = NULL;
 
317
                        if (strlen(net_name))
 
318
                                *network = strdup(net_name);
 
319
                } else if (bssid && bssid_part) {
 
320
                        /* Deal with a request for a scanned BSSID */
 
321
                        const char *bssid_name = bssid_part +
 
322
                                strlen(WPAS_DBUS_BSSIDS_PART "/");
 
323
                        if (strlen(bssid_name))
 
324
                                *bssid = strdup(bssid_name);
 
325
                        else
 
326
                                *bssid = NULL;
 
327
                }
 
328
 
 
329
                /* Cut off interface object path before "/" */
 
330
                *next_sep = '\0';
 
331
        }
 
332
 
 
333
        return obj_path_only;
 
334
}
 
335
 
 
336
 
 
337
/**
 
338
 * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message
 
339
 * @message: Pointer to incoming dbus message this error refers to
 
340
 * Returns: A dbus error message
 
341
 *
 
342
 * Convenience function to create and return an invalid interface error
 
343
 */
 
344
DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
 
345
{
 
346
        return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE,
 
347
                                      "wpa_supplicant knows nothing about "
 
348
                                      "this interface.");
 
349
}
 
350
 
 
351
 
 
352
/**
 
353
 * wpas_dbus_new_invalid_network_error - Return a new invalid network error message
 
354
 * @message: Pointer to incoming dbus message this error refers to
 
355
 * Returns: a dbus error message
 
356
 *
 
357
 * Convenience function to create and return an invalid network error
 
358
 */
 
359
DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message)
 
360
{
 
361
        return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK,
 
362
                                      "The requested network does not exist.");
 
363
}
 
364
 
 
365
 
 
366
/**
 
367
 * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message
 
368
 * @message: Pointer to incoming dbus message this error refers to
 
369
 * Returns: a dbus error message
 
370
 *
 
371
 * Convenience function to create and return an invalid bssid error
 
372
 */
 
373
static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message)
 
374
{
 
375
        return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID,
 
376
                                      "The BSSID requested was invalid.");
 
377
}
 
378
 
 
379
 
 
380
/**
 
381
 * wpas_dispatch_network_method - dispatch messages for configured networks
 
382
 * @message: the incoming dbus message
 
383
 * @wpa_s: a network interface's data
 
384
 * @network_id: id of the configured network we're interested in
 
385
 * Returns: a reply dbus message, or a dbus error message
 
386
 *
 
387
 * This function dispatches all incoming dbus messages for configured networks.
 
388
 */
 
389
static DBusMessage * wpas_dispatch_network_method(DBusMessage *message,
 
390
                                                  struct wpa_supplicant *wpa_s,
 
391
                                                  int network_id)
 
392
{
 
393
        DBusMessage *reply = NULL;
 
394
        const char *method = dbus_message_get_member(message);
 
395
        struct wpa_ssid *ssid;
 
396
 
 
397
        ssid = wpa_config_get_network(wpa_s->conf, network_id);
 
398
        if (ssid == NULL)
 
399
                return wpas_dbus_new_invalid_network_error(message);
 
400
 
 
401
        if (!strcmp(method, "set"))
 
402
                reply = wpas_dbus_iface_set_network(message, wpa_s, ssid);
 
403
        else if (!strcmp(method, "enable"))
 
404
                reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid);
 
405
        else if (!strcmp(method, "disable"))
 
406
                reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid);
 
407
 
 
408
        return reply;
 
409
}
 
410
 
 
411
 
 
412
/**
 
413
 * wpas_dispatch_bssid_method - dispatch messages for scanned networks
 
414
 * @message: the incoming dbus message
 
415
 * @wpa_s: a network interface's data
 
416
 * @bssid: bssid of the scanned network we're interested in
 
417
 * Returns: a reply dbus message, or a dbus error message
 
418
 *
 
419
 * This function dispatches all incoming dbus messages for scanned networks.
 
420
 */
 
421
static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message,
 
422
                                                struct wpa_supplicant *wpa_s,
 
423
                                                const char *bssid)
 
424
{
 
425
        DBusMessage *reply = NULL;
 
426
        const char *method = dbus_message_get_member(message);
 
427
        struct wpa_scan_res *res = NULL;
 
428
        size_t i;
 
429
 
 
430
        /* Ensure we actually have scan data */
 
431
        if (wpa_s->scan_res == NULL &&
 
432
            wpa_supplicant_get_scan_results(wpa_s) < 0) {
 
433
                reply = wpas_dbus_new_invalid_bssid_error(message);
 
434
                goto out;
 
435
        }
 
436
 
 
437
        /* Find the bssid's scan data */
 
438
        for (i = 0; i < wpa_s->scan_res->num; i++) {
 
439
                struct wpa_scan_res *search_res = wpa_s->scan_res->res[i];
 
440
                char mac_str[18];
 
441
 
 
442
                memset(mac_str, 0, sizeof(mac_str));
 
443
                snprintf(mac_str, sizeof(mac_str) - 1, WPAS_DBUS_BSSID_FORMAT,
 
444
                         MAC2STR(search_res->bssid));
 
445
                if (!strcmp(bssid, mac_str)) {
 
446
                        res = search_res;
 
447
                        break;
 
448
                }
 
449
        }
 
450
 
 
451
        if (!res) {
 
452
                reply = wpas_dbus_new_invalid_bssid_error(message);
 
453
                goto out;
 
454
        }
 
455
 
 
456
        /* Dispatch the method call against the scanned bssid */
 
457
        if (!strcmp(method, "properties"))
 
458
                reply = wpas_dbus_bssid_properties(message, wpa_s, res);
 
459
 
 
460
out:
 
461
        return reply;
 
462
}
 
463
 
 
464
 
 
465
/**
 
466
 * wpas_iface_message_handler - Dispatch messages for interfaces or networks
 
467
 * @connection: Connection to the system message bus
 
468
 * @message: An incoming dbus message
 
469
 * @user_data: A pointer to a dbus control interface data structure
 
470
 * Returns: Whether or not the message was handled
 
471
 *
 
472
 * This function dispatches all incoming dbus messages for network interfaces,
 
473
 * or objects owned by them, such as scanned BSSIDs and configured networks.
 
474
 */
 
475
static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
 
476
                                                    DBusMessage *message,
 
477
                                                    void *user_data)
 
478
{
 
479
        struct wpa_supplicant *wpa_s = user_data;
 
480
        const char *method = dbus_message_get_member(message);
 
481
        const char *path = dbus_message_get_path(message);
 
482
        const char *msg_interface = dbus_message_get_interface(message);
 
483
        char *iface_obj_path = NULL;
 
484
        char *network = NULL;
 
485
        char *bssid = NULL;
 
486
        DBusMessage *reply = NULL;
 
487
 
 
488
        /* Caller must specify a message interface */
 
489
        if (!msg_interface)
 
490
                goto out;
 
491
 
 
492
        iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
 
493
                                                         &bssid);
 
494
        if (iface_obj_path == NULL) {
 
495
                reply = wpas_dbus_new_invalid_iface_error(message);
 
496
                goto out;
 
497
        }
 
498
 
 
499
        /* Make sure the message's object path actually refers to the
 
500
         * wpa_supplicant structure it's supposed to (which is wpa_s)
 
501
         */
 
502
        if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
 
503
                                                  iface_obj_path) != wpa_s) {
 
504
                reply = wpas_dbus_new_invalid_iface_error(message);
 
505
                goto out;
 
506
        }
 
507
 
 
508
        if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
 
509
                /* A method for one of this interface's configured networks */
 
510
                int nid = strtoul(network, NULL, 10);
 
511
                if (errno != EINVAL)
 
512
                        reply = wpas_dispatch_network_method(message, wpa_s,
 
513
                                                             nid);
 
514
                else
 
515
                        reply = wpas_dbus_new_invalid_network_error(message);
 
516
        } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) {
 
517
                /* A method for one of this interface's scanned BSSIDs */
 
518
                reply = wpas_dispatch_bssid_method(message, wpa_s, bssid);
 
519
        } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) {
 
520
                /* A method for an interface only. */
 
521
                if (!strcmp(method, "scan"))
 
522
                        reply = wpas_dbus_iface_scan(message, wpa_s);
 
523
                else if (!strcmp(method, "scanResults"))
 
524
                        reply = wpas_dbus_iface_scan_results(message, wpa_s);
 
525
                else if (!strcmp(method, "addNetwork"))
 
526
                        reply = wpas_dbus_iface_add_network(message, wpa_s);
 
527
                else if (!strcmp(method, "removeNetwork"))
 
528
                        reply = wpas_dbus_iface_remove_network(message, wpa_s);
 
529
                else if (!strcmp(method, "selectNetwork"))
 
530
                        reply = wpas_dbus_iface_select_network(message, wpa_s);
 
531
                else if (!strcmp(method, "capabilities"))
 
532
                        reply = wpas_dbus_iface_capabilities(message, wpa_s);
 
533
                else if (!strcmp(method, "disconnect"))
 
534
                        reply = wpas_dbus_iface_disconnect(message, wpa_s);
 
535
                else if (!strcmp(method, "setAPScan"))
 
536
                        reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
 
537
                else if (!strcmp(method, "state"))
 
538
                        reply = wpas_dbus_iface_get_state(message, wpa_s);
 
539
                else if (!strcmp(method, "setBlobs"))
 
540
                        reply = wpas_dbus_iface_set_blobs(message, wpa_s);
 
541
                else if (!strcmp(method, "removeBlobs"))
 
542
                        reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
 
543
        }
 
544
 
 
545
        /* If the message was handled, send back the reply */
 
546
        if (reply) {
 
547
                dbus_connection_send(connection, reply, NULL);
 
548
                dbus_message_unref(reply);
 
549
        }
 
550
 
 
551
out:
 
552
        free(iface_obj_path);
 
553
        free(network);
 
554
        free(bssid);
 
555
        return reply ? DBUS_HANDLER_RESULT_HANDLED :
 
556
                DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
557
}
 
558
 
 
559
 
 
560
/**
 
561
 * wpas_message_handler - dispatch incoming dbus messages
 
562
 * @connection: connection to the system message bus
 
563
 * @message: an incoming dbus message
 
564
 * @user_data: a pointer to a dbus control interface data structure
 
565
 * Returns: whether or not the message was handled
 
566
 *
 
567
 * This function dispatches all incoming dbus messages to the correct
 
568
 * handlers, depending on what the message's target object path is,
 
569
 * and what the method call is.
 
570
 */
 
571
static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
 
572
        DBusMessage *message, void *user_data)
 
573
{
 
574
        struct ctrl_iface_dbus_priv *ctrl_iface = user_data;
 
575
        const char *method;
 
576
        const char *path;
 
577
        const char *msg_interface;
 
578
        DBusMessage *reply = NULL;
 
579
 
 
580
        method = dbus_message_get_member(message);
 
581
        path = dbus_message_get_path(message);
 
582
        msg_interface = dbus_message_get_interface(message);
 
583
        if (!method || !path || !ctrl_iface || !msg_interface)
 
584
                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
585
 
 
586
        /* Validate the method interface */
 
587
        if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
 
588
                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
589
 
 
590
        if (!strcmp(path, WPAS_DBUS_PATH)) {
 
591
                /* dispatch methods against our global dbus interface here */
 
592
                if (!strcmp(method, "addInterface")) {
 
593
                        reply = wpas_dbus_global_add_interface(
 
594
                                message, ctrl_iface->global);
 
595
                } else if (!strcmp(method, "removeInterface")) {
 
596
                        reply = wpas_dbus_global_remove_interface(
 
597
                                message, ctrl_iface->global);
 
598
                } else if (!strcmp(method, "getInterface")) {
 
599
                        reply = wpas_dbus_global_get_interface(
 
600
                                message, ctrl_iface->global);
 
601
                }
 
602
        }
 
603
 
 
604
        /* If the message was handled, send back the reply */
 
605
        if (reply) {
 
606
                dbus_connection_send(connection, reply, NULL);
 
607
                dbus_message_unref(reply);
 
608
        }
 
609
 
 
610
        return reply ? DBUS_HANDLER_RESULT_HANDLED :
 
611
                DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
612
}
 
613
 
 
614
 
 
615
/**
 
616
 * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal
 
617
 * @wpa_s: %wpa_supplicant network interface data
 
618
 * Returns: 0 on success, -1 on failure
 
619
 *
 
620
 * Notify listeners that this interface has updated scan results.
 
621
 */
 
622
void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
 
623
{
 
624
        struct ctrl_iface_dbus_priv *iface = wpa_s->global->dbus_ctrl_iface;
 
625
        DBusMessage *_signal;
 
626
        const char *path;
 
627
 
 
628
        /* Do nothing if the control interface is not turned on */
 
629
        if (iface == NULL)
 
630
                return;
 
631
 
 
632
        path = wpa_supplicant_get_dbus_path(wpa_s);
 
633
        if (path == NULL) {
 
634
                perror("wpa_supplicant_dbus_notify_scan_results[dbus]: "
 
635
                       "interface didn't have a dbus path");
 
636
                wpa_printf(MSG_ERROR,
 
637
                           "wpa_supplicant_dbus_notify_scan_results[dbus]: "
 
638
                           "interface didn't have a dbus path; can't send "
 
639
                           "scan result signal.");
 
640
                return;
 
641
        }
 
642
        _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
 
643
                                          "ScanResultsAvailable");
 
644
        if (_signal == NULL) {
 
645
                perror("wpa_supplicant_dbus_notify_scan_results[dbus]: "
 
646
                       "couldn't create dbus signal; likely out of memory");
 
647
                wpa_printf(MSG_ERROR, "dbus control interface: not enough "
 
648
                           "memory to send scan results signal.");
 
649
                return;
 
650
        }
 
651
        dbus_connection_send(iface->con, _signal, NULL);
 
652
        dbus_message_unref(_signal);
 
653
}
 
654
 
 
655
 
 
656
/**
 
657
 * wpa_supplicant_dbus_notify_state_change - Send a state change signal
 
658
 * @wpa_s: %wpa_supplicant network interface data
 
659
 * @new_state: new state wpa_supplicant is entering
 
660
 * @old_state: old state wpa_supplicant is leaving
 
661
 * Returns: 0 on success, -1 on failure
 
662
 *
 
663
 * Notify listeners that wpa_supplicant has changed state
 
664
 */
 
665
void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
 
666
                                             wpa_states new_state,
 
667
                                             wpa_states old_state)
 
668
{
 
669
        struct ctrl_iface_dbus_priv *iface;
 
670
        DBusMessage *_signal = NULL;
 
671
        const char *path;
 
672
        const char *new_state_str, *old_state_str;
 
673
 
 
674
        /* Do nothing if the control interface is not turned on */
 
675
        if (wpa_s->global == NULL)
 
676
                return;
 
677
        iface = wpa_s->global->dbus_ctrl_iface;
 
678
        if (iface == NULL)
 
679
                return;
 
680
 
 
681
        /* Only send signal if state really changed */
 
682
        if (new_state == old_state)
 
683
                return;
 
684
 
 
685
        path = wpa_supplicant_get_dbus_path(wpa_s);
 
686
        if (path == NULL) {
 
687
                perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
 
688
                       "interface didn't have a dbus path");
 
689
                wpa_printf(MSG_ERROR,
 
690
                           "wpa_supplicant_dbus_notify_state_change[dbus]: "
 
691
                           "interface didn't have a dbus path; can't send "
 
692
                           "signal.");
 
693
                return;
 
694
        }
 
695
        _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
 
696
                                          "StateChange");
 
697
        if (_signal == NULL) {
 
698
                perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
 
699
                       "couldn't create dbus signal; likely out of memory");
 
700
                wpa_printf(MSG_ERROR,
 
701
                           "wpa_supplicant_dbus_notify_state_change[dbus]: "
 
702
                           "couldn't create dbus signal; likely out of "
 
703
                           "memory.");
 
704
                return;
 
705
        }
 
706
 
 
707
        new_state_str = wpa_supplicant_state_txt(new_state);
 
708
        old_state_str = wpa_supplicant_state_txt(old_state);
 
709
        if (new_state_str == NULL || old_state_str == NULL) {
 
710
                perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
 
711
                       "couldn't convert state strings");
 
712
                wpa_printf(MSG_ERROR,
 
713
                           "wpa_supplicant_dbus_notify_state_change[dbus]: "
 
714
                           "couldn't convert state strings.");
 
715
                goto out;
 
716
        }
 
717
 
 
718
        if (!dbus_message_append_args(_signal,
 
719
                                      DBUS_TYPE_STRING, &new_state_str,
 
720
                                      DBUS_TYPE_STRING, &old_state_str,
 
721
                                      DBUS_TYPE_INVALID)) {
 
722
                perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
 
723
                       "not enough memory to construct state change signal.");
 
724
                wpa_printf(MSG_ERROR,
 
725
                           "wpa_supplicant_dbus_notify_state_change[dbus]: "
 
726
                           "not enough memory to construct state change "
 
727
                           "signal.");
 
728
                goto out;
 
729
        }
 
730
 
 
731
        dbus_connection_send(iface->con, _signal, NULL);
 
732
 
 
733
out:
 
734
        dbus_message_unref(_signal);
 
735
}
 
736
 
 
737
 
 
738
/**
 
739
 * integrate_with_eloop - Register our mainloop integration with dbus
 
740
 * @connection: connection to the system message bus
 
741
 * @iface: a dbus control interface data structure
 
742
 * Returns: 0 on success, -1 on failure
 
743
 *
 
744
 * We register our mainloop integration functions with dbus here.
 
745
 */
 
746
static int integrate_with_eloop(DBusConnection *connection,
 
747
        struct ctrl_iface_dbus_priv *iface)
 
748
{
 
749
        if (!dbus_connection_set_watch_functions(connection, add_watch,
 
750
                                                 remove_watch, watch_toggled,
 
751
                                                 iface, NULL)) {
 
752
                perror("dbus_connection_set_watch_functions[dbus]");
 
753
                wpa_printf(MSG_ERROR, "Not enough memory to set up dbus.");
 
754
                return -1;
 
755
        }
 
756
 
 
757
        if (!dbus_connection_set_timeout_functions(connection, add_timeout,
 
758
                                                   remove_timeout,
 
759
                                                   timeout_toggled, iface,
 
760
                                                   NULL)) {
 
761
                perror("dbus_connection_set_timeout_functions[dbus]");
 
762
                wpa_printf(MSG_ERROR, "Not enough memory to set up dbus.");
 
763
                return -1;
 
764
        }
 
765
 
 
766
        if (connection_setup_wakeup_main(iface) < 0) {
 
767
                perror("connection_setup_wakeup_main[dbus]");
 
768
                wpa_printf(MSG_ERROR, "Could not setup main wakeup function.");
 
769
                return -1;
 
770
        }
 
771
 
 
772
        return 0;
 
773
}
 
774
 
 
775
 
 
776
/**
 
777
 * dispatch_initial_dbus_messages - Dispatch initial dbus messages after
 
778
 *     claiming bus name
 
779
 * @eloop_ctx: the DBusConnection to dispatch on
 
780
 * @timeout_ctx: unused
 
781
 *
 
782
 * If clients are quick to notice that wpa_supplicant claimed its bus name,
 
783
 * there may have been messages that came in before initialization was
 
784
 * all finished.  Dispatch those here.
 
785
 */
 
786
static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx)
 
787
{
 
788
        DBusConnection *con = eloop_ctx;
 
789
 
 
790
        while (dbus_connection_get_dispatch_status(con) ==
 
791
               DBUS_DISPATCH_DATA_REMAINS)
 
792
                dbus_connection_dispatch(con);
 
793
}
 
794
 
 
795
 
 
796
/**
 
797
 * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
 
798
 * @global: Pointer to global data from wpa_supplicant_init()
 
799
 * Returns: Pointer to dbus_ctrl_iface date or %NULL on failure
 
800
 *
 
801
 * Initialize the dbus control interface and start receiving commands from
 
802
 * external programs over the bus.
 
803
 */
 
804
struct ctrl_iface_dbus_priv *
 
805
wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global)
 
806
{
 
807
        struct ctrl_iface_dbus_priv *iface;
 
808
        DBusError error;
 
809
        int ret = -1;
 
810
        DBusObjectPathVTable wpas_vtable = {
 
811
                NULL, &wpas_message_handler, NULL, NULL, NULL, NULL
 
812
        };
 
813
 
 
814
        iface = os_zalloc(sizeof(struct ctrl_iface_dbus_priv));
 
815
        if (iface == NULL)
 
816
                return NULL;
 
817
 
 
818
        iface->global = global;
 
819
 
 
820
        /* Get a reference to the system bus */
 
821
        dbus_error_init(&error);
 
822
        iface->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
 
823
        dbus_error_free(&error);
 
824
        if (!iface->con) {
 
825
                perror("dbus_bus_get[ctrl_iface_dbus]");
 
826
                wpa_printf(MSG_ERROR, "Could not acquire the system bus.");
 
827
                goto fail;
 
828
        }
 
829
 
 
830
        /* Tell dbus about our mainloop integration functions */
 
831
        if (integrate_with_eloop(iface->con, iface))
 
832
                goto fail;
 
833
 
 
834
        /* Register the message handler for the global dbus interface */
 
835
        if (!dbus_connection_register_object_path(iface->con,
 
836
                                                  WPAS_DBUS_PATH, &wpas_vtable,
 
837
                                                  iface)) {
 
838
                perror("dbus_connection_register_object_path[dbus]");
 
839
                wpa_printf(MSG_ERROR, "Could not set up DBus message "
 
840
                           "handler.");
 
841
                goto fail;
 
842
        }
 
843
 
 
844
        /* Register our service with the message bus */
 
845
        dbus_error_init(&error);
 
846
        switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE,
 
847
                                      0, &error)) {
 
848
        case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
 
849
                ret = 0;
 
850
                break;
 
851
        case DBUS_REQUEST_NAME_REPLY_EXISTS:
 
852
        case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
 
853
        case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
 
854
                perror("dbus_bus_request_name[dbus]");
 
855
                wpa_printf(MSG_ERROR, "Could not request DBus service name: "
 
856
                           "already registered.");
 
857
                break;
 
858
        default:
 
859
                perror("dbus_bus_request_name[dbus]");
 
860
                wpa_printf(MSG_ERROR, "Could not request DBus service name: "
 
861
                           "%s %s.", error.name, error.message);
 
862
                break;
 
863
        }
 
864
        dbus_error_free(&error);
 
865
 
 
866
        if (ret != 0)
 
867
                goto fail;
 
868
 
 
869
        wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE
 
870
                   "'.");
 
871
 
 
872
        /*
 
873
         * Dispatch initial DBus messages that may have come in since the bus
 
874
         * name was claimed above. Happens when clients are quick to notice the
 
875
         * wpa_supplicant service.
 
876
         *
 
877
         * FIXME: is there a better solution to this problem?
 
878
         */
 
879
        eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
 
880
                               iface->con, NULL);
 
881
 
 
882
        return iface;
 
883
 
 
884
fail:
 
885
        wpa_supplicant_dbus_ctrl_iface_deinit(iface);
 
886
        return NULL;
 
887
}
 
888
 
 
889
 
 
890
/**
 
891
 * wpa_supplicant_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface
 
892
 * @iface: Pointer to dbus private data from
 
893
 * wpa_supplicant_dbus_ctrl_iface_init()
 
894
 *
 
895
 * Deinitialize the dbus control interface that was initialized with
 
896
 * wpa_supplicant_dbus_ctrl_iface_init().
 
897
 */
 
898
void wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface)
 
899
{
 
900
        if (iface == NULL)
 
901
                return;
 
902
 
 
903
        if (iface->con) {
 
904
                eloop_cancel_timeout(dispatch_initial_dbus_messages,
 
905
                                     iface->con, NULL);
 
906
                dbus_connection_set_watch_functions(iface->con, NULL, NULL,
 
907
                                                    NULL, NULL, NULL);
 
908
                dbus_connection_set_timeout_functions(iface->con, NULL, NULL,
 
909
                                                      NULL, NULL, NULL);
 
910
                dbus_connection_unref(iface->con);
 
911
        }
 
912
 
 
913
        memset(iface, 0, sizeof(struct ctrl_iface_dbus_priv));
 
914
        free(iface);
 
915
}
 
916
 
 
917
 
 
918
/**
 
919
 * wpas_dbus_register_new_iface - Register a new interface with dbus
 
920
 * @global: Global %wpa_supplicant data
 
921
 * @wpa_s: %wpa_supplicant interface description structure to register
 
922
 * Returns: 0 on success, -1 on error
 
923
 *
 
924
 * Registers a new interface with dbus and assigns it a dbus object path.
 
925
 */
 
926
int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
 
927
{
 
928
        struct ctrl_iface_dbus_priv *ctrl_iface =
 
929
                wpa_s->global->dbus_ctrl_iface;
 
930
        DBusConnection * con;
 
931
        u32 next;
 
932
        DBusObjectPathVTable vtable = {
 
933
                NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL
 
934
        };
 
935
        char *path;
 
936
        int ret = -1;
 
937
 
 
938
        /* Do nothing if the control interface is not turned on */
 
939
        if (ctrl_iface == NULL)
 
940
                return 0;
 
941
 
 
942
        con = ctrl_iface->con;
 
943
        next = wpa_supplicant_dbus_next_objid(ctrl_iface);
 
944
 
 
945
        /* Create and set the interface's object path */
 
946
        path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
 
947
        if (path == NULL)
 
948
                return -1;
 
949
        snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
 
950
                 WPAS_DBUS_PATH_INTERFACES "/%u",
 
951
                 next);
 
952
        if (wpa_supplicant_set_dbus_path(wpa_s, path)) {
 
953
                wpa_printf(MSG_DEBUG,
 
954
                           "Failed to set dbus path for interface %s",
 
955
                           wpa_s->ifname);
 
956
                goto out;
 
957
        }
 
958
 
 
959
        /* Register the message handler for the interface functions */
 
960
        if (!dbus_connection_register_fallback(con, path, &vtable, wpa_s)) {
 
961
                perror("wpas_dbus_register_iface [dbus]");
 
962
                wpa_printf(MSG_ERROR, "Could not set up DBus message "
 
963
                           "handler for interface %s.", wpa_s->ifname);
 
964
                goto out;
 
965
        }
 
966
        ret = 0;
 
967
 
 
968
out:
 
969
        free(path);
 
970
        return ret;
 
971
}
 
972
 
 
973
 
 
974
/**
 
975
 * wpas_dbus_unregister_iface - Unregister an interface from dbus
 
976
 * @wpa_s: wpa_supplicant interface structure
 
977
 * Returns: 0 on success, -1 on failure
 
978
 *
 
979
 * Unregisters the interface with dbus
 
980
 */
 
981
int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
 
982
{
 
983
        struct ctrl_iface_dbus_priv *ctrl_iface;
 
984
        DBusConnection *con;
 
985
        const char *path;
 
986
 
 
987
        /* Do nothing if the control interface is not turned on */
 
988
        if (wpa_s == NULL || wpa_s->global == NULL)
 
989
                return 0;
 
990
        ctrl_iface = wpa_s->global->dbus_ctrl_iface;
 
991
        if (ctrl_iface == NULL)
 
992
                return 0;
 
993
 
 
994
        con = ctrl_iface->con;
 
995
        path = wpa_supplicant_get_dbus_path(wpa_s);
 
996
 
 
997
        if (!dbus_connection_unregister_object_path(con, path))
 
998
                return -1;
 
999
 
 
1000
        free(wpa_s->dbus_path);
 
1001
        wpa_s->dbus_path = NULL;
 
1002
 
 
1003
        return 0;
 
1004
}
 
1005
 
 
1006
 
 
1007
/**
 
1008
 * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface
 
1009
 * @global: Pointer to global data from wpa_supplicant_init()
 
1010
 * @path: Pointer to a dbus object path representing an interface
 
1011
 * Returns: Pointer to the interface or %NULL if not found
 
1012
 */
 
1013
struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
 
1014
        struct wpa_global *global, const char *path)
 
1015
{
 
1016
        struct wpa_supplicant *wpa_s;
 
1017
 
 
1018
        for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
 
1019
                if (strcmp(wpa_s->dbus_path, path) == 0)
 
1020
                        return wpa_s;
 
1021
        }
 
1022
        return NULL;
 
1023
}
 
1024
 
 
1025
 
 
1026
/**
 
1027
 * wpa_supplicant_set_dbus_path - Assign a dbus path to an interface
 
1028
 * @wpa_s: wpa_supplicant interface structure
 
1029
 * @path: dbus path to set on the interface
 
1030
 * Returns: 0 on succes, -1 on error
 
1031
 */
 
1032
int wpa_supplicant_set_dbus_path(struct wpa_supplicant *wpa_s,
 
1033
                                  const char *path)
 
1034
{
 
1035
        u32 len = strlen (path);
 
1036
        if (len >= WPAS_DBUS_OBJECT_PATH_MAX)
 
1037
                return -1;
 
1038
        if (wpa_s->dbus_path)
 
1039
                return -1;
 
1040
        wpa_s->dbus_path = strdup(path);
 
1041
        return 0;
 
1042
}
 
1043
 
 
1044
 
 
1045
/**
 
1046
 * wpa_supplicant_get_dbus_path - Get an interface's dbus path
 
1047
 * @wpa_s: %wpa_supplicant interface structure
 
1048
 * Returns: Interface's dbus object path, or %NULL on error
 
1049
 */
 
1050
const char * wpa_supplicant_get_dbus_path(struct wpa_supplicant *wpa_s)
 
1051
{
 
1052
        return wpa_s->dbus_path;
 
1053
}