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

« back to all changes in this revision

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