~ubuntu-branches/debian/sid/acx100/sid

« back to all changes in this revision

Viewing changes to src/acx100_conv.c

  • Committer: Bazaar Package Importer
  • Author(s): Miguel Gea Milvaques
  • Date: 2005-04-13 23:36:11 UTC
  • Revision ID: james.westby@ubuntu.com-20050413233611-5ec8mnua3b9k3t4u
Tags: upstream-0.2.0pre8+52
ImportĀ upstreamĀ versionĀ 0.2.0pre8+52

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* src/p80211conv.c - conversion between 802.11 and ethernet
 
2
 *
 
3
 * --------------------------------------------------------------------
 
4
 *
 
5
 * Copyright (C) 2003  ACX100 Open Source Project
 
6
 *
 
7
 *   The contents of this file are subject to the Mozilla Public
 
8
 *   License Version 1.1 (the "License"); you may not use this file
 
9
 *   except in compliance with the License. You may obtain a copy of
 
10
 *   the License at http://www.mozilla.org/MPL/
 
11
 *
 
12
 *   Software distributed under the License is distributed on an "AS
 
13
 *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
14
 *   implied. See the License for the specific language governing
 
15
 *   rights and limitations under the License.
 
16
 *
 
17
 *   Alternatively, the contents of this file may be used under the
 
18
 *   terms of the GNU Public License version 2 (the "GPL"), in which
 
19
 *   case the provisions of the GPL are applicable instead of the
 
20
 *   above.  If you wish to allow the use of your version of this file
 
21
 *   only under the terms of the GPL and not to allow others to use
 
22
 *   your version of this file under the MPL, indicate your decision
 
23
 *   by deleting the provisions above and replace them with the notice
 
24
 *   and other provisions required by the GPL.  If you do not delete
 
25
 *   the provisions above, a recipient may use your version of this
 
26
 *   file under either the MPL or the GPL.
 
27
 *
 
28
 * --------------------------------------------------------------------
 
29
 *
 
30
 * This code is based on elements which are
 
31
 * Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
 
32
 * info@linux-wlan.com
 
33
 * http://www.linux-wlan.com
 
34
 *
 
35
 * --------------------------------------------------------------------
 
36
 *
 
37
 * Inquiries regarding the ACX100 Open Source Project can be
 
38
 * made directly to:
 
39
 *
 
40
 * acx100-users@lists.sf.net
 
41
 * http://acx100.sf.net
 
42
 *
 
43
 * --------------------------------------------------------------------
 
44
 */
 
45
 
 
46
#ifdef S_SPLINT_S /* some crap that splint needs to not crap out */
 
47
#define __signed__ signed
 
48
#define __u64 unsigned long long
 
49
#define loff_t unsigned long
 
50
#define sigval_t unsigned long
 
51
#define siginfo_t unsigned long
 
52
#define stack_t unsigned long
 
53
#define __s64 signed long long
 
54
#endif
 
55
#include <linux/config.h>
 
56
#include <linux/version.h>
 
57
 
 
58
#include <linux/skbuff.h>
 
59
#include <linux/if_arp.h>
 
60
#include <linux/etherdevice.h>
 
61
#include <linux/wireless.h>
 
62
#if WIRELESS_EXT >= 13
 
63
#include <net/iw_handler.h>
 
64
#endif
 
65
 
 
66
#include <acx.h>
 
67
 
 
68
/*----------------------------------------------------------------
 
69
* acx_rxdesc_to_txdesc
 
70
*
 
71
* Converts a rx descriptor to a tx descriptor.
 
72
*
 
73
* Arguments:
 
74
*
 
75
* Returns:
 
76
*
 
77
* Side effects:
 
78
*
 
79
* Call context:
 
80
*
 
81
* STATUS: 
 
82
*       FINISHED
 
83
*
 
84
* Comment:
 
85
*
 
86
*----------------------------------------------------------------*/
 
87
 
 
88
void acx_rxdesc_to_txdesc(const struct rxhostdescriptor *rxhostdesc,
 
89
                                struct txdescriptor *txdesc)
 
90
{
 
91
        struct txhostdescriptor *payload;
 
92
        struct txhostdescriptor *header;
 
93
        
 
94
        header = txdesc->fixed_size.s.host_desc;
 
95
        payload = header + 1;
 
96
        
 
97
        payload->data_offset = 0;
 
98
        header->data_offset = 0;
 
99
        
 
100
        memcpy(header->data, &rxhostdesc->data->hdr_a3, WLAN_HDR_A3_LEN);
 
101
 
 
102
        /* BUG??? rxhostdesc->data->data was 12 bytes farther that 
 
103
        ** in reality because wlan_hdr was erroneously defined to have 3 extra void*
 
104
        ** fields... Bug should have been mangling AP bridged packets. Fixed */
 
105
        memcpy(payload->data, &rxhostdesc->data->data_a3,
 
106
                MAC_CNT_RCVD(rxhostdesc->data) - WLAN_HDR_A3_LEN);
 
107
 
 
108
}
 
109
 
 
110
/*----------------------------------------------------------------
 
111
* proto_is_stt
 
112
*
 
113
* Searches the 802.1h Selective Translation Table for a given 
 
114
* protocol.
 
115
*
 
116
* Arguments:
 
117
*       prottype        protocol number (in host order) to search for.
 
118
*
 
119
* Returns:
 
120
*       1 - if the table is empty or a match is found.
 
121
*       0 - if the table is non-empty and a match is not found.
 
122
*
 
123
* Side effects:
 
124
*
 
125
* Call context:
 
126
*       May be called in interrupt or non-interrupt context
 
127
*
 
128
* STATUS:
 
129
*
 
130
* Comment:
 
131
*       Based largely on p80211conv.c of the linux-wlan-ng project
 
132
*
 
133
*----------------------------------------------------------------*/
 
134
 
 
135
static inline int proto_is_stt(unsigned int proto)
 
136
{
 
137
        /* Always return found for now.  This is the behavior used by the */
 
138
        /*  Zoom Win95 driver when 802.1h mode is selected */
 
139
        /* TODO: If necessary, add an actual search we'll probably
 
140
                 need this to match the CMAC's way of doing things.
 
141
                 Need to do some testing to confirm.
 
142
        */
 
143
 
 
144
        if (proto == 0x80f3)  /* APPLETALK */
 
145
                return 1;
 
146
 
 
147
        return 0;
 
148
/*      return ((prottype == ETH_P_AARP) || (prottype == ETH_P_IPX)); */
 
149
}
 
150
 
 
151
/* Helpers */
 
152
 
 
153
static inline void store_llc_snap(struct wlan_llc *llc)
 
154
{
 
155
        llc->dsap = 0xaa;       /* SNAP, see IEEE 802 */
 
156
        llc->ssap = 0xaa;
 
157
        llc->ctl = 0x03;
 
158
}
 
159
static inline int llc_is_snap(const struct wlan_llc *llc)
 
160
{
 
161
        return (llc->dsap == 0xaa)
 
162
        && (llc->ssap == 0xaa)
 
163
        && (llc->ctl == 0x03);
 
164
}
 
165
static inline void store_oui_rfc1042(struct wlan_snap *snap)
 
166
{
 
167
        snap->oui[0] = 0;
 
168
        snap->oui[1] = 0;
 
169
        snap->oui[2] = 0;
 
170
}
 
171
static inline int oui_is_rfc1042(const struct wlan_snap *snap)
 
172
{
 
173
        return (snap->oui[0] == 0)
 
174
        && (snap->oui[1] == 0)
 
175
        && (snap->oui[2] == 0);
 
176
}
 
177
static inline void store_oui_8021h(struct wlan_snap *snap)
 
178
{
 
179
        snap->oui[0] = 0;
 
180
        snap->oui[1] = 0;
 
181
        snap->oui[2] = 0xf8;
 
182
}
 
183
static inline int oui_is_8021h(const struct wlan_snap *snap)
 
184
{
 
185
        return (snap->oui[0] == 0)
 
186
        && (snap->oui[1] == 0)
 
187
        && (snap->oui[2] == 0xf8);
 
188
}
 
189
 
 
190
/*----------------------------------------------------------------
 
191
* acx_ether_to_txdesc
 
192
*
 
193
* Uses the contents of the ether frame to build the elements of 
 
194
* the 802.11 frame.
 
195
*
 
196
* We don't actually set up the frame header here.  That's the 
 
197
* MAC's job.  We're only handling conversion of DIXII or 802.3+LLC 
 
198
* frames to something that works with 802.11.
 
199
*
 
200
* Arguments:
 
201
*
 
202
* Returns:
 
203
*
 
204
* Side effects:
 
205
*
 
206
* Call context:
 
207
*
 
208
* STATUS: 
 
209
*       FINISHED
 
210
*
 
211
* Comment: 
 
212
*       Based largely on p80211conv.c of the linux-wlan-ng project
 
213
*
 
214
*----------------------------------------------------------------*/
 
215
 
 
216
int acx_ether_to_txdesc(wlandevice_t *priv,
 
217
                         struct txdescriptor *tx_desc,
 
218
                         const struct sk_buff *skb)
 
219
{
 
220
        struct txhostdescriptor *header;
 
221
        struct txhostdescriptor *payload;
 
222
        union p80211_hdr *w_hdr;
 
223
        struct wlan_ethhdr *e_hdr; 
 
224
        struct wlan_llc *e_llc;
 
225
        struct wlan_snap *e_snap;
 
226
        const u8 *a1,*a2,*a3;
 
227
        int header_len,payload_len;
 
228
        u16 proto;              /* protocol type or data length, depending on whether DIX or 802.3 ethernet format */
 
229
        u16 fc;
 
230
 
 
231
        FN_ENTER;
 
232
 
 
233
        if (unlikely(0 == skb->len)) {
 
234
                acxlog(L_DEBUG, "zero-length skb!\n");
 
235
                FN_EXIT1(NOT_OK);
 
236
                return NOT_OK;
 
237
        }
 
238
 
 
239
        header = tx_desc->fixed_size.s.host_desc;
 
240
        if ((unsigned long)0xffffffff == (unsigned long)header) /* FIXME: happens on card eject; better method? */
 
241
                return NOT_OK;
 
242
        payload = header + 1;
 
243
 
 
244
        switch (priv->mode) {
 
245
        case ACX_MODE_MONITOR:
 
246
                /* FIXME: skb size check... */
 
247
                header->length = 0;
 
248
                header->data_offset = 0;
 
249
                memcpy(payload->data, skb->data, skb->len);
 
250
                payload->length = cpu_to_le16(skb->len);
 
251
                payload->data_offset = 0;
 
252
                tx_desc->total_length = cpu_to_le16(skb->len);
 
253
                FN_EXIT0();
 
254
                return OK;
 
255
        }
 
256
 
 
257
        /* step 1: classify ether frame, DIX or 802.3? */
 
258
        e_hdr = (wlan_ethhdr_t *)skb->data;
 
259
        proto = ntohs(e_hdr->type);
 
260
        if (proto <= 1500) {
 
261
                acxlog(L_DEBUG, "tx: 802.3 len: %d\n", skb->len);
 
262
                /* codes <= 1500 reserved for 802.3 lengths */
 
263
                /* it's 802.3, pass ether payload unchanged, */
 
264
                /* trim off ethernet header and copy payload to tx_desc */
 
265
                header_len = WLAN_HDR_A3_LEN;
 
266
                /* TODO: must be equal to skb->len - sizeof(wlan_ethhdr_t), no? */
 
267
                /* then we can do payload_len = ... after this big if() */
 
268
                payload_len = proto;
 
269
        } else {
 
270
                /* it's DIXII, time for some conversion */
 
271
                /* Create 802.11 packet. Header also contains llc and snap. */
 
272
 
 
273
                acxlog(L_DEBUG, "tx: DIXII len: %d\n", skb->len);
 
274
 
 
275
                /* size of header is 802.11 header + llc + snap */
 
276
                header_len = WLAN_HDR_A3_LEN + sizeof(wlan_llc_t) + sizeof(wlan_snap_t);
 
277
                /* llc is located behind the 802.11 header */
 
278
                e_llc = (wlan_llc_t*)(header->data + WLAN_HDR_A3_LEN);
 
279
                /* snap is located behind the llc */
 
280
                e_snap = (wlan_snap_t*)((u8*)e_llc + sizeof(wlan_llc_t));
 
281
                        
 
282
                /* setup the LLC header */
 
283
                store_llc_snap(e_llc);
 
284
 
 
285
                /* setup the SNAP header */
 
286
                e_snap->type = htons(proto);
 
287
                if (proto_is_stt(proto)) {
 
288
                        store_oui_8021h(e_snap);
 
289
                } else {
 
290
                        store_oui_rfc1042(e_snap);
 
291
                }
 
292
                /* trim off ethernet header and copy payload to tx_desc */
 
293
                payload_len = skb->len - sizeof(wlan_ethhdr_t);
 
294
        }
 
295
        /* TODO: can we just let acx DMA payload from skb instead? */
 
296
        memcpy(payload->data, skb->data + sizeof(wlan_ethhdr_t), payload_len);
 
297
        payload->length = cpu_to_le16(payload_len);
 
298
        header->length = cpu_to_le16(header_len);
 
299
        payload->data_offset = 0;
 
300
        header->data_offset = 0;
 
301
        
 
302
        /* calculate total tx_desc length */
 
303
        tx_desc->total_length = cpu_to_le16(payload_len + header_len);
 
304
 
 
305
        /* Set up the 802.11 header */
 
306
        w_hdr = (p80211_hdr_t*)header->data;
 
307
 
 
308
        /* It's a data frame */
 
309
        fc = (WF_FTYPE_DATAi | WF_FSTYPE_DATAONLYi);
 
310
 
 
311
        switch (priv->mode) {
 
312
        case ACX_MODE_0_ADHOC:
 
313
                a1 = e_hdr->daddr;
 
314
                a2 = priv->dev_addr;
 
315
                a3 = priv->bssid;
 
316
                break;
 
317
        case ACX_MODE_2_STA:
 
318
                SET_BIT(fc, WF_FC_TODSi);
 
319
                a1 = priv->bssid;
 
320
                a2 = priv->dev_addr;
 
321
                a3 = e_hdr->daddr;
 
322
                break;
 
323
        case ACX_MODE_3_AP:
 
324
                SET_BIT(fc, WF_FC_FROMDSi);
 
325
                a1 = e_hdr->daddr;
 
326
                a2 = priv->bssid;
 
327
                a3 = e_hdr->saddr;
 
328
                break;
 
329
        default:
 
330
                acxlog(L_STD, "Error: Converting eth to wlan in unknown mode\n");
 
331
                goto fail;
 
332
        }
 
333
        MAC_COPY(w_hdr->a3.a1, a1);
 
334
        MAC_COPY(w_hdr->a3.a2, a2);
 
335
        MAC_COPY(w_hdr->a3.a3, a3);
 
336
 
 
337
        if (priv->wep_enabled)
 
338
                SET_BIT(fc, WF_FC_ISWEPi);
 
339
                
 
340
        w_hdr->a3.fc = fc;
 
341
        w_hdr->a3.dur = 0;
 
342
        w_hdr->a3.seq = 0;
 
343
 
 
344
#if DEBUG_CONVERT
 
345
        if (debug & L_DATA) {
 
346
                int i;
 
347
                printk("Original eth frame [%d]: ", skb->len);
 
348
                for (i = 0; i < skb->len; i++)
 
349
                        printk(" %02x", ((u8 *) skb->data)[i]);
 
350
                        printk("\n");
 
351
 
 
352
                printk("802.11 header [%d]: ", header_len));
 
353
                for (i = 0; i < header_len; i++)
 
354
                        printk(" %02x", header->data[i]);
 
355
                printk("\n");
 
356
 
 
357
                printk("802.11 payload [%d]: ", payload_len);
 
358
                for (i = 0; i < payload_len); i++)
 
359
                        printk(" %02x", payload->data[i]);
 
360
                printk("\n");
 
361
        }
 
362
#endif
 
363
 
 
364
fail:
 
365
        FN_EXIT0();
 
366
        return OK;
 
367
}
 
368
 
 
369
/*----------------------------------------------------------------
 
370
* acx_rxdesc_to_ether
 
371
*
 
372
* Uses the contents of a received 802.11 frame to build an ether
 
373
* frame.
 
374
*
 
375
* This function extracts the src and dest address from the 802.11
 
376
* frame to use in the construction of the eth frame.
 
377
*
 
378
* Arguments:
 
379
*
 
380
* Returns:
 
381
*
 
382
* Side effects:
 
383
*
 
384
* Call context:
 
385
*
 
386
* STATUS: 
 
387
*       FINISHED
 
388
*
 
389
* Comment:  
 
390
*       Based largely on p80211conv.c of the linux-wlan-ng project
 
391
*
 
392
*----------------------------------------------------------------*/
 
393
 
 
394
/*@null@*/ struct sk_buff *acx_rxdesc_to_ether(wlandevice_t *priv, const struct
 
395
                rxhostdescriptor *rx_desc)
 
396
{
 
397
        union p80211_hdr *w_hdr;
 
398
        struct wlan_ethhdr *e_hdr;
 
399
        struct wlan_llc *e_llc;
 
400
        struct wlan_snap *e_snap;
 
401
        struct sk_buff *skb;
 
402
        const u8 *daddr;
 
403
        const u8 *saddr;
 
404
        u8 *e_payload;
 
405
        int buflen;
 
406
        int payload_length;
 
407
        unsigned int payload_offset;
 
408
        u16 fc;
 
409
 
 
410
        FN_ENTER;
 
411
 
 
412
        payload_length = MAC_CNT_RCVD(rx_desc->data) - WLAN_HDR_A3_LEN;
 
413
        payload_offset = WLAN_HDR_A3_LEN;
 
414
 
 
415
        w_hdr = (p80211_hdr_t*)&rx_desc->data->hdr_a3;
 
416
 
 
417
        /* check if additional header is included */
 
418
        if (priv->rx_config_1 & RX_CFG1_INCLUDE_ADDIT_HDR) {
 
419
                /* Mmm, strange, when receiving a packet, 4 bytes precede the packet. Is it the CRC ? */
 
420
                w_hdr = (p80211_hdr_t*)(((u8*)w_hdr) + WLAN_CRC_LEN);
 
421
                payload_length -= WLAN_CRC_LEN;
 
422
        }
 
423
 
 
424
        /* setup some vars for convenience */
 
425
        fc = w_hdr->a3.fc;
 
426
        switch (WF_FC_FROMTODSi & fc) {
 
427
        case 0:
 
428
                daddr = w_hdr->a3.a1;
 
429
                saddr = w_hdr->a3.a2;
 
430
                break;
 
431
        case WF_FC_FROMDSi:
 
432
                daddr = w_hdr->a3.a1;
 
433
                saddr = w_hdr->a3.a3;
 
434
                break;
 
435
        case WF_FC_TODSi:
 
436
                daddr = w_hdr->a3.a3;
 
437
                saddr = w_hdr->a3.a2;
 
438
                break;
 
439
        default: /* WF_FC_FROMTODSi */
 
440
                payload_offset = WLAN_HDR_A4_LEN;
 
441
                payload_length -= ( WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN );
 
442
                if (0 > payload_length) {
 
443
                        acxlog(L_STD, "A4 frame too short!\n");
 
444
                        FN_EXIT1((int)NULL);
 
445
                        return NULL;
 
446
                }
 
447
                daddr = w_hdr->a4.a3;
 
448
                saddr = w_hdr->a4.a4;
 
449
        }
 
450
        
 
451
        if ((WF_FC_ISWEPi & fc) && (CHIPTYPE_ACX100 == priv->chip_type)) {
 
452
                /* chop off the IV+ICV WEP header and footer */
 
453
                acxlog(L_DATA | L_DEBUG, "rx: it's a WEP packet, chopping off IV and ICV.\n");
 
454
                payload_length -= 8;
 
455
                payload_offset += 4;
 
456
        }
 
457
 
 
458
        e_hdr = (wlan_ethhdr_t*) ((u8*) w_hdr + payload_offset);
 
459
 
 
460
        e_llc = (wlan_llc_t*) e_hdr;
 
461
        e_snap = (wlan_snap_t*) (e_llc+1);
 
462
        e_payload = (u8*) (e_snap+1);
 
463
 
 
464
        acxlog(L_DATA, "rx: payload_offset %i, payload_length %i\n", payload_offset, payload_length);
 
465
        acxlog(L_XFER | L_DATA,
 
466
                "rx: frame info: llc.dsap %X, llc.ssap %X, llc.ctl %X, snap.oui %02X%02X%02X, snap.type %X\n",
 
467
                e_llc->dsap, e_llc->ssap,
 
468
                e_llc->ctl, e_snap->oui[0],
 
469
                e_snap->oui[1], e_snap->oui[2],
 
470
                e_snap->type);
 
471
 
 
472
        /* Test for the various encodings */
 
473
        if ((payload_length >= sizeof(wlan_ethhdr_t))
 
474
         && ((e_llc->dsap != 0xaa) || (e_llc->ssap != 0xaa))
 
475
         && (   (mac_is_equal(daddr, e_hdr->daddr))
 
476
             || (mac_is_equal(saddr, e_hdr->saddr))
 
477
            )
 
478
        ) {
 
479
                acxlog(L_DEBUG | L_DATA, "rx: 802.3 ENCAP len: %d\n", payload_length);
 
480
                /* 802.3 Encapsulated */
 
481
                /* Test for an overlength frame */
 
482
 
 
483
                if (unlikely(payload_length > WLAN_MAX_ETHFRM_LEN)) {
 
484
                        /* A bogus length ethfrm has been encap'd. */
 
485
                        /* Is someone trying an oflow attack? */
 
486
                        acxlog(L_STD, "rx: ENCAP frame too large (%d > %d)\n", 
 
487
                                payload_length, WLAN_MAX_ETHFRM_LEN);
 
488
                        FN_EXIT1((int)NULL);
 
489
                        return NULL;
 
490
                }
 
491
 
 
492
                /* allocate space and setup host buffer */
 
493
                buflen = payload_length;
 
494
                /* FIXME: implement skb ring buffer similar to
 
495
                 * xircom_tulip_cb.c? */
 
496
                skb = dev_alloc_skb(buflen + 2);        /* +2 is attempt to align IP header */
 
497
                if (unlikely(!skb)) {
 
498
                        acxlog(L_STD, "rx: FAILED to allocate skb\n");
 
499
                        FN_EXIT1((int)NULL);
 
500
                        return NULL;
 
501
                }
 
502
                skb_reserve(skb, 2);
 
503
                skb_put(skb, buflen);           /* make room */
 
504
 
 
505
                /* now copy the data from the 80211 frame */
 
506
                memcpy(skb->data, e_hdr, payload_length);       /* copy the data */
 
507
 
 
508
        } else if ( (payload_length >= sizeof(wlan_llc_t)+sizeof(wlan_snap_t)) && llc_is_snap(e_llc) ) {
 
509
                /* it's a SNAP */
 
510
 
 
511
                if ( !oui_is_rfc1042(e_snap) || (proto_is_stt(ieee2host16(e_snap->type)) /* && (ethconv == WLAN_ETHCONV_8021h) */)) {
 
512
                        acxlog(L_DEBUG | L_DATA, "rx: SNAP+RFC1042 len: %d\n", payload_length);
 
513
                        /* it's a SNAP + RFC1042 frame && protocol is in STT */
 
514
                        /* build 802.3 + RFC1042 */
 
515
 
 
516
                        /* Test for an overlength frame */
 
517
                        if (unlikely(payload_length + WLAN_ETHHDR_LEN > WLAN_MAX_ETHFRM_LEN)) {
 
518
                                /* A bogus length ethfrm has been sent. */
 
519
                                /* Is someone trying an oflow attack? */
 
520
                                acxlog(L_STD, "rx: SNAP frame too large (%d > %d)\n", 
 
521
                                        payload_length, WLAN_MAX_ETHFRM_LEN);
 
522
                                FN_EXIT1((int)NULL);
 
523
                                return NULL;
 
524
                        }
 
525
 
 
526
                        /* allocate space and setup host buffer */
 
527
                        buflen = payload_length + WLAN_ETHHDR_LEN;
 
528
                        skb = dev_alloc_skb(buflen + 2);        /* +2 is attempt to align IP header */
 
529
                        if (unlikely(!skb)) {
 
530
                                acxlog(L_STD, "rx: FAILED to allocate skb\n");
 
531
                                FN_EXIT1((int)NULL);
 
532
                                return NULL;
 
533
                        }
 
534
                        skb_reserve(skb, 2);
 
535
                        skb_put(skb, buflen);           /* make room */
 
536
 
 
537
                        /* create 802.3 header */
 
538
                        e_hdr = (wlan_ethhdr_t*) skb->data;
 
539
                        MAC_COPY(e_hdr->daddr, daddr);
 
540
                        MAC_COPY(e_hdr->saddr, saddr); 
 
541
                        e_hdr->type = htons(payload_length);
 
542
 
 
543
                        /* Now copy the data from the 80211 frame.
 
544
                           Make room in front for the eth header, and keep the 
 
545
                           llc and snap from the 802.11 payload */
 
546
                        memcpy(skb->data + WLAN_ETHHDR_LEN, 
 
547
                               e_llc, 
 
548
                               payload_length);
 
549
                       
 
550
                } else {
 
551
                        acxlog(L_DEBUG | L_DATA, "rx: 802.1h/RFC1042 len: %d\n", payload_length);
 
552
                        /* it's an 802.1h frame (an RFC1042 && protocol is not in STT) */
 
553
                        /* build a DIXII + RFC894 */
 
554
                        
 
555
                        /* Test for an overlength frame */
 
556
                        if (unlikely(payload_length - sizeof(wlan_llc_t) - sizeof(wlan_snap_t) + WLAN_ETHHDR_LEN > WLAN_MAX_ETHFRM_LEN)) {
 
557
                                /* A bogus length ethfrm has been sent. */
 
558
                                /* Is someone trying an oflow attack? */
 
559
                                acxlog(L_STD, "rx: DIXII frame too large (%d > %d)\n",
 
560
                                                payload_length - sizeof(wlan_llc_t) - sizeof(wlan_snap_t),
 
561
                                                WLAN_MAX_ETHFRM_LEN - WLAN_ETHHDR_LEN);
 
562
                                FN_EXIT1((int)NULL);
 
563
                                return NULL;
 
564
                        }
 
565
        
 
566
                        /* allocate space and setup host buffer */
 
567
                        buflen = payload_length + WLAN_ETHHDR_LEN - sizeof(wlan_llc_t) - sizeof(wlan_snap_t);
 
568
                        skb = dev_alloc_skb(buflen + 2);        /* +2 is attempt to align IP header */
 
569
                        if (unlikely(!skb)) {
 
570
                                acxlog(L_STD, "rx: FAILED to allocate skb\n");
 
571
                                FN_EXIT1((int)NULL);
 
572
                                return NULL;
 
573
                        }
 
574
                        skb_reserve(skb, 2);
 
575
                        skb_put(skb, buflen);           /* make room */
 
576
        
 
577
                        /* create 802.3 header */
 
578
                        e_hdr = (wlan_ethhdr_t *) skb->data;
 
579
                        MAC_COPY(e_hdr->daddr, daddr);
 
580
                        MAC_COPY(e_hdr->saddr, saddr); 
 
581
                        e_hdr->type = e_snap->type;
 
582
        
 
583
                        /* Now copy the data from the 80211 frame.
 
584
                           Make room in front for the eth header, and cut off the 
 
585
                           llc and snap from the 802.11 payload */
 
586
                        memcpy(skb->data + WLAN_ETHHDR_LEN, e_payload,
 
587
                               payload_length - sizeof(wlan_llc_t) - sizeof(wlan_snap_t));
 
588
                }
 
589
 
 
590
        } else {
 
591
                acxlog(L_DEBUG | L_DATA, "rx: NON-ENCAP len: %d\n", payload_length);
 
592
                /* any NON-ENCAP */
 
593
                /* it's a generic 80211+LLC or IPX 'Raw 802.3' */
 
594
                /*  build an 802.3 frame */
 
595
                /* allocate space and setup hostbuf */
 
596
 
 
597
                /* Test for an overlength frame */
 
598
                if (unlikely(payload_length + WLAN_ETHHDR_LEN > WLAN_MAX_ETHFRM_LEN)) {
 
599
                        /* A bogus length ethfrm has been sent. */
 
600
                        /* Is someone trying an oflow attack? */
 
601
                        acxlog(L_STD, "rx: OTHER frame too large (%d > %d)\n",
 
602
                                payload_length,
 
603
                                WLAN_MAX_ETHFRM_LEN - WLAN_ETHHDR_LEN);
 
604
                        FN_EXIT1((int)NULL);
 
605
                        return NULL;
 
606
                }
 
607
 
 
608
                /* allocate space and setup host buffer */
 
609
                buflen = payload_length + WLAN_ETHHDR_LEN;
 
610
                skb = dev_alloc_skb(buflen + 2);        /* +2 is attempt to align IP header */
 
611
                if (unlikely(!skb)) {
 
612
                        acxlog(L_STD, "rx: FAILED to allocate skb\n");
 
613
                        FN_EXIT1((int)NULL);
 
614
                        return NULL;
 
615
                }
 
616
                skb_reserve(skb, 2);
 
617
                skb_put(skb, buflen);           /* make room */
 
618
 
 
619
                /* set up the 802.3 header */
 
620
                e_hdr = (wlan_ethhdr_t *) skb->data;
 
621
                MAC_COPY(e_hdr->daddr, daddr);
 
622
                MAC_COPY(e_hdr->saddr, saddr);
 
623
                e_hdr->type = htons(payload_length);
 
624
                
 
625
                /* now copy the data from the 80211 frame */
 
626
                memcpy(skb->data + WLAN_ETHHDR_LEN, e_llc, payload_length);
 
627
        }
 
628
 
 
629
        skb->dev = priv->netdev;
 
630
        skb->protocol = eth_type_trans(skb, priv->netdev);
 
631
        
 
632
#if DEBUG_CONVERT
 
633
        if (debug & L_DATA) {
 
634
                int i;
 
635
                printk("p802.11 frame [%d]:", MAC_CNT_RCVD(rx_desc->data));
 
636
                for (i = 0; i < MAC_CNT_RCVD(rx_desc->data); i++)
 
637
                        printk(" %02x", ((u8 *) w_hdr)[i]);
 
638
                printk("\n");
 
639
 
 
640
                printk("eth frame [%d]:", skb->len);
 
641
                for (i = 0; i < skb->len; i++)
 
642
                        printk(" %02x", ((u8 *) skb->data)[i]);
 
643
                printk("\n");
 
644
        }
 
645
#endif
 
646
 
 
647
        FN_EXIT0();
 
648
        return skb;
 
649
}