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

« back to all changes in this revision

Viewing changes to l2_packet_ndis.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 - Layer2 packet handling with Microsoft NDISUIO
3
 
 * Copyright (c) 2003-2006, Jouni Malinen <j@w1.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
 
 * This implementation requires Windows specific event loop implementation,
15
 
 * i.e., eloop_win.c. In addition, the NDISUIO connection is shared with
16
 
 * driver_ndis.c, so only that driver interface can be used and
17
 
 * CONFIG_USE_NDISUIO must be defined.
18
 
 *
19
 
 * WinXP version of the code uses overlapped I/O and a single threaded design
20
 
 * with callback functions from I/O code. WinCE version uses a separate RX
21
 
 * thread that blocks on ReadFile() whenever the media status is connected.
22
 
 */
23
 
 
24
 
#include "includes.h"
25
 
#include <winsock2.h>
26
 
#include <ntddndis.h>
27
 
 
28
 
#ifdef _WIN32_WCE
29
 
#include <winioctl.h>
30
 
#include <nuiouser.h>
31
 
#endif /* _WIN32_WCE */
32
 
 
33
 
#include "common.h"
34
 
#include "eloop.h"
35
 
#include "l2_packet.h"
36
 
 
37
 
#ifndef _WIN32_WCE
38
 
/* from nuiouser.h */
39
 
#define FSCTL_NDISUIO_BASE      FILE_DEVICE_NETWORK
40
 
#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \
41
 
        CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)
42
 
#define IOCTL_NDISUIO_SET_ETHER_TYPE \
43
 
        _NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \
44
 
                          FILE_READ_ACCESS | FILE_WRITE_ACCESS)
45
 
#endif /* _WIN32_WCE */
46
 
 
47
 
/* From driver_ndis.c to shared the handle to NDISUIO */
48
 
HANDLE driver_ndis_get_ndisuio_handle(void);
49
 
 
50
 
/*
51
 
 * NDISUIO supports filtering of only one ethertype at the time, so we must
52
 
 * fake support for two (EAPOL and RSN pre-auth) by switching to pre-auth
53
 
 * whenever wpa_supplicant is trying to pre-authenticate and then switching
54
 
 * back to EAPOL when pre-authentication has been completed.
55
 
 */
56
 
 
57
 
struct l2_packet_data;
58
 
 
59
 
struct l2_packet_ndisuio_global {
60
 
        int refcount;
61
 
        unsigned short first_proto;
62
 
        struct l2_packet_data *l2[2];
63
 
#ifdef _WIN32_WCE
64
 
        HANDLE rx_thread;
65
 
        HANDLE stop_request;
66
 
        HANDLE ready_for_read;
67
 
        HANDLE rx_processed;
68
 
#endif /* _WIN32_WCE */
69
 
};
70
 
 
71
 
static struct l2_packet_ndisuio_global *l2_ndisuio_global = NULL;
72
 
 
73
 
struct l2_packet_data {
74
 
        char ifname[100];
75
 
        u8 own_addr[ETH_ALEN];
76
 
        void (*rx_callback)(void *ctx, const u8 *src_addr,
77
 
                            const u8 *buf, size_t len);
78
 
        void *rx_callback_ctx;
79
 
        int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to
80
 
                     * rx_callback and l2_packet_send() */
81
 
        HANDLE rx_avail;
82
 
#ifndef _WIN32_WCE
83
 
        OVERLAPPED rx_overlapped;
84
 
#endif /* _WIN32_WCE */
85
 
        u8 rx_buf[1514];
86
 
        DWORD rx_written;
87
 
};
88
 
 
89
 
 
90
 
int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
91
 
{
92
 
        os_memcpy(addr, l2->own_addr, ETH_ALEN);
93
 
        return 0;
94
 
}
95
 
 
96
 
 
97
 
int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
98
 
                   const u8 *buf, size_t len)
99
 
{
100
 
        BOOL res;
101
 
        DWORD written;
102
 
        struct l2_ethhdr *eth;
103
 
#ifndef _WIN32_WCE
104
 
        OVERLAPPED overlapped;
105
 
#endif /* _WIN32_WCE */
106
 
        OVERLAPPED *o;
107
 
 
108
 
        if (l2 == NULL)
109
 
                return -1;
110
 
 
111
 
#ifdef _WIN32_WCE
112
 
        o = NULL;
113
 
#else /* _WIN32_WCE */
114
 
        os_memset(&overlapped, 0, sizeof(overlapped));
115
 
        o = &overlapped;
116
 
#endif /* _WIN32_WCE */
117
 
 
118
 
        if (l2->l2_hdr) {
119
 
                res = WriteFile(driver_ndis_get_ndisuio_handle(), buf, len,
120
 
                                &written, o);
121
 
        } else {
122
 
                size_t mlen = sizeof(*eth) + len;
123
 
                eth = os_malloc(mlen);
124
 
                if (eth == NULL)
125
 
                        return -1;
126
 
 
127
 
                os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
128
 
                os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
129
 
                eth->h_proto = htons(proto);
130
 
                os_memcpy(eth + 1, buf, len);
131
 
                res = WriteFile(driver_ndis_get_ndisuio_handle(), eth, mlen,
132
 
                                &written, o);
133
 
                os_free(eth);
134
 
        }
135
 
 
136
 
        if (!res) {
137
 
                DWORD err = GetLastError();
138
 
#ifndef _WIN32_WCE
139
 
                if (err == ERROR_IO_PENDING) {
140
 
                        /* For now, just assume that the packet will be sent in
141
 
                         * time before the next write happens. This could be
142
 
                         * cleaned up at some point to actually wait for
143
 
                         * completion before starting new writes.
144
 
                         */
145
 
                        return 0;
146
 
                }
147
 
#endif /* _WIN32_WCE */
148
 
                wpa_printf(MSG_DEBUG, "L2(NDISUIO): WriteFile failed: %d",
149
 
                           (int) GetLastError());
150
 
                return -1;
151
 
        }
152
 
 
153
 
        return 0;
154
 
}
155
 
 
156
 
 
157
 
static void l2_packet_callback(struct l2_packet_data *l2);
158
 
 
159
 
#ifdef _WIN32_WCE
160
 
static void l2_packet_rx_thread_try_read(struct l2_packet_data *l2)
161
 
{
162
 
        HANDLE handles[2];
163
 
 
164
 
        wpa_printf(MSG_MSGDUMP, "l2_packet_rx_thread: -> ReadFile");
165
 
        if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf,
166
 
                      sizeof(l2->rx_buf), &l2->rx_written, NULL)) {
167
 
                DWORD err = GetLastError();
168
 
                wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: ReadFile failed: "
169
 
                           "%d", (int) err);
170
 
                /*
171
 
                 * ReadFile on NDISUIO/WinCE returns ERROR_DEVICE_NOT_CONNECTED
172
 
                 * error whenever the connection is not up. Yield the thread to
173
 
                 * avoid triggering a busy loop. Connection event should stop
174
 
                 * us from looping for long, but we need to allow enough CPU
175
 
                 * for the main thread to process the media disconnection.
176
 
                 */
177
 
                Sleep(100);
178
 
                return;
179
 
        }
180
 
 
181
 
        wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Read %d byte packet",
182
 
                   (int) l2->rx_written);
183
 
 
184
 
        /*
185
 
         * Notify the main thread about the availability of a frame and wait
186
 
         * for the frame to be processed.
187
 
         */
188
 
        SetEvent(l2->rx_avail);
189
 
        handles[0] = l2_ndisuio_global->stop_request;
190
 
        handles[1] = l2_ndisuio_global->rx_processed;
191
 
        WaitForMultipleObjects(2, handles, FALSE, INFINITE);
192
 
        ResetEvent(l2_ndisuio_global->rx_processed);
193
 
}
194
 
 
195
 
 
196
 
static DWORD WINAPI l2_packet_rx_thread(LPVOID arg)
197
 
{
198
 
        struct l2_packet_data *l2 = arg;
199
 
        DWORD res;
200
 
        HANDLE handles[2];
201
 
        int run = 1;
202
 
 
203
 
        wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread started");
204
 
        handles[0] = l2_ndisuio_global->stop_request;
205
 
        handles[1] = l2_ndisuio_global->ready_for_read;
206
 
 
207
 
        /*
208
 
         * Unfortunately, NDISUIO on WinCE does not seem to support waiting
209
 
         * on the handle. There do not seem to be anything else that we could
210
 
         * wait for either. If one were to modify NDISUIO to set a named event
211
 
         * whenever packets are available, this event could be used here to
212
 
         * avoid having to poll for new packets or we could even move to use a
213
 
         * single threaded design.
214
 
         *
215
 
         * In addition, NDISUIO on WinCE is returning
216
 
         * ERROR_DEVICE_NOT_CONNECTED whenever ReadFile() is attempted while
217
 
         * the adapter is not in connected state. For now, we are just using a
218
 
         * local event to allow ReadFile calls only after having received NDIS
219
 
         * media connect event. This event could be easily converted to handle
220
 
         * another event if the protocol driver is replaced with somewhat more
221
 
         * useful design.
222
 
         */
223
 
 
224
 
        while (l2_ndisuio_global && run) {
225
 
                res = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
226
 
                switch (res) {
227
 
                case WAIT_OBJECT_0:
228
 
                        wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Received "
229
 
                                   "request to stop RX thread");
230
 
                        run = 0;
231
 
                        break;
232
 
                case WAIT_OBJECT_0 + 1:
233
 
                        l2_packet_rx_thread_try_read(l2);
234
 
                        break;
235
 
                case WAIT_FAILED:
236
 
                default:
237
 
                        wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: "
238
 
                                   "WaitForMultipleObjects failed: %d",
239
 
                                   (int) GetLastError());
240
 
                        run = 0;
241
 
                        break;
242
 
                }
243
 
        }
244
 
 
245
 
        wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread stopped");
246
 
 
247
 
        return 0;
248
 
}
249
 
#else /* _WIN32_WCE */
250
 
static int l2_ndisuio_start_read(struct l2_packet_data *l2, int recursive)
251
 
{
252
 
        os_memset(&l2->rx_overlapped, 0, sizeof(l2->rx_overlapped));
253
 
        l2->rx_overlapped.hEvent = l2->rx_avail;
254
 
        if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf,
255
 
                      sizeof(l2->rx_buf), &l2->rx_written, &l2->rx_overlapped))
256
 
        {
257
 
                DWORD err = GetLastError();
258
 
                if (err != ERROR_IO_PENDING) {
259
 
                        wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile failed: "
260
 
                                   "%d", (int) err);
261
 
                        return -1;
262
 
                }
263
 
                /*
264
 
                 * Once read is completed, l2_packet_rx_event() will be
265
 
                 * called.
266
 
                 */
267
 
        } else {
268
 
                wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile returned data "
269
 
                           "without wait for completion");
270
 
                if (!recursive)
271
 
                        l2_packet_callback(l2);
272
 
        }
273
 
 
274
 
        return 0;
275
 
}
276
 
#endif /* _WIN32_WCE */
277
 
 
278
 
 
279
 
static void l2_packet_callback(struct l2_packet_data *l2)
280
 
{
281
 
        const u8 *rx_buf, *rx_src;
282
 
        size_t rx_len;
283
 
        struct l2_ethhdr *ethhdr = (struct l2_ethhdr *) l2->rx_buf;
284
 
 
285
 
        wpa_printf(MSG_DEBUG, "L2(NDISUIO): Read %d bytes",
286
 
                   (int) l2->rx_written);
287
 
 
288
 
        if (l2->l2_hdr || l2->rx_written < sizeof(*ethhdr)) {
289
 
                rx_buf = (u8 *) ethhdr;
290
 
                rx_len = l2->rx_written;
291
 
        } else {
292
 
                rx_buf = (u8 *) (ethhdr + 1);
293
 
                rx_len = l2->rx_written - sizeof(*ethhdr);
294
 
        }
295
 
        rx_src = ethhdr->h_source;
296
 
 
297
 
        l2->rx_callback(l2->rx_callback_ctx, rx_src, rx_buf, rx_len);
298
 
#ifndef _WIN32_WCE
299
 
        l2_ndisuio_start_read(l2, 1);
300
 
#endif /* _WIN32_WCE */
301
 
}
302
 
 
303
 
 
304
 
static void l2_packet_rx_event(void *eloop_data, void *user_data)
305
 
{
306
 
        struct l2_packet_data *l2 = eloop_data;
307
 
 
308
 
        if (l2_ndisuio_global)
309
 
                l2 = l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1];
310
 
 
311
 
        ResetEvent(l2->rx_avail);
312
 
 
313
 
#ifndef _WIN32_WCE
314
 
        if (!GetOverlappedResult(driver_ndis_get_ndisuio_handle(),
315
 
                                 &l2->rx_overlapped, &l2->rx_written, FALSE)) {
316
 
                wpa_printf(MSG_DEBUG, "L2(NDISUIO): GetOverlappedResult "
317
 
                           "failed: %d", (int) GetLastError());
318
 
                return;
319
 
        }
320
 
#endif /* _WIN32_WCE */
321
 
 
322
 
        l2_packet_callback(l2);
323
 
 
324
 
#ifdef _WIN32_WCE
325
 
        SetEvent(l2_ndisuio_global->rx_processed);
326
 
#endif /* _WIN32_WCE */
327
 
}
328
 
 
329
 
 
330
 
static int l2_ndisuio_set_ether_type(unsigned short protocol)
331
 
{
332
 
        USHORT proto = htons(protocol);
333
 
        DWORD written;
334
 
 
335
 
        if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(),
336
 
                             IOCTL_NDISUIO_SET_ETHER_TYPE, &proto,
337
 
                             sizeof(proto), NULL, 0, &written, NULL)) {
338
 
                wpa_printf(MSG_ERROR, "L2(NDISUIO): "
339
 
                           "IOCTL_NDISUIO_SET_ETHER_TYPE failed: %d",
340
 
                           (int) GetLastError());
341
 
                return -1;
342
 
        }
343
 
 
344
 
        return 0;
345
 
}
346
 
 
347
 
 
348
 
struct l2_packet_data * l2_packet_init(
349
 
        const char *ifname, const u8 *own_addr, unsigned short protocol,
350
 
        void (*rx_callback)(void *ctx, const u8 *src_addr,
351
 
                            const u8 *buf, size_t len),
352
 
        void *rx_callback_ctx, int l2_hdr)
353
 
{
354
 
        struct l2_packet_data *l2;
355
 
 
356
 
        if (l2_ndisuio_global == NULL) {
357
 
                l2_ndisuio_global = os_zalloc(sizeof(*l2_ndisuio_global));
358
 
                if (l2_ndisuio_global == NULL)
359
 
                        return NULL;
360
 
                l2_ndisuio_global->first_proto = protocol;
361
 
        }
362
 
        if (l2_ndisuio_global->refcount >= 2) {
363
 
                wpa_printf(MSG_ERROR, "L2(NDISUIO): Not more than two "
364
 
                           "simultaneous connections allowed");
365
 
                return NULL;
366
 
        }
367
 
        l2_ndisuio_global->refcount++;
368
 
 
369
 
        l2 = os_zalloc(sizeof(struct l2_packet_data));
370
 
        if (l2 == NULL)
371
 
                return NULL;
372
 
        l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1] = l2;
373
 
 
374
 
        os_strncpy(l2->ifname, ifname, sizeof(l2->ifname));
375
 
        l2->rx_callback = rx_callback;
376
 
        l2->rx_callback_ctx = rx_callback_ctx;
377
 
        l2->l2_hdr = l2_hdr;
378
 
 
379
 
        if (own_addr)
380
 
                os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
381
 
 
382
 
        if (l2_ndisuio_set_ether_type(protocol) < 0) {
383
 
                os_free(l2);
384
 
                return NULL;
385
 
        }
386
 
 
387
 
        if (l2_ndisuio_global->refcount > 1) {
388
 
                wpa_printf(MSG_DEBUG, "L2(NDISUIO): Temporarily setting "
389
 
                           "filtering ethertype to %04x", protocol);
390
 
                if (l2_ndisuio_global->l2[0])
391
 
                        l2->rx_avail = l2_ndisuio_global->l2[0]->rx_avail;
392
 
                return l2;
393
 
        }
394
 
 
395
 
        l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
396
 
        if (l2->rx_avail == NULL) {
397
 
                os_free(l2);
398
 
                return NULL;
399
 
        }
400
 
 
401
 
        eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail),
402
 
                             l2_packet_rx_event, l2, NULL);
403
 
 
404
 
#ifdef _WIN32_WCE
405
 
        l2_ndisuio_global->stop_request = CreateEvent(NULL, TRUE, FALSE, NULL);
406
 
        /*
407
 
         * This event is being set based on media connect/disconnect
408
 
         * notifications in driver_ndis.c.
409
 
         */
410
 
        l2_ndisuio_global->ready_for_read =
411
 
                CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected"));
412
 
        l2_ndisuio_global->rx_processed = CreateEvent(NULL, TRUE, FALSE, NULL);
413
 
        if (l2_ndisuio_global->stop_request == NULL ||
414
 
            l2_ndisuio_global->ready_for_read == NULL ||
415
 
            l2_ndisuio_global->rx_processed == NULL) {
416
 
                if (l2_ndisuio_global->stop_request) {
417
 
                        CloseHandle(l2_ndisuio_global->stop_request);
418
 
                        l2_ndisuio_global->stop_request = NULL;
419
 
                }
420
 
                if (l2_ndisuio_global->ready_for_read) {
421
 
                        CloseHandle(l2_ndisuio_global->ready_for_read);
422
 
                        l2_ndisuio_global->ready_for_read = NULL;
423
 
                }
424
 
                if (l2_ndisuio_global->rx_processed) {
425
 
                        CloseHandle(l2_ndisuio_global->rx_processed);
426
 
                        l2_ndisuio_global->rx_processed = NULL;
427
 
                }
428
 
                eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
429
 
                os_free(l2);
430
 
                return NULL;
431
 
        }
432
 
 
433
 
        l2_ndisuio_global->rx_thread = CreateThread(NULL, 0,
434
 
                                                    l2_packet_rx_thread, l2, 0,
435
 
                                                    NULL);
436
 
        if (l2_ndisuio_global->rx_thread == NULL) {
437
 
                wpa_printf(MSG_INFO, "L2(NDISUIO): Failed to create RX "
438
 
                           "thread: %d", (int) GetLastError());
439
 
                eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
440
 
                CloseHandle(l2_ndisuio_global->stop_request);
441
 
                l2_ndisuio_global->stop_request = NULL;
442
 
                os_free(l2);
443
 
                return NULL;
444
 
        }
445
 
#else /* _WIN32_WCE */
446
 
        l2_ndisuio_start_read(l2, 0);
447
 
#endif /* _WIN32_WCE */
448
 
 
449
 
        return l2;
450
 
}
451
 
 
452
 
 
453
 
void l2_packet_deinit(struct l2_packet_data *l2)
454
 
{
455
 
        if (l2 == NULL)
456
 
                return;
457
 
 
458
 
        if (l2_ndisuio_global) {
459
 
                l2_ndisuio_global->refcount--;
460
 
                l2_ndisuio_global->l2[l2_ndisuio_global->refcount] = NULL;
461
 
                if (l2_ndisuio_global->refcount) {
462
 
                        wpa_printf(MSG_DEBUG, "L2(NDISUIO): restore filtering "
463
 
                                   "ethertype to %04x",
464
 
                                   l2_ndisuio_global->first_proto);
465
 
                        l2_ndisuio_set_ether_type(
466
 
                                l2_ndisuio_global->first_proto);
467
 
                        return;
468
 
                }
469
 
 
470
 
#ifdef _WIN32_WCE
471
 
                wpa_printf(MSG_DEBUG, "L2(NDISUIO): Waiting for RX thread to "
472
 
                           "stop");
473
 
                SetEvent(l2_ndisuio_global->stop_request);
474
 
                /*
475
 
                 * Cancel pending ReadFile() in the RX thread (if we were still
476
 
                 * connected at this point).
477
 
                 */
478
 
                if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(),
479
 
                                     IOCTL_CANCEL_READ, NULL, 0, NULL, 0, NULL,
480
 
                                     NULL)) {
481
 
                        wpa_printf(MSG_DEBUG, "L2(NDISUIO): IOCTL_CANCEL_READ "
482
 
                                   "failed: %d", (int) GetLastError());
483
 
                        /* RX thread will exit blocking ReadFile once NDISUIO
484
 
                         * notices that the adapter is disconnected. */
485
 
                }
486
 
                WaitForSingleObject(l2_ndisuio_global->rx_thread, INFINITE);
487
 
                wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread exited");
488
 
                CloseHandle(l2_ndisuio_global->rx_thread);
489
 
                CloseHandle(l2_ndisuio_global->stop_request);
490
 
                CloseHandle(l2_ndisuio_global->ready_for_read);
491
 
                CloseHandle(l2_ndisuio_global->rx_processed);
492
 
#endif /* _WIN32_WCE */
493
 
 
494
 
                os_free(l2_ndisuio_global);
495
 
                l2_ndisuio_global = NULL;
496
 
        }
497
 
 
498
 
#ifndef _WIN32_WCE
499
 
        CancelIo(driver_ndis_get_ndisuio_handle());
500
 
#endif /* _WIN32_WCE */
501
 
 
502
 
        eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
503
 
        CloseHandle(l2->rx_avail);
504
 
        os_free(l2);
505
 
}
506
 
 
507
 
 
508
 
int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
509
 
{
510
 
        return -1;
511
 
}
512
 
 
513
 
 
514
 
void l2_packet_notify_auth_start(struct l2_packet_data *l2)
515
 
{
516
 
}