OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [net/] [ieee80211/] [softmac/] [ieee80211softmac_io.c] - Blame information for rev 67

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Some parts based on code from net80211
3
 * Copyright (c) 2001 Atsushi Onoe
4
 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 * 3. The name of the author may not be used to endorse or promote products
16
 *    derived from this software without specific prior written permission.
17
 *
18
 * Alternatively, this software may be distributed under the terms of the
19
 * GNU General Public License ("GPL") version 2 as published by the Free
20
 * Software Foundation.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
 *
33
 */
34
 
35
#include "ieee80211softmac_priv.h"
36
 
37
/* Helper functions for inserting data into the frames */
38
 
39
/*
40
 * Adds an ESSID element to the frame
41
 *
42
 */
43
static u8 *
44
ieee80211softmac_add_essid(u8 *dst, struct ieee80211softmac_essid *essid)
45
{
46
        if (essid) {
47
                *dst++ = MFIE_TYPE_SSID;
48
                *dst++ = essid->len;
49
                memcpy(dst, essid->data, essid->len);
50
                return dst+essid->len;
51
        } else {
52
                *dst++ = MFIE_TYPE_SSID;
53
                *dst++ = 0;
54
                return dst;
55
        }
56
}
57
 
58
/* Adds Supported Rates and if required Extended Rates Information Element
59
 * to the frame, ASSUMES WE HAVE A SORTED LIST OF RATES */
60
static u8 *
61
ieee80211softmac_frame_add_rates(u8 *dst, const struct ieee80211softmac_ratesinfo *r)
62
{
63
        int cck_len, ofdm_len;
64
        *dst++ = MFIE_TYPE_RATES;
65
 
66
        for(cck_len=0; ieee80211_is_cck_rate(r->rates[cck_len]) && (cck_len < r->count);cck_len++);
67
 
68
        if(cck_len > IEEE80211SOFTMAC_MAX_RATES_LEN)
69
                cck_len = IEEE80211SOFTMAC_MAX_RATES_LEN;
70
        *dst++ = cck_len;
71
        memcpy(dst, r->rates, cck_len);
72
        dst += cck_len;
73
 
74
        if(cck_len < r->count){
75
                for (ofdm_len=0; ieee80211_is_ofdm_rate(r->rates[ofdm_len + cck_len]) && (ofdm_len + cck_len < r->count); ofdm_len++);
76
                if (ofdm_len > 0) {
77
                        if (ofdm_len > IEEE80211SOFTMAC_MAX_EX_RATES_LEN)
78
                                ofdm_len = IEEE80211SOFTMAC_MAX_EX_RATES_LEN;
79
                        *dst++ = MFIE_TYPE_RATES_EX;
80
                        *dst++ = ofdm_len;
81
                        memcpy(dst, r->rates + cck_len, ofdm_len);
82
                        dst += ofdm_len;
83
                }
84
        }
85
        return dst;
86
}
87
 
88
/* Allocate a management frame */
89
static u8 *
90
ieee80211softmac_alloc_mgt(u32 size)
91
{
92
        u8 * data;
93
 
94
        /* Add the header and FCS to the size */
95
        size = size + IEEE80211_3ADDR_LEN;
96
        if(size > IEEE80211_DATA_LEN)
97
                return NULL;
98
        /* Allocate the frame */
99
        data = kzalloc(size, GFP_ATOMIC);
100
        return data;
101
}
102
 
103
/*
104
 * Add a 2 Address Header
105
 */
106
static void
107
ieee80211softmac_hdr_2addr(struct ieee80211softmac_device *mac,
108
        struct ieee80211_hdr_2addr *header, u32 type, u8 *dest)
109
{
110
        /* Fill in the frame control flags */
111
        header->frame_ctl = cpu_to_le16(type);
112
        /* Control packets always have WEP turned off */
113
        if(type > IEEE80211_STYPE_CFENDACK && type < IEEE80211_STYPE_PSPOLL)
114
                header->frame_ctl |= mac->ieee->sec.level ? cpu_to_le16(IEEE80211_FCTL_PROTECTED) : 0;
115
 
116
        /* Fill in the duration */
117
        header->duration_id = 0;
118
        /* FIXME: How do I find this?
119
         * calculate. But most drivers just fill in 0 (except if it's a station id of course) */
120
 
121
        /* Fill in the Destination Address */
122
        if(dest == NULL)
123
                memset(header->addr1, 0xFF, ETH_ALEN);
124
        else
125
                memcpy(header->addr1, dest, ETH_ALEN);
126
        /* Fill in the Source Address */
127
        memcpy(header->addr2, mac->ieee->dev->dev_addr, ETH_ALEN);
128
 
129
}
130
 
131
 
132
/* Add a 3 Address Header */
133
static void
134
ieee80211softmac_hdr_3addr(struct ieee80211softmac_device *mac,
135
        struct ieee80211_hdr_3addr *header, u32 type, u8 *dest, u8 *bssid)
136
{
137
        /* This is common with 2addr, so use that instead */
138
        ieee80211softmac_hdr_2addr(mac, (struct ieee80211_hdr_2addr *)header, type, dest);
139
 
140
        /* Fill in the BSS ID */
141
        if(bssid == NULL)
142
                memset(header->addr3, 0xFF, ETH_ALEN);
143
        else
144
                memcpy(header->addr3, bssid, ETH_ALEN);
145
 
146
        /* Fill in the sequence # */
147
        /* FIXME: I need to add this to the softmac struct
148
         * shouldn't the sequence number be in ieee80211? */
149
}
150
 
151
static u16
152
ieee80211softmac_capabilities(struct ieee80211softmac_device *mac,
153
        struct ieee80211softmac_network *net)
154
{
155
        u16 capability = 0;
156
 
157
        /* ESS and IBSS bits are set according to the current mode */
158
        switch (mac->ieee->iw_mode) {
159
        case IW_MODE_INFRA:
160
                capability = cpu_to_le16(WLAN_CAPABILITY_ESS);
161
                break;
162
        case IW_MODE_ADHOC:
163
                capability = cpu_to_le16(WLAN_CAPABILITY_IBSS);
164
                break;
165
        case IW_MODE_AUTO:
166
                capability = net->capabilities &
167
                        (WLAN_CAPABILITY_ESS|WLAN_CAPABILITY_IBSS);
168
                break;
169
        default:
170
                /* bleh. we don't ever go to these modes */
171
                printk(KERN_ERR PFX "invalid iw_mode!\n");
172
                break;
173
        }
174
 
175
        /* CF Pollable / CF Poll Request */
176
        /* Needs to be implemented, for now, the 0's == not supported */
177
 
178
        /* Privacy Bit */
179
        capability |= mac->ieee->sec.level ?
180
                cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
181
 
182
        /* Short Preamble */
183
        /* Always supported: we probably won't ever be powering devices which
184
         * dont support this... */
185
        capability |= WLAN_CAPABILITY_SHORT_PREAMBLE;
186
 
187
        /* PBCC */
188
        /* Not widely used */
189
 
190
        /* Channel Agility */
191
        /* Not widely used */
192
 
193
        /* Short Slot */
194
        /* Will be implemented later */
195
 
196
        /* DSSS-OFDM */
197
        /* Not widely used */
198
 
199
        return capability;
200
}
201
 
202
/*****************************************************************************
203
 * Create Management packets
204
 *****************************************************************************/
205
 
206
/* Creates an association request packet */
207
static u32
208
ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
209
        struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
210
{
211
        u8 *data;
212
        (*pkt) = (struct ieee80211_assoc_request *)ieee80211softmac_alloc_mgt(
213
                2 +             /* Capability Info */
214
                2 +             /* Listen Interval */
215
                /* SSID IE */
216
                1 + 1 + IW_ESSID_MAX_SIZE +
217
                /* Rates IE */
218
                1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
219
                /* Extended Rates IE */
220
                1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN +
221
                /* WPA IE if present */
222
                mac->wpa.IElen
223
                /* Other IE's?  Optional?
224
                 * Yeah, probably need an extra IE parameter -- lots of vendors like to
225
                 * fill in their own IEs */
226
        );
227
        if (unlikely((*pkt) == NULL))
228
                return 0;
229
        ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
230
 
231
        /* Fill in the capabilities */
232
        (*pkt)->capability = ieee80211softmac_capabilities(mac, net);
233
 
234
        /* Fill in Listen Interval (?) */
235
        (*pkt)->listen_interval = cpu_to_le16(10);
236
 
237
        data = (u8 *)(*pkt)->info_element;
238
        /* Add SSID */
239
        data = ieee80211softmac_add_essid(data, &net->essid);
240
        /* Add Rates */
241
        data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
242
        /* Add WPA IE */
243
        if (mac->wpa.IElen && mac->wpa.IE) {
244
                memcpy(data, mac->wpa.IE, mac->wpa.IElen);
245
                data += mac->wpa.IElen;
246
        }
247
        /* Return the number of used bytes */
248
        return (data - (u8*)(*pkt));
249
}
250
 
251
/* Create a reassociation request packet */
252
static u32
253
ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt,
254
        struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
255
{
256
        u8 *data;
257
        (*pkt) = (struct ieee80211_reassoc_request *)ieee80211softmac_alloc_mgt(
258
                2 +             /* Capability Info */
259
                2 +             /* Listen Interval */
260
                ETH_ALEN +      /* AP MAC */
261
                /* SSID IE */
262
                1 + 1 + IW_ESSID_MAX_SIZE +
263
                /* Rates IE */
264
                1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
265
                /* Extended Rates IE */
266
                1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
267
                /* Other IE's? */
268
        );
269
        if (unlikely((*pkt) == NULL))
270
                return 0;
271
        ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid);
272
 
273
        /* Fill in the capabilities */
274
        (*pkt)->capability = ieee80211softmac_capabilities(mac, net);
275
 
276
        /* Fill in Listen Interval (?) */
277
        (*pkt)->listen_interval = cpu_to_le16(10);
278
        /* Fill in the current AP MAC */
279
        memcpy((*pkt)->current_ap, mac->ieee->bssid, ETH_ALEN);
280
 
281
        data = (u8 *)(*pkt)->info_element;
282
        /* Add SSID */
283
        data = ieee80211softmac_add_essid(data, &net->essid);
284
        /* Add Rates */
285
        data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
286
        /* Return packet size */
287
        return (data - (u8 *)(*pkt));
288
}
289
 
290
/* Create an authentication packet */
291
static u32
292
ieee80211softmac_auth(struct ieee80211_auth **pkt,
293
        struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
294
        u16 transaction, u16 status, int *encrypt_mpdu)
295
{
296
        u8 *data;
297
        int auth_mode = mac->ieee->sec.auth_mode;
298
        int is_shared_response = (auth_mode == WLAN_AUTH_SHARED_KEY
299
                && transaction == IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE);
300
 
301
        /* Allocate Packet */
302
        (*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt(
303
                2 +             /* Auth Algorithm */
304
                2 +             /* Auth Transaction Seq */
305
                2 +             /* Status Code */
306
                 /* Challenge Text IE */
307
                (is_shared_response ? 1 + 1 + net->challenge_len : 0)
308
        );
309
        if (unlikely((*pkt) == NULL))
310
                return 0;
311
        ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid);
312
 
313
        /* Algorithm */
314
        (*pkt)->algorithm = cpu_to_le16(auth_mode);
315
        /* Transaction */
316
        (*pkt)->transaction = cpu_to_le16(transaction);
317
        /* Status */
318
        (*pkt)->status = cpu_to_le16(status);
319
 
320
        data = (u8 *)(*pkt)->info_element;
321
        /* Challenge Text */
322
        if (is_shared_response) {
323
                *data = MFIE_TYPE_CHALLENGE;
324
                data++;
325
 
326
                /* Copy the challenge in */
327
                *data = net->challenge_len;
328
                data++;
329
                memcpy(data, net->challenge, net->challenge_len);
330
                data += net->challenge_len;
331
 
332
                /* Make sure this frame gets encrypted with the shared key */
333
                *encrypt_mpdu = 1;
334
        } else
335
                *encrypt_mpdu = 0;
336
 
337
        /* Return the packet size */
338
        return (data - (u8 *)(*pkt));
339
}
340
 
341
/* Create a disassocation or deauthentication packet */
342
static u32
343
ieee80211softmac_disassoc_deauth(struct ieee80211_disassoc **pkt,
344
        struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
345
        u16 type, u16 reason)
346
{
347
        /* Allocate Packet */
348
        (*pkt) = (struct ieee80211_disassoc *)ieee80211softmac_alloc_mgt(2);
349
        if (unlikely((*pkt) == NULL))
350
                return 0;
351
        ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), type, net->bssid, net->bssid);
352
        /* Reason */
353
        (*pkt)->reason = cpu_to_le16(reason);
354
        /* Return the packet size */
355
        return (2 + IEEE80211_3ADDR_LEN);
356
}
357
 
358
/* Create a probe request packet */
359
static u32
360
ieee80211softmac_probe_req(struct ieee80211_probe_request **pkt,
361
        struct ieee80211softmac_device *mac, struct ieee80211softmac_essid *essid)
362
{
363
        u8 *data;
364
        /* Allocate Packet */
365
        (*pkt) = (struct ieee80211_probe_request *)ieee80211softmac_alloc_mgt(
366
                /* SSID of requested network */
367
                1 + 1 + IW_ESSID_MAX_SIZE +
368
                /* Rates IE */
369
                1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
370
                /* Extended Rates IE */
371
                1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
372
        );
373
        if (unlikely((*pkt) == NULL))
374
                return 0;
375
        ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_REQ, NULL, NULL);
376
 
377
        data = (u8 *)(*pkt)->info_element;
378
        /* Add ESSID (can be NULL) */
379
        data = ieee80211softmac_add_essid(data, essid);
380
        /* Add Rates */
381
        data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
382
        /* Return packet size */
383
        return (data - (u8 *)(*pkt));
384
}
385
 
386
/* Create a probe response packet */
387
/* FIXME: Not complete */
388
static u32
389
ieee80211softmac_probe_resp(struct ieee80211_probe_response **pkt,
390
        struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
391
{
392
        u8 *data;
393
        /* Allocate Packet */
394
        (*pkt) = (struct ieee80211_probe_response *)ieee80211softmac_alloc_mgt(
395
                8 +             /* Timestamp */
396
                2 +             /* Beacon Interval */
397
                2 +             /* Capability Info */
398
                                /* SSID IE */
399
                1 + 1 + IW_ESSID_MAX_SIZE +
400
                7 +             /* FH Parameter Set */
401
                2 +             /* DS Parameter Set */
402
                8 +             /* CF Parameter Set */
403
                4               /* IBSS Parameter Set */
404
        );
405
        if (unlikely((*pkt) == NULL))
406
                return 0;
407
        ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_RESP, net->bssid, net->bssid);
408
        data = (u8 *)(*pkt)->info_element;
409
 
410
        /* Return the packet size */
411
        return (data - (u8 *)(*pkt));
412
}
413
 
414
 
415
/* Sends a manangement packet
416
 * FIXME: document the use of the arg parameter
417
 * for _AUTH: (transaction #) | (status << 16)
418
 */
419
int
420
ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
421
        void *ptrarg, u32 type, u32 arg)
422
{
423
        void *pkt = NULL;
424
        u32 pkt_size = 0;
425
        int encrypt_mpdu = 0;
426
 
427
        switch(type) {
428
        case IEEE80211_STYPE_ASSOC_REQ:
429
                pkt_size = ieee80211softmac_assoc_req((struct ieee80211_assoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
430
                break;
431
        case IEEE80211_STYPE_REASSOC_REQ:
432
                pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
433
                break;
434
        case IEEE80211_STYPE_AUTH:
435
                pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16), &encrypt_mpdu);
436
                break;
437
        case IEEE80211_STYPE_DISASSOC:
438
        case IEEE80211_STYPE_DEAUTH:
439
                pkt_size = ieee80211softmac_disassoc_deauth((struct ieee80211_disassoc **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, type, (u16)(arg & 0xFFFF));
440
                break;
441
        case IEEE80211_STYPE_PROBE_REQ:
442
                pkt_size = ieee80211softmac_probe_req((struct ieee80211_probe_request **)(&pkt), mac, (struct ieee80211softmac_essid *)ptrarg);
443
                break;
444
        case IEEE80211_STYPE_PROBE_RESP:
445
                pkt_size = ieee80211softmac_probe_resp((struct ieee80211_probe_response **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
446
                break;
447
        default:
448
                printkl(KERN_DEBUG PFX "Unsupported Management Frame type: %i\n", type);
449
                return -EINVAL;
450
        };
451
 
452
        if(pkt_size == 0 || pkt == NULL) {
453
                printkl(KERN_DEBUG PFX "Error, packet is nonexistant or 0 length\n");
454
                return -ENOMEM;
455
        }
456
 
457
        /* Send the packet to the ieee80211 layer for tx */
458
        /* we defined softmac->mgmt_xmit for this. Should we keep it
459
         * as it is (that means we'd need to wrap this into a txb),
460
         * modify the prototype (so it matches this function),
461
         * or get rid of it alltogether?
462
         * Does this work for you now?
463
         */
464
        ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt,
465
                IEEE80211_3ADDR_LEN, pkt_size, encrypt_mpdu);
466
 
467
        kfree(pkt);
468
        return 0;
469
}
470
 
471
/* Beacon handling */
472
int ieee80211softmac_handle_beacon(struct net_device *dev,
473
        struct ieee80211_beacon *beacon,
474
        struct ieee80211_network *network)
475
{
476
        struct ieee80211softmac_device *mac = ieee80211_priv(dev);
477
 
478
        /* This might race, but we don't really care and it's not worth
479
         * adding heavyweight locking in this fastpath.
480
         */
481
        if (mac->associnfo.associated) {
482
                if (memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0)
483
                        ieee80211softmac_process_erp(mac, network->erp_value);
484
        }
485
 
486
        return 0;
487
}
488
 

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.