blob: 23a1f88de7cbb633c5216fa4df849f9c7dfe0ee9 [file] [log] [blame]
Jeff Garzikb4538722005-05-12 22:48:20 -04001/******************************************************************************
2
3 Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of version 2 of the GNU General Public License as
7 published by the Free Software Foundation.
8
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc., 59
16 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 The full GNU General Public License is included in this distribution in the
19 file called LICENSE.
20
21 Contact Information:
22 James P. Ketrenos <ipw2100-admin@linux.intel.com>
23 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24
25******************************************************************************/
26#include <linux/compiler.h>
27#include <linux/config.h>
28#include <linux/errno.h>
29#include <linux/if_arp.h>
30#include <linux/in6.h>
31#include <linux/in.h>
32#include <linux/ip.h>
33#include <linux/kernel.h>
34#include <linux/module.h>
35#include <linux/netdevice.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040036#include <linux/proc_fs.h>
37#include <linux/skbuff.h>
38#include <linux/slab.h>
39#include <linux/tcp.h>
40#include <linux/types.h>
41#include <linux/version.h>
42#include <linux/wireless.h>
43#include <linux/etherdevice.h>
44#include <asm/uaccess.h>
45
46#include <net/ieee80211.h>
47
Jeff Garzikb4538722005-05-12 22:48:20 -040048/*
49
Jeff Garzikb4538722005-05-12 22:48:20 -040050802.11 Data Frame
51
52 ,-------------------------------------------------------------------.
53Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
54 |------|------|---------|---------|---------|------|---------|------|
55Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs |
56 | | tion | (BSSID) | | | ence | data | |
57 `--------------------------------------------------| |------'
58Total: 28 non-data bytes `----.----'
59 |
60 .- 'Frame data' expands to <---------------------------'
61 |
62 V
63 ,---------------------------------------------------.
64Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 |
65 |------|------|---------|----------|------|---------|
66Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP |
67 | DSAP | SSAP | | | | Packet |
68 | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | |
69 `-----------------------------------------| |
70Total: 8 non-data bytes `----.----'
71 |
72 .- 'IP Packet' expands, if WEP enabled, to <--'
73 |
74 V
75 ,-----------------------.
76Bytes | 4 | 0-2296 | 4 |
77 |-----|-----------|-----|
78Desc. | IV | Encrypted | ICV |
79 | | IP Packet | |
80 `-----------------------'
81Total: 8 non-data bytes
82
Jeff Garzikb4538722005-05-12 22:48:20 -040083802.3 Ethernet Data Frame
84
85 ,-----------------------------------------.
86Bytes | 6 | 6 | 2 | Variable | 4 |
87 |-------|-------|------|-----------|------|
88Desc. | Dest. | Source| Type | IP Packet | fcs |
89 | MAC | MAC | | | |
90 `-----------------------------------------'
91Total: 18 non-data bytes
92
93In the event that fragmentation is required, the incoming payload is split into
94N parts of size ieee->fts. The first fragment contains the SNAP header and the
95remaining packets are just data.
96
97If encryption is enabled, each fragment payload size is reduced by enough space
98to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP)
99So if you have 1500 bytes of payload with ieee->fts set to 500 without
100encryption it will take 3 frames. With WEP it will take 4 frames as the
101payload of each frame is reduced to 492 bytes.
102
103* SKB visualization
104*
105* ,- skb->data
106* |
107* | ETHERNET HEADER ,-<-- PAYLOAD
108* | | 14 bytes from skb->data
109* | 2 bytes for Type --> ,T. | (sizeof ethhdr)
110* | | | |
111* |,-Dest.--. ,--Src.---. | | |
112* | 6 bytes| | 6 bytes | | | |
113* v | | | | | |
114* 0 | v 1 | v | v 2
115* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
116* ^ | ^ | ^ |
117* | | | | | |
118* | | | | `T' <---- 2 bytes for Type
119* | | | |
120* | | '---SNAP--' <-------- 6 bytes for SNAP
121* | |
122* `-IV--' <-------------------- 4 bytes for IV (WEP)
123*
124* SNAP HEADER
125*
126*/
127
128static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
129static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
130
James Ketrenos1264fc02005-09-21 11:54:53 -0500131static inline int ieee80211_copy_snap(u8 * data, u16 h_proto)
Jeff Garzikb4538722005-05-12 22:48:20 -0400132{
133 struct ieee80211_snap_hdr *snap;
134 u8 *oui;
135
136 snap = (struct ieee80211_snap_hdr *)data;
137 snap->dsap = 0xaa;
138 snap->ssap = 0xaa;
139 snap->ctrl = 0x03;
140
141 if (h_proto == 0x8137 || h_proto == 0x80f3)
142 oui = P802_1H_OUI;
143 else
144 oui = RFC1042_OUI;
145 snap->oui[0] = oui[0];
146 snap->oui[1] = oui[1];
147 snap->oui[2] = oui[2];
148
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400149 *(u16 *) (data + SNAP_SIZE) = htons(h_proto);
Jeff Garzikb4538722005-05-12 22:48:20 -0400150
151 return SNAP_SIZE + sizeof(u16);
152}
153
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400154static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
155 struct sk_buff *frag, int hdr_len)
Jeff Garzikb4538722005-05-12 22:48:20 -0400156{
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400157 struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
Jeff Garzikb4538722005-05-12 22:48:20 -0400158 int res;
159
Jeff Garzikb4538722005-05-12 22:48:20 -0400160 /* To encrypt, frame format is:
161 * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
Jeff Garzikb4538722005-05-12 22:48:20 -0400162 atomic_inc(&crypt->refcnt);
163 res = 0;
James Ketrenos1264fc02005-09-21 11:54:53 -0500164 if (crypt->ops->encrypt_mpdu)
Jeff Garzikb4538722005-05-12 22:48:20 -0400165 res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
166
167 atomic_dec(&crypt->refcnt);
168 if (res < 0) {
169 printk(KERN_INFO "%s: Encryption failed: len=%d.\n",
170 ieee->dev->name, frag->len);
171 ieee->ieee_stats.tx_discards++;
172 return -1;
173 }
174
175 return 0;
176}
177
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400178void ieee80211_txb_free(struct ieee80211_txb *txb)
179{
Jeff Garzikb4538722005-05-12 22:48:20 -0400180 int i;
181 if (unlikely(!txb))
182 return;
183 for (i = 0; i < txb->nr_frags; i++)
184 if (txb->fragments[i])
185 dev_kfree_skb_any(txb->fragments[i]);
186 kfree(txb);
187}
188
Adrian Bunke1572492005-05-06 23:32:39 +0200189static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
190 int gfp_mask)
Jeff Garzikb4538722005-05-12 22:48:20 -0400191{
192 struct ieee80211_txb *txb;
193 int i;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400194 txb = kmalloc(sizeof(struct ieee80211_txb) + (sizeof(u8 *) * nr_frags),
195 gfp_mask);
Jeff Garzikb4538722005-05-12 22:48:20 -0400196 if (!txb)
197 return NULL;
198
Adrian Bunk0a989b22005-04-11 16:52:15 -0700199 memset(txb, 0, sizeof(struct ieee80211_txb));
Jeff Garzikb4538722005-05-12 22:48:20 -0400200 txb->nr_frags = nr_frags;
201 txb->frag_size = txb_size;
202
203 for (i = 0; i < nr_frags; i++) {
204 txb->fragments[i] = dev_alloc_skb(txb_size);
205 if (unlikely(!txb->fragments[i])) {
206 i--;
207 break;
208 }
209 }
210 if (unlikely(i != nr_frags)) {
211 while (i >= 0)
212 dev_kfree_skb_any(txb->fragments[i--]);
213 kfree(txb);
214 return NULL;
215 }
216 return txb;
217}
218
James Ketrenos1264fc02005-09-21 11:54:53 -0500219/* Incoming skb is converted to a txb which consists of
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500220 * a block of 802.11 fragment packets (stored as skbs) */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400221int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
Jeff Garzikb4538722005-05-12 22:48:20 -0400222{
223 struct ieee80211_device *ieee = netdev_priv(dev);
224 struct ieee80211_txb *txb = NULL;
James Ketrenosee34af32005-09-21 11:54:36 -0500225 struct ieee80211_hdr_3addr *frag_hdr;
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500226 int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
227 rts_required;
Jeff Garzikb4538722005-05-12 22:48:20 -0400228 unsigned long flags;
229 struct net_device_stats *stats = &ieee->stats;
James Ketrenos1264fc02005-09-21 11:54:53 -0500230 int ether_type, encrypt, host_encrypt, host_encrypt_msdu;
Jeff Garzikb4538722005-05-12 22:48:20 -0400231 int bytes, fc, hdr_len;
232 struct sk_buff *skb_frag;
James Ketrenosee34af32005-09-21 11:54:36 -0500233 struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */
Jeff Garzikb4538722005-05-12 22:48:20 -0400234 .duration_id = 0,
235 .seq_ctl = 0
236 };
237 u8 dest[ETH_ALEN], src[ETH_ALEN];
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400238 struct ieee80211_crypt_data *crypt;
James Ketrenos1264fc02005-09-21 11:54:53 -0500239 int snapped = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400240
241 spin_lock_irqsave(&ieee->lock, flags);
242
243 /* If there is no driver handler to take the TXB, dont' bother
244 * creating it... */
245 if (!ieee->hard_start_xmit) {
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400246 printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
Jeff Garzikb4538722005-05-12 22:48:20 -0400247 goto success;
248 }
249
250 if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
251 printk(KERN_WARNING "%s: skb too small (%d).\n",
252 ieee->dev->name, skb->len);
253 goto success;
254 }
255
256 ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto);
257
258 crypt = ieee->crypt[ieee->tx_keyidx];
259
260 encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
James Ketrenosf1bf6632005-09-21 11:53:54 -0500261 ieee->sec.encrypt;
262 host_encrypt = ieee->host_encrypt && encrypt;
James Ketrenos1264fc02005-09-21 11:54:53 -0500263 host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt;
Jeff Garzikb4538722005-05-12 22:48:20 -0400264
265 if (!encrypt && ieee->ieee802_1x &&
266 ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
267 stats->tx_dropped++;
268 goto success;
269 }
270
Jeff Garzikb4538722005-05-12 22:48:20 -0400271 /* Save source and destination addresses */
James Ketrenos18294d82005-09-13 17:40:29 -0500272 memcpy(dest, skb->data, ETH_ALEN);
273 memcpy(src, skb->data + ETH_ALEN, ETH_ALEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400274
275 /* Advance the SKB to the start of the payload */
276 skb_pull(skb, sizeof(struct ethhdr));
277
278 /* Determine total amount of storage required for TXB packets */
279 bytes = skb->len + SNAP_SIZE + sizeof(u16);
280
James Ketrenosf1bf6632005-09-21 11:53:54 -0500281 if (host_encrypt)
Jeff Garzikb4538722005-05-12 22:48:20 -0400282 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400283 IEEE80211_FCTL_PROTECTED;
Jeff Garzikb4538722005-05-12 22:48:20 -0400284 else
285 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
286
287 if (ieee->iw_mode == IW_MODE_INFRA) {
288 fc |= IEEE80211_FCTL_TODS;
James Ketrenos1264fc02005-09-21 11:54:53 -0500289 /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
James Ketrenos18294d82005-09-13 17:40:29 -0500290 memcpy(header.addr1, ieee->bssid, ETH_ALEN);
291 memcpy(header.addr2, src, ETH_ALEN);
292 memcpy(header.addr3, dest, ETH_ALEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400293 } else if (ieee->iw_mode == IW_MODE_ADHOC) {
James Ketrenos1264fc02005-09-21 11:54:53 -0500294 /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
James Ketrenos18294d82005-09-13 17:40:29 -0500295 memcpy(header.addr1, dest, ETH_ALEN);
296 memcpy(header.addr2, src, ETH_ALEN);
297 memcpy(header.addr3, ieee->bssid, ETH_ALEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400298 }
299 header.frame_ctl = cpu_to_le16(fc);
300 hdr_len = IEEE80211_3ADDR_LEN;
301
James Ketrenos1264fc02005-09-21 11:54:53 -0500302 /* Encrypt msdu first on the whole data packet. */
303 if ((host_encrypt || host_encrypt_msdu) &&
304 crypt && crypt->ops && crypt->ops->encrypt_msdu) {
305 int res = 0;
306 int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len +
307 crypt->ops->extra_msdu_postfix_len;
308 struct sk_buff *skb_new = dev_alloc_skb(len);
309 if (unlikely(!skb_new))
310 goto failed;
311 skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len);
312 memcpy(skb_put(skb_new, hdr_len), &header, hdr_len);
313 snapped = 1;
314 ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)),
315 ether_type);
316 memcpy(skb_put(skb_new, skb->len), skb->data, skb->len);
317 res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv);
318 if (res < 0) {
319 IEEE80211_ERROR("msdu encryption failed\n");
320 dev_kfree_skb_any(skb_new);
321 goto failed;
322 }
323 dev_kfree_skb_any(skb);
324 skb = skb_new;
325 bytes += crypt->ops->extra_msdu_prefix_len +
326 crypt->ops->extra_msdu_postfix_len;
327 skb_pull(skb, hdr_len);
328 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400329
James Ketrenos1264fc02005-09-21 11:54:53 -0500330 if (host_encrypt || ieee->host_open_frag) {
331 /* Determine fragmentation size based on destination (multicast
332 * and broadcast are not fragmented) */
333 if (is_multicast_ether_addr(dest))
334 frag_size = MAX_FRAG_THRESHOLD;
335 else
336 frag_size = ieee->fts;
Jeff Garzikb4538722005-05-12 22:48:20 -0400337
James Ketrenos1264fc02005-09-21 11:54:53 -0500338 /* Determine amount of payload per fragment. Regardless of if
339 * this stack is providing the full 802.11 header, one will
340 * eventually be affixed to this fragment -- so we must account
341 * for it when determining the amount of payload space. */
342 bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN;
343 if (ieee->config &
344 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
345 bytes_per_frag -= IEEE80211_FCS_LEN;
Jeff Garzikb4538722005-05-12 22:48:20 -0400346
James Ketrenos1264fc02005-09-21 11:54:53 -0500347 /* Each fragment may need to have room for encryptiong
348 * pre/postfix */
349 if (host_encrypt)
350 bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
351 crypt->ops->extra_mpdu_postfix_len;
352
353 /* Number of fragments is the total
354 * bytes_per_frag / payload_per_fragment */
355 nr_frags = bytes / bytes_per_frag;
356 bytes_last_frag = bytes % bytes_per_frag;
357 if (bytes_last_frag)
358 nr_frags++;
359 else
360 bytes_last_frag = bytes_per_frag;
361 } else {
362 nr_frags = 1;
363 bytes_per_frag = bytes_last_frag = bytes;
364 frag_size = bytes + IEEE80211_3ADDR_LEN;
365 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400366
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500367 rts_required = (frag_size > ieee->rts
368 && ieee->config & CFG_IEEE80211_RTS);
369 if (rts_required)
370 nr_frags++;
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500371
Jeff Garzikb4538722005-05-12 22:48:20 -0400372 /* When we allocate the TXB we allocate enough space for the reserve
373 * and full fragment bytes (bytes_per_frag doesn't include prefix,
374 * postfix, header, FCS, etc.) */
375 txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC);
376 if (unlikely(!txb)) {
377 printk(KERN_WARNING "%s: Could not allocate TXB\n",
378 ieee->dev->name);
379 goto failed;
380 }
381 txb->encrypted = encrypt;
James Ketrenos1264fc02005-09-21 11:54:53 -0500382 if (host_encrypt)
383 txb->payload_size = frag_size * (nr_frags - 1) +
384 bytes_last_frag;
385 else
386 txb->payload_size = bytes;
Jeff Garzikb4538722005-05-12 22:48:20 -0400387
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500388 if (rts_required) {
389 skb_frag = txb->fragments[0];
390 frag_hdr =
391 (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len);
392
393 /*
394 * Set header frame_ctl to the RTS.
395 */
396 header.frame_ctl =
397 cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
398 memcpy(frag_hdr, &header, hdr_len);
399
400 /*
401 * Restore header frame_ctl to the original data setting.
402 */
403 header.frame_ctl = cpu_to_le16(fc);
404
405 if (ieee->config &
406 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
407 skb_put(skb_frag, 4);
408
409 txb->rts_included = 1;
410 i = 1;
411 } else
412 i = 0;
413
414 for (; i < nr_frags; i++) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400415 skb_frag = txb->fragments[i];
416
James Ketrenosf1bf6632005-09-21 11:53:54 -0500417 if (host_encrypt)
James Ketrenos1264fc02005-09-21 11:54:53 -0500418 skb_reserve(skb_frag,
419 crypt->ops->extra_mpdu_prefix_len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400420
James Ketrenosee34af32005-09-21 11:54:36 -0500421 frag_hdr =
422 (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400423 memcpy(frag_hdr, &header, hdr_len);
424
425 /* If this is not the last fragment, then add the MOREFRAGS
426 * bit to the frame control */
427 if (i != nr_frags - 1) {
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400428 frag_hdr->frame_ctl =
429 cpu_to_le16(fc | IEEE80211_FCTL_MOREFRAGS);
Jeff Garzikb4538722005-05-12 22:48:20 -0400430 bytes = bytes_per_frag;
431 } else {
432 /* The last fragment takes the remaining length */
433 bytes = bytes_last_frag;
434 }
435
James Ketrenos1264fc02005-09-21 11:54:53 -0500436 if (i == 0 && !snapped) {
437 ieee80211_copy_snap(skb_put
438 (skb_frag, SNAP_SIZE + sizeof(u16)),
439 ether_type);
Jeff Garzikb4538722005-05-12 22:48:20 -0400440 bytes -= SNAP_SIZE + sizeof(u16);
441 }
442
443 memcpy(skb_put(skb_frag, bytes), skb->data, bytes);
444
445 /* Advance the SKB... */
446 skb_pull(skb, bytes);
447
448 /* Encryption routine will move the header forward in order
449 * to insert the IV between the header and the payload */
James Ketrenosf1bf6632005-09-21 11:53:54 -0500450 if (host_encrypt)
Jeff Garzikb4538722005-05-12 22:48:20 -0400451 ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
James Ketrenosf1bf6632005-09-21 11:53:54 -0500452
Jeff Garzikb4538722005-05-12 22:48:20 -0400453 if (ieee->config &
454 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
455 skb_put(skb_frag, 4);
456 }
457
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400458 success:
Jeff Garzikb4538722005-05-12 22:48:20 -0400459 spin_unlock_irqrestore(&ieee->lock, flags);
460
461 dev_kfree_skb_any(skb);
462
463 if (txb) {
James Ketrenos1264fc02005-09-21 11:54:53 -0500464 int ret = (*ieee->hard_start_xmit) (txb, dev);
465 if (ret == 0) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400466 stats->tx_packets++;
467 stats->tx_bytes += txb->payload_size;
468 return 0;
469 }
470 ieee80211_txb_free(txb);
471 }
472
473 return 0;
474
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400475 failed:
Jeff Garzikb4538722005-05-12 22:48:20 -0400476 spin_unlock_irqrestore(&ieee->lock, flags);
477 netif_stop_queue(dev);
478 stats->tx_errors++;
479 return 1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400480}
481
James Ketrenos3f552bb2005-09-21 11:54:47 -0500482/* Incoming 802.11 strucure is converted to a TXB
483 * a block of 802.11 fragment packets (stored as skbs) */
484int ieee80211_tx_frame(struct ieee80211_device *ieee,
485 struct ieee80211_hdr *frame, int len)
486{
487 struct ieee80211_txb *txb = NULL;
488 unsigned long flags;
489 struct net_device_stats *stats = &ieee->stats;
490 struct sk_buff *skb_frag;
491
492 spin_lock_irqsave(&ieee->lock, flags);
493
494 /* If there is no driver handler to take the TXB, dont' bother
495 * creating it... */
496 if (!ieee->hard_start_xmit) {
497 printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
498 goto success;
499 }
500
501 if (unlikely(len < 24)) {
502 printk(KERN_WARNING "%s: skb too small (%d).\n",
503 ieee->dev->name, len);
504 goto success;
505 }
506
507 /* When we allocate the TXB we allocate enough space for the reserve
508 * and full fragment bytes (bytes_per_frag doesn't include prefix,
509 * postfix, header, FCS, etc.) */
510 txb = ieee80211_alloc_txb(1, len, GFP_ATOMIC);
511 if (unlikely(!txb)) {
512 printk(KERN_WARNING "%s: Could not allocate TXB\n",
513 ieee->dev->name);
514 goto failed;
515 }
516 txb->encrypted = 0;
517 txb->payload_size = len;
518
519 skb_frag = txb->fragments[0];
520
521 memcpy(skb_put(skb_frag, len), frame, len);
522
523 if (ieee->config &
524 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
525 skb_put(skb_frag, 4);
526
527 success:
528 spin_unlock_irqrestore(&ieee->lock, flags);
529
530 if (txb) {
531 if ((*ieee->hard_start_xmit) (txb, ieee->dev) == 0) {
532 stats->tx_packets++;
533 stats->tx_bytes += txb->payload_size;
534 return 0;
535 }
536 ieee80211_txb_free(txb);
537 }
538 return 0;
539
540 failed:
541 spin_unlock_irqrestore(&ieee->lock, flags);
542 stats->tx_errors++;
543 return 1;
544}
545
546EXPORT_SYMBOL(ieee80211_tx_frame);
Jeff Garzikb4538722005-05-12 22:48:20 -0400547EXPORT_SYMBOL(ieee80211_txb_free);