~ubuntu-branches/ubuntu/lucid/wpasupplicant/lucid-updates

« back to all changes in this revision

Viewing changes to ctrl_iface_named_pipe.c

  • Committer: Bazaar Package Importer
  • Author(s): Kel Modderman
  • Date: 2006-10-05 08:04:01 UTC
  • mfrom: (1.1.5 upstream) (3 etch)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20061005080401-r8lqlix4390yos7b
Tags: 0.5.5-2
* Update madwifi headers to latest SVN. (Closes: #388316)
* Remove failed attempt at action locking. [debian/functions.sh,
  debian/wpa_action.sh]
* Add hysteresis checking functions, to avoid "event loops" while
  using wpa-roam. [debian/functions.sh, debian/wpa_action.sh]
* Change of co-maintainer email address.
* Add ishex() function to functions.sh to determine wpa-psk value type in
  plaintext or hex. This effectively eliminates the need for the bogus and
  somewhat confusing wpa-passphrase contruct specific to our scripts and
  allows wpa-psk to work with either a 8 to 63 character long plaintext
  string or 64 character long hex string.
* Adjust README.modes to not refer to the redundant wpa-passphrase stuff.
* Add big fat NOTE about acceptable wpa-psk's to top of example gallery.
* Strip surrounding quotes from wpa-ssid if present, instead of just whining
  about them.
* Update email address in copyright blurb of functions.sh, ifupdown.sh and
  wpa_action.sh.  

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * WPA Supplicant / Windows Named Pipe -based control interface
 
3
 * Copyright (c) 2004-2006, Jouni Malinen <jkmaline@cc.hut.fi>
 
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 "eapol_sm.h"
 
21
#include "wpa_supplicant_i.h"
 
22
#include "ctrl_iface.h"
 
23
#include "wpa_ctrl.h"
 
24
 
 
25
#ifdef __MINGW32_VERSION
 
26
/* mingw-w32api v3.1 does not yet include sddl.h, so define needed parts here
 
27
 */
 
28
#define SDDL_REVISION_1 1
 
29
BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA(
 
30
        LPCSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG);
 
31
BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW(
 
32
        LPCWSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG);
 
33
#ifdef UNICODE
 
34
#define ConvertStringSecurityDescriptorToSecurityDescriptor \
 
35
ConvertStringSecurityDescriptorToSecurityDescriptorW
 
36
#else
 
37
#define ConvertStringSecurityDescriptorToSecurityDescriptor \
 
38
ConvertStringSecurityDescriptorToSecurityDescriptorA
 
39
#endif
 
40
#else /* __MINGW32_VERSION */
 
41
#ifndef _WIN32_WINNT
 
42
#define _WIN32_WINNT 0x0500
 
43
#endif
 
44
#include <sddl.h>
 
45
#endif /* __MINGW32_VERSION */
 
46
 
 
47
#ifndef WPA_SUPPLICANT_NAMED_PIPE
 
48
#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
 
49
#endif
 
50
#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
 
51
 
 
52
/* Per-interface ctrl_iface */
 
53
 
 
54
#define REQUEST_BUFSIZE 256
 
55
#define REPLY_BUFSIZE 4096
 
56
 
 
57
struct ctrl_iface_priv;
 
58
 
 
59
/**
 
60
 * struct wpa_ctrl_dst - Internal data structure of control interface clients
 
61
 *
 
62
 * This structure is used to store information about registered control
 
63
 * interface monitors into struct wpa_supplicant. This data is private to
 
64
 * ctrl_iface_named_pipe.c and should not be touched directly from other files.
 
65
 */
 
66
struct wpa_ctrl_dst {
 
67
        /* Note: OVERLAPPED must be the first member of struct wpa_ctrl_dst */
 
68
        OVERLAPPED overlap;
 
69
        struct wpa_ctrl_dst *next, *prev;
 
70
        struct ctrl_iface_priv *priv;
 
71
        HANDLE pipe;
 
72
        int attached;
 
73
        int debug_level;
 
74
        int errors;
 
75
        char req_buf[REQUEST_BUFSIZE];
 
76
        char *rsp_buf;
 
77
};
 
78
 
 
79
 
 
80
struct ctrl_iface_priv {
 
81
        struct wpa_supplicant *wpa_s;
 
82
        struct wpa_ctrl_dst *ctrl_dst;
 
83
        SECURITY_ATTRIBUTES attr;
 
84
        int sec_attr_set;
 
85
};
 
86
 
 
87
 
 
88
static void ctrl_close_pipe(struct wpa_ctrl_dst *dst);
 
89
static void wpa_supplicant_ctrl_iface_receive(void *, void *);
 
90
static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes,
 
91
                                             LPOVERLAPPED overlap);
 
92
 
 
93
struct wpa_global_dst;
 
94
static void global_close_pipe(struct wpa_global_dst *dst);
 
95
static void wpa_supplicant_global_iface_receive(void *eloop_data,
 
96
                                                void *user_ctx);
 
97
static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes,
 
98
                                               LPOVERLAPPED overlap);
 
99
 
 
100
 
 
101
static int ctrl_broken_pipe(HANDLE pipe)
 
102
{
 
103
        DWORD err;
 
104
 
 
105
        if (PeekNamedPipe(pipe, NULL, 0, NULL, NULL, NULL))
 
106
                return 0;
 
107
 
 
108
        err = GetLastError();
 
109
        if (err == ERROR_BAD_PIPE || err == ERROR_BROKEN_PIPE)
 
110
                return 1;
 
111
        return 0;
 
112
}
 
113
 
 
114
 
 
115
static void ctrl_flush_broken_pipes(struct ctrl_iface_priv *priv)
 
116
{
 
117
        struct wpa_ctrl_dst *dst, *next;
 
118
 
 
119
        dst = priv->ctrl_dst;
 
120
 
 
121
        while (dst) {
 
122
                next = dst->next;
 
123
                if (ctrl_broken_pipe(dst->pipe)) {
 
124
                        wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p",
 
125
                                   dst);
 
126
                        ctrl_close_pipe(dst);
 
127
                }
 
128
                dst = next;
 
129
        }
 
130
}
 
131
 
 
132
 
 
133
static int ctrl_open_pipe(struct ctrl_iface_priv *priv)
 
134
{
 
135
        struct wpa_ctrl_dst *dst;
 
136
        DWORD err;
 
137
        TCHAR name[256];
 
138
 
 
139
        ctrl_flush_broken_pipes(priv);
 
140
        dst = wpa_zalloc(sizeof(*dst));
 
141
        if (dst == NULL)
 
142
                return -1;
 
143
        wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst);
 
144
 
 
145
        dst->priv = priv;
 
146
        dst->debug_level = MSG_INFO;
 
147
        dst->pipe = INVALID_HANDLE_VALUE;
 
148
 
 
149
        dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
 
150
        if (dst->overlap.hEvent == NULL) {
 
151
                wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d",
 
152
                           (int) GetLastError()); 
 
153
                goto fail;
 
154
        }
 
155
 
 
156
        eloop_register_event(dst->overlap.hEvent,
 
157
                             sizeof(dst->overlap.hEvent),
 
158
                             wpa_supplicant_ctrl_iface_receive, dst, NULL);
 
159
 
 
160
#ifdef UNICODE
 
161
        _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
 
162
                   priv->wpa_s->ifname);
 
163
#else /* UNICODE */
 
164
        snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
 
165
                 priv->wpa_s->ifname);
 
166
#endif /* UNICODE */
 
167
 
 
168
        /* TODO: add support for configuring access list for the pipe */
 
169
        dst->pipe = CreateNamedPipe(name,
 
170
                                    PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
 
171
                                    PIPE_TYPE_MESSAGE |
 
172
                                    PIPE_READMODE_MESSAGE |
 
173
                                    PIPE_WAIT,
 
174
                                    15, REPLY_BUFSIZE, REQUEST_BUFSIZE,
 
175
                                    1000,
 
176
                                    priv->sec_attr_set ? &priv->attr : NULL);
 
177
        if (dst->pipe == INVALID_HANDLE_VALUE) {
 
178
                wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d",
 
179
                           (int) GetLastError()); 
 
180
                goto fail;
 
181
        }
 
182
 
 
183
        if (ConnectNamedPipe(dst->pipe, &dst->overlap)) {
 
184
                wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d",
 
185
                           (int) GetLastError());
 
186
                CloseHandle(dst->pipe);
 
187
                free(dst);
 
188
                return -1;
 
189
        }
 
190
 
 
191
        err = GetLastError();
 
192
        switch (err) {
 
193
        case ERROR_IO_PENDING:
 
194
                wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in "
 
195
                           "progress");
 
196
                break;
 
197
        case ERROR_PIPE_CONNECTED:
 
198
                wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already "
 
199
                           "connected");
 
200
                if (SetEvent(dst->overlap.hEvent))
 
201
                        break;
 
202
                /* fall through */
 
203
        default:
 
204
                wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d",
 
205
                           (int) err);
 
206
                CloseHandle(dst->pipe);
 
207
                free(dst);
 
208
                return -1;
 
209
        }
 
210
 
 
211
        dst->next = priv->ctrl_dst;
 
212
        if (dst->next)
 
213
                dst->next->prev = dst;
 
214
        priv->ctrl_dst = dst;
 
215
 
 
216
        return 0;
 
217
 
 
218
fail:
 
219
        ctrl_close_pipe(dst);
 
220
        return -1;
 
221
}
 
222
 
 
223
 
 
224
static void ctrl_close_pipe(struct wpa_ctrl_dst *dst)
 
225
{
 
226
        wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst);
 
227
 
 
228
        if (dst->overlap.hEvent) {
 
229
                eloop_unregister_event(dst->overlap.hEvent,
 
230
                                       sizeof(dst->overlap.hEvent));
 
231
                CloseHandle(dst->overlap.hEvent);
 
232
        }
 
233
 
 
234
        if (dst->pipe != INVALID_HANDLE_VALUE) {
 
235
                /*
 
236
                 * Could use FlushFileBuffers() here to guarantee that all data
 
237
                 * gets delivered to the client, but that can block, so let's
 
238
                 * not do this for now.
 
239
                 * FlushFileBuffers(dst->pipe);
 
240
                 */
 
241
                CloseHandle(dst->pipe);
 
242
        }
 
243
 
 
244
        if (dst->prev)
 
245
                dst->prev->next = dst->next;
 
246
        else
 
247
                dst->priv->ctrl_dst = dst->next;
 
248
        if (dst->next)
 
249
                dst->next->prev = dst->prev;
 
250
 
 
251
        free(dst->rsp_buf);
 
252
        free(dst);
 
253
}
 
254
 
 
255
 
 
256
static VOID WINAPI ctrl_iface_write_completed(DWORD err, DWORD bytes,
 
257
                                              LPOVERLAPPED overlap)
 
258
{
 
259
        struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap;
 
260
        wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p "
 
261
                   "err=%d bytes=%d", dst, (int) err, (int) bytes);
 
262
        if (err) {
 
263
                ctrl_close_pipe(dst);
 
264
                return;
 
265
        }
 
266
 
 
267
        free(dst->rsp_buf);
 
268
        dst->rsp_buf = NULL;
 
269
 
 
270
        if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf),
 
271
                        &dst->overlap, ctrl_iface_read_completed)) {
 
272
                wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d",
 
273
                           (int) GetLastError());
 
274
                ctrl_close_pipe(dst);
 
275
        }
 
276
        wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst);
 
277
}
 
278
 
 
279
 
 
280
static void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len)
 
281
{
 
282
        struct wpa_supplicant *wpa_s = dst->priv->wpa_s;
 
283
        char *reply = NULL, *send_buf;
 
284
        size_t reply_len = 0, send_len;
 
285
        int new_attached = 0;
 
286
        char *buf = dst->req_buf;
 
287
 
 
288
        if (len >= REQUEST_BUFSIZE)
 
289
                len = REQUEST_BUFSIZE - 1;
 
290
        buf[len] = '\0';
 
291
 
 
292
        if (strcmp(buf, "ATTACH") == 0) {
 
293
                dst->attached = 1;
 
294
                wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached");
 
295
                new_attached = 1;
 
296
                reply_len = 2;
 
297
        } else if (strcmp(buf, "DETACH") == 0) {
 
298
                dst->attached = 0;
 
299
                wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached");
 
300
                reply_len = 2;
 
301
        } else if (strncmp(buf, "LEVEL ", 6) == 0) {
 
302
                wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", buf + 6);
 
303
                dst->debug_level = atoi(buf + 6);
 
304
                reply_len = 2;
 
305
        } else {
 
306
                reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
 
307
                                                          &reply_len);
 
308
        }
 
309
 
 
310
        if (reply) {
 
311
                send_buf = reply;
 
312
                send_len = reply_len;
 
313
        } else if (reply_len == 2) {
 
314
                send_buf = "OK\n";
 
315
                send_len = 3;
 
316
        } else {
 
317
                send_buf = "FAIL\n";
 
318
                send_len = 5;
 
319
        }
 
320
 
 
321
        free(dst->rsp_buf);
 
322
        dst->rsp_buf = malloc(send_len);
 
323
        if (dst->rsp_buf == NULL) {
 
324
                ctrl_close_pipe(dst);
 
325
                free(reply);
 
326
                return;
 
327
        }
 
328
        memcpy(dst->rsp_buf, send_buf, send_len);
 
329
        free(reply);
 
330
 
 
331
        if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap,
 
332
                         ctrl_iface_write_completed)) {
 
333
                wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d",
 
334
                           (int) GetLastError());
 
335
                ctrl_close_pipe(dst);
 
336
        }
 
337
        wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", dst);
 
338
 
 
339
        if (new_attached)
 
340
                eapol_sm_notify_ctrl_attached(wpa_s->eapol);
 
341
}
 
342
 
 
343
 
 
344
static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes,
 
345
                                             LPOVERLAPPED overlap)
 
346
{
 
347
        struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap;
 
348
        wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d "
 
349
                   "bytes=%d", dst, (int) err, (int) bytes);
 
350
        if (err == 0 && bytes > 0)
 
351
                wpa_supplicant_ctrl_iface_rx(dst, bytes);
 
352
}
 
353
 
 
354
 
 
355
static void wpa_supplicant_ctrl_iface_receive(void *eloop_data, void *user_ctx)
 
356
{
 
357
        struct wpa_ctrl_dst *dst = eloop_data;
 
358
        struct ctrl_iface_priv *priv = dst->priv;
 
359
        DWORD bytes;
 
360
 
 
361
        wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_ctrl_iface_receive");
 
362
        ResetEvent(dst->overlap.hEvent);
 
363
 
 
364
        if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) {
 
365
                wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d",
 
366
                           (int) GetLastError());
 
367
                return;
 
368
        }
 
369
        wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client "
 
370
                   "connected");
 
371
 
 
372
        /* Open a new named pipe for the next client. */
 
373
        ctrl_open_pipe(priv); 
 
374
 
 
375
        /* Use write completion function to start reading a command */
 
376
        ctrl_iface_write_completed(0, 0, &dst->overlap);
 
377
}
 
378
 
 
379
 
 
380
static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params)
 
381
{
 
382
        const char *sddl = NULL;
 
383
        TCHAR *t_sddl;
 
384
 
 
385
        if (strncmp(params, "SDDL=", 5) == 0)
 
386
                sddl = params + 5;
 
387
        if (!sddl) {
 
388
                sddl = strstr(params, " SDDL=");
 
389
                if (sddl)
 
390
                        sddl += 6;
 
391
        }
 
392
 
 
393
        if (!sddl)
 
394
                return 0;
 
395
 
 
396
        wpa_printf(MSG_DEBUG, "CTRL: SDDL='%s'", sddl);
 
397
        memset(&priv->attr, 0, sizeof(priv->attr));
 
398
        priv->attr.nLength = sizeof(priv->attr);
 
399
        priv->attr.bInheritHandle = FALSE;
 
400
        t_sddl = wpa_strdup_tchar(sddl);
 
401
        if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
 
402
                    t_sddl, SDDL_REVISION_1,
 
403
                    (PSECURITY_DESCRIPTOR *) &priv->attr.lpSecurityDescriptor,
 
404
                    NULL)) {
 
405
                free(t_sddl);
 
406
                wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to "
 
407
                           "security descriptor: %d",
 
408
                           sddl, (int) GetLastError());
 
409
                return -1;
 
410
        }
 
411
        free(t_sddl);
 
412
 
 
413
        priv->sec_attr_set = 1;
 
414
 
 
415
        return 0;
 
416
}
 
417
 
 
418
 
 
419
struct ctrl_iface_priv *
 
420
wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
 
421
{
 
422
        struct ctrl_iface_priv *priv;
 
423
 
 
424
        priv = wpa_zalloc(sizeof(*priv));
 
425
        if (priv == NULL)
 
426
                return NULL;
 
427
        priv->wpa_s = wpa_s;
 
428
 
 
429
        if (wpa_s->conf->ctrl_interface == NULL)
 
430
                return priv;
 
431
 
 
432
        if (ctrl_iface_parse(priv, wpa_s->conf->ctrl_interface) < 0) {
 
433
                free(priv);
 
434
                return NULL;
 
435
        }
 
436
 
 
437
        if (ctrl_open_pipe(priv) < 0) {
 
438
                free(priv);
 
439
                return NULL;
 
440
        }
 
441
 
 
442
        return priv;
 
443
}
 
444
 
 
445
 
 
446
void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
 
447
{
 
448
        while (priv->ctrl_dst)
 
449
                ctrl_close_pipe(priv->ctrl_dst);
 
450
        if (priv->sec_attr_set)
 
451
                LocalFree(priv->attr.lpSecurityDescriptor);
 
452
        free(priv);
 
453
}
 
454
 
 
455
 
 
456
void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, int level,
 
457
                                    const char *buf, size_t len)
 
458
{
 
459
        struct wpa_ctrl_dst *dst, *next;
 
460
        char levelstr[10];
 
461
        int idx;
 
462
        char *sbuf;
 
463
        int llen;
 
464
        DWORD written;
 
465
 
 
466
        dst = priv->ctrl_dst;
 
467
        if (dst == NULL)
 
468
                return;
 
469
 
 
470
        snprintf(levelstr, sizeof(levelstr), "<%d>", level);
 
471
 
 
472
        llen = strlen(levelstr);
 
473
        sbuf = malloc(llen + len);
 
474
        if (sbuf == NULL)
 
475
                return;
 
476
 
 
477
        memcpy(sbuf, levelstr, llen);
 
478
        memcpy(sbuf + llen, buf, len);
 
479
 
 
480
        idx = 0;
 
481
        while (dst) {
 
482
                next = dst->next;
 
483
                if (dst->attached && level >= dst->debug_level) {
 
484
                        wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p",
 
485
                                   dst);
 
486
                        if (!WriteFile(dst->pipe, sbuf, llen + len, &written,
 
487
                                       NULL)) {
 
488
                                wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst "
 
489
                                           "%p failed: %d",
 
490
                                           dst, (int) GetLastError());
 
491
                                dst->errors++;
 
492
                                if (dst->errors > 10)
 
493
                                        ctrl_close_pipe(dst);
 
494
                        } else
 
495
                                dst->errors = 0;
 
496
                }
 
497
                idx++;
 
498
                dst = next;
 
499
        }
 
500
        free(sbuf);
 
501
}
 
502
 
 
503
 
 
504
void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
 
505
{
 
506
        wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
 
507
                   priv->wpa_s->ifname);
 
508
        if (priv->ctrl_dst == NULL)
 
509
                return;
 
510
        WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE);
 
511
}
 
512
 
 
513
 
 
514
/* Global ctrl_iface */
 
515
 
 
516
struct ctrl_iface_global_priv;
 
517
 
 
518
struct wpa_global_dst {
 
519
        /* Note: OVERLAPPED must be the first member of struct wpa_global_dst
 
520
         */
 
521
        OVERLAPPED overlap;
 
522
        struct wpa_global_dst *next, *prev;
 
523
        struct ctrl_iface_global_priv *priv;
 
524
        HANDLE pipe;
 
525
        char req_buf[REQUEST_BUFSIZE];
 
526
        char *rsp_buf;
 
527
};
 
528
 
 
529
struct ctrl_iface_global_priv {
 
530
        struct wpa_global *global;
 
531
        struct wpa_global_dst *ctrl_dst;
 
532
};
 
533
 
 
534
 
 
535
static void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv)
 
536
{
 
537
        struct wpa_global_dst *dst, *next;
 
538
 
 
539
        dst = priv->ctrl_dst;
 
540
 
 
541
        while (dst) {
 
542
                next = dst->next;
 
543
                if (ctrl_broken_pipe(dst->pipe)) {
 
544
                        wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p",
 
545
                                   dst);
 
546
                        global_close_pipe(dst);
 
547
                }
 
548
                dst = next;
 
549
        }
 
550
}
 
551
 
 
552
 
 
553
static int global_open_pipe(struct ctrl_iface_global_priv *priv)
 
554
{
 
555
        struct wpa_global_dst *dst;
 
556
        DWORD err;
 
557
 
 
558
        global_flush_broken_pipes(priv);
 
559
        dst = wpa_zalloc(sizeof(*dst));
 
560
        if (dst == NULL)
 
561
                return -1;
 
562
        wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst);
 
563
 
 
564
        dst->priv = priv;
 
565
        dst->pipe = INVALID_HANDLE_VALUE;
 
566
 
 
567
        dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
 
568
        if (dst->overlap.hEvent == NULL) {
 
569
                wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d",
 
570
                           (int) GetLastError()); 
 
571
                goto fail;
 
572
        }
 
573
 
 
574
        eloop_register_event(dst->overlap.hEvent,
 
575
                             sizeof(dst->overlap.hEvent),
 
576
                             wpa_supplicant_global_iface_receive, dst, NULL);
 
577
 
 
578
        /* TODO: add support for configuring access list for the pipe */
 
579
        dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX,
 
580
                                    PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
 
581
                                    PIPE_TYPE_MESSAGE |
 
582
                                    PIPE_READMODE_MESSAGE |
 
583
                                    PIPE_WAIT,
 
584
                                    10, REPLY_BUFSIZE, REQUEST_BUFSIZE,
 
585
                                    1000, NULL);
 
586
        if (dst->pipe == INVALID_HANDLE_VALUE) {
 
587
                wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d",
 
588
                           (int) GetLastError()); 
 
589
                goto fail;
 
590
        }
 
591
 
 
592
        if (ConnectNamedPipe(dst->pipe, &dst->overlap)) {
 
593
                wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d",
 
594
                           (int) GetLastError());
 
595
                CloseHandle(dst->pipe);
 
596
                free(dst);
 
597
                return -1;
 
598
        }
 
599
 
 
600
        err = GetLastError();
 
601
        switch (err) {
 
602
        case ERROR_IO_PENDING:
 
603
                wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in "
 
604
                           "progress");
 
605
                break;
 
606
        case ERROR_PIPE_CONNECTED:
 
607
                wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already "
 
608
                           "connected");
 
609
                if (SetEvent(dst->overlap.hEvent))
 
610
                        break;
 
611
                /* fall through */
 
612
        default:
 
613
                wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d",
 
614
                           (int) err);
 
615
                CloseHandle(dst->pipe);
 
616
                free(dst);
 
617
                return -1;
 
618
        }
 
619
 
 
620
        dst->next = priv->ctrl_dst;
 
621
        if (dst->next)
 
622
                dst->next->prev = dst;
 
623
        priv->ctrl_dst = dst;
 
624
 
 
625
        return 0;
 
626
 
 
627
fail:
 
628
        global_close_pipe(dst);
 
629
        return -1;
 
630
}
 
631
 
 
632
 
 
633
static void global_close_pipe(struct wpa_global_dst *dst)
 
634
{
 
635
        wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst);
 
636
 
 
637
        if (dst->overlap.hEvent) {
 
638
                eloop_unregister_event(dst->overlap.hEvent,
 
639
                                       sizeof(dst->overlap.hEvent));
 
640
                CloseHandle(dst->overlap.hEvent);
 
641
        }
 
642
 
 
643
        if (dst->pipe != INVALID_HANDLE_VALUE) {
 
644
                /*
 
645
                 * Could use FlushFileBuffers() here to guarantee that all data
 
646
                 * gets delivered to the client, but that can block, so let's
 
647
                 * not do this for now.
 
648
                 * FlushFileBuffers(dst->pipe);
 
649
                 */
 
650
                CloseHandle(dst->pipe);
 
651
        }
 
652
 
 
653
        if (dst->prev)
 
654
                dst->prev->next = dst->next;
 
655
        else
 
656
                dst->priv->ctrl_dst = dst->next;
 
657
        if (dst->next)
 
658
                dst->next->prev = dst->prev;
 
659
 
 
660
        free(dst->rsp_buf);
 
661
        free(dst);
 
662
}
 
663
 
 
664
 
 
665
static VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes,
 
666
                                                LPOVERLAPPED overlap)
 
667
{
 
668
        struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap;
 
669
        wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p "
 
670
                   "err=%d bytes=%d", dst, (int) err, (int) bytes);
 
671
        if (err) {
 
672
                global_close_pipe(dst);
 
673
                return;
 
674
        }
 
675
 
 
676
        free(dst->rsp_buf);
 
677
        dst->rsp_buf = NULL;
 
678
 
 
679
        if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf),
 
680
                        &dst->overlap, global_iface_read_completed)) {
 
681
                wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d",
 
682
                           (int) GetLastError());
 
683
                global_close_pipe(dst);
 
684
        }
 
685
        wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst);
 
686
}
 
687
 
 
688
 
 
689
static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst,
 
690
                                           size_t len)
 
691
{
 
692
        struct wpa_global *global = dst->priv->global;
 
693
        char *reply = NULL, *send_buf;
 
694
        size_t reply_len = 0, send_len;
 
695
        char *buf = dst->req_buf;
 
696
 
 
697
        if (len >= REQUEST_BUFSIZE)
 
698
                len = REQUEST_BUFSIZE - 1;
 
699
        buf[len] = '\0';
 
700
 
 
701
        reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
 
702
                                                         &reply_len);
 
703
        if (reply) {
 
704
                send_buf = reply;
 
705
                send_len = reply_len;
 
706
        } else if (reply_len) {
 
707
                send_buf = "FAIL\n";
 
708
                send_len = 5;
 
709
        } else {
 
710
                free(dst->rsp_buf);
 
711
                dst->rsp_buf = NULL;
 
712
                return;
 
713
        }
 
714
 
 
715
        free(dst->rsp_buf);
 
716
        dst->rsp_buf = malloc(send_len);
 
717
        if (dst->rsp_buf == NULL) {
 
718
                global_close_pipe(dst);
 
719
                free(reply);
 
720
                return;
 
721
        }
 
722
        memcpy(dst->rsp_buf, send_buf, send_len);
 
723
        free(reply);
 
724
 
 
725
        if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap,
 
726
                         global_iface_write_completed)) {
 
727
                wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d",
 
728
                           (int) GetLastError());
 
729
                global_close_pipe(dst);
 
730
        }
 
731
        wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", dst);
 
732
}
 
733
 
 
734
 
 
735
static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes,
 
736
                                               LPOVERLAPPED overlap)
 
737
{
 
738
        struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap;
 
739
        wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d "
 
740
                   "bytes=%d", dst, (int) err, (int) bytes);
 
741
        if (err == 0 && bytes > 0)
 
742
                wpa_supplicant_global_iface_rx(dst, bytes);
 
743
}
 
744
 
 
745
 
 
746
static void wpa_supplicant_global_iface_receive(void *eloop_data,
 
747
                                                void *user_ctx)
 
748
{
 
749
        struct wpa_global_dst *dst = eloop_data;
 
750
        struct ctrl_iface_global_priv *priv = dst->priv;
 
751
        DWORD bytes;
 
752
 
 
753
        wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive");
 
754
        ResetEvent(dst->overlap.hEvent);
 
755
 
 
756
        if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) {
 
757
                wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d",
 
758
                           (int) GetLastError());
 
759
                return;
 
760
        }
 
761
        wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client "
 
762
                   "connected");
 
763
 
 
764
        /* Open a new named pipe for the next client. */
 
765
        global_open_pipe(priv); 
 
766
 
 
767
        /* Use write completion function to start reading a command */
 
768
        global_iface_write_completed(0, 0, &dst->overlap);
 
769
}
 
770
 
 
771
 
 
772
struct ctrl_iface_global_priv *
 
773
wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
 
774
{
 
775
        struct ctrl_iface_global_priv *priv;
 
776
 
 
777
        priv = wpa_zalloc(sizeof(*priv));
 
778
        if (priv == NULL)
 
779
                return NULL;
 
780
        priv->global = global;
 
781
 
 
782
        if (global_open_pipe(priv) < 0) {
 
783
                free(priv);
 
784
                return NULL;
 
785
        }
 
786
 
 
787
        return priv;
 
788
}
 
789
 
 
790
 
 
791
void
 
792
wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
 
793
{
 
794
        while (priv->ctrl_dst)
 
795
                global_close_pipe(priv->ctrl_dst);
 
796
        free(priv);
 
797
}