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

« back to all changes in this revision

Viewing changes to l2_packet_ndis.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler, Alexander Sack
  • Date: 2007-08-26 16:06:57 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070826160657-2m8pxoweuxe8f93t
Tags: 0.6.0+0.5.8-0ubuntu1
* New upstream release
* remove patch 11_erroneous_manpage_ref, applied upstream
* remove patch 25_wpas_dbus_unregister_iface_fix, applied upstream

[ Alexander Sack ]
* bumping upstream version to replace development version 0.6.0 with
  this package from stable release branch.
* attempt to fix wierd timeout and high latency issues by going
  back to stable upstream version (0.5.9) (LP: #140763,
  LP: #141233).

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
}