~ubuntu-branches/ubuntu/gutsy/wpasupplicant/gutsy

« back to all changes in this revision

Viewing changes to src/l2_packet/l2_packet_ndis.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler, Kel Modderman, Reinhard Tartler
  • Date: 2007-06-17 10:33:31 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20070617103331-yeag0brnomq30kiu
Tags: 0.6.0-1
[Kel Modderman]
* New upstream release.
  - restructured source layout
* Adjust debian/wpasupplicant.examples, debian/wpagui.install,
  debian/wpasupplicant.install, debian/wpasupplicant.manpages, and
  debian/wpasupplicant.docs for new layout.
* Redjust debian/patches/30_dbus_policy.dpatch and
  debian/patches/40_debian_doc_examples.dpatch to apply against new layout.
* Drop debian/patches/10_config.dpatch and
  debian/patches/21_madwifi_includes.dpatch.
* Introduce makefile fragment for wpa_supplicant .config creation. Call it
  from debian/rules. It is named debian/dot.config.mk.
* Add WPADIR variable to debian/rules, adjust build and install targets to
  use WPADIR.
* Update madwifi_headers patch with code from current madwifi SVN trunk.
* Damage control: allow 'wpa-conf managed' to pass through without failure
  for those people who followed the poor example outlined in the hidden
  ssid's section of README.modes. Also remove the offending line from the
  documentaion. (Closes: #428137)

[Reinhard Tartler]
* Fix building wpagui.
* remove debian/wpasupplicant.preinst, since we don't support upgrades
  from oldstable. This way we don't need to look at /var/lib/dpkg/status
  anymore, which is unreliable anyway. Makes lintian happy.

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_strlcpy(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
}