blob: f4f2a33973a7d491a9368c5cccafdc597060a7d6 [file] [log] [blame]
Jeff Garzikb4538722005-05-12 22:48:20 -04001/******************************************************************************
2
James Ketrenosebeaddc2005-09-21 11:58:43 -05003 Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
Jeff Garzikb4538722005-05-12 22:48:20 -04004
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
Hong Liuf0f15ab2005-10-20 11:06:36 -0500160 if (crypt == NULL)
161 return -1;
162
Jeff Garzikb4538722005-05-12 22:48:20 -0400163 /* To encrypt, frame format is:
164 * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
Jeff Garzikb4538722005-05-12 22:48:20 -0400165 atomic_inc(&crypt->refcnt);
166 res = 0;
Hong Liuf0f15ab2005-10-20 11:06:36 -0500167 if (crypt->ops && crypt->ops->encrypt_mpdu)
Jeff Garzikb4538722005-05-12 22:48:20 -0400168 res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
169
170 atomic_dec(&crypt->refcnt);
171 if (res < 0) {
172 printk(KERN_INFO "%s: Encryption failed: len=%d.\n",
173 ieee->dev->name, frag->len);
174 ieee->ieee_stats.tx_discards++;
175 return -1;
176 }
177
178 return 0;
179}
180
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400181void ieee80211_txb_free(struct ieee80211_txb *txb)
182{
Jeff Garzikb4538722005-05-12 22:48:20 -0400183 int i;
184 if (unlikely(!txb))
185 return;
186 for (i = 0; i < txb->nr_frags; i++)
187 if (txb->fragments[i])
188 dev_kfree_skb_any(txb->fragments[i]);
189 kfree(txb);
190}
191
Adrian Bunke1572492005-05-06 23:32:39 +0200192static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size,
Al Virodd0fc662005-10-07 07:46:04 +0100193 gfp_t gfp_mask)
Jeff Garzikb4538722005-05-12 22:48:20 -0400194{
195 struct ieee80211_txb *txb;
196 int i;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400197 txb = kmalloc(sizeof(struct ieee80211_txb) + (sizeof(u8 *) * nr_frags),
198 gfp_mask);
Jeff Garzikb4538722005-05-12 22:48:20 -0400199 if (!txb)
200 return NULL;
201
Adrian Bunk0a989b22005-04-11 16:52:15 -0700202 memset(txb, 0, sizeof(struct ieee80211_txb));
Jeff Garzikb4538722005-05-12 22:48:20 -0400203 txb->nr_frags = nr_frags;
204 txb->frag_size = txb_size;
205
206 for (i = 0; i < nr_frags; i++) {
207 txb->fragments[i] = dev_alloc_skb(txb_size);
208 if (unlikely(!txb->fragments[i])) {
209 i--;
210 break;
211 }
212 }
213 if (unlikely(i != nr_frags)) {
214 while (i >= 0)
215 dev_kfree_skb_any(txb->fragments[i--]);
216 kfree(txb);
217 return NULL;
218 }
219 return txb;
220}
221
James Ketrenos1264fc02005-09-21 11:54:53 -0500222/* Incoming skb is converted to a txb which consists of
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500223 * a block of 802.11 fragment packets (stored as skbs) */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400224int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
Jeff Garzikb4538722005-05-12 22:48:20 -0400225{
226 struct ieee80211_device *ieee = netdev_priv(dev);
227 struct ieee80211_txb *txb = NULL;
James Ketrenosee34af32005-09-21 11:54:36 -0500228 struct ieee80211_hdr_3addr *frag_hdr;
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500229 int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
230 rts_required;
Jeff Garzikb4538722005-05-12 22:48:20 -0400231 unsigned long flags;
232 struct net_device_stats *stats = &ieee->stats;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500233 int ether_type, encrypt, host_encrypt, host_encrypt_msdu, host_build_iv;
Jeff Garzikb4538722005-05-12 22:48:20 -0400234 int bytes, fc, hdr_len;
235 struct sk_buff *skb_frag;
James Ketrenosee34af32005-09-21 11:54:36 -0500236 struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */
Jeff Garzikb4538722005-05-12 22:48:20 -0400237 .duration_id = 0,
238 .seq_ctl = 0
239 };
240 u8 dest[ETH_ALEN], src[ETH_ALEN];
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400241 struct ieee80211_crypt_data *crypt;
James Ketrenos2c0aa2a2005-09-21 11:56:27 -0500242 int priority = skb->priority;
James Ketrenos1264fc02005-09-21 11:54:53 -0500243 int snapped = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400244
James Ketrenos2c0aa2a2005-09-21 11:56:27 -0500245 if (ieee->is_queue_full && (*ieee->is_queue_full) (dev, priority))
246 return NETDEV_TX_BUSY;
247
Jeff Garzikb4538722005-05-12 22:48:20 -0400248 spin_lock_irqsave(&ieee->lock, flags);
249
250 /* If there is no driver handler to take the TXB, dont' bother
251 * creating it... */
252 if (!ieee->hard_start_xmit) {
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400253 printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
Jeff Garzikb4538722005-05-12 22:48:20 -0400254 goto success;
255 }
256
257 if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
258 printk(KERN_WARNING "%s: skb too small (%d).\n",
259 ieee->dev->name, skb->len);
260 goto success;
261 }
262
263 ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto);
264
265 crypt = ieee->crypt[ieee->tx_keyidx];
266
267 encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
James Ketrenosf1bf6632005-09-21 11:53:54 -0500268 ieee->sec.encrypt;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500269
Hong Liuf0f15ab2005-10-20 11:06:36 -0500270 host_encrypt = ieee->host_encrypt && encrypt && crypt;
271 host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt && crypt;
272 host_build_iv = ieee->host_build_iv && encrypt && crypt;
Jeff Garzikb4538722005-05-12 22:48:20 -0400273
274 if (!encrypt && ieee->ieee802_1x &&
275 ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
276 stats->tx_dropped++;
277 goto success;
278 }
279
Jeff Garzikb4538722005-05-12 22:48:20 -0400280 /* Save source and destination addresses */
James Ketrenos18294d82005-09-13 17:40:29 -0500281 memcpy(dest, skb->data, ETH_ALEN);
282 memcpy(src, skb->data + ETH_ALEN, ETH_ALEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400283
284 /* Advance the SKB to the start of the payload */
285 skb_pull(skb, sizeof(struct ethhdr));
286
287 /* Determine total amount of storage required for TXB packets */
288 bytes = skb->len + SNAP_SIZE + sizeof(u16);
289
James Ketrenosf1bf6632005-09-21 11:53:54 -0500290 if (host_encrypt)
Jeff Garzikb4538722005-05-12 22:48:20 -0400291 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400292 IEEE80211_FCTL_PROTECTED;
Jeff Garzikb4538722005-05-12 22:48:20 -0400293 else
294 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
295
296 if (ieee->iw_mode == IW_MODE_INFRA) {
297 fc |= IEEE80211_FCTL_TODS;
James Ketrenos1264fc02005-09-21 11:54:53 -0500298 /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
James Ketrenos18294d82005-09-13 17:40:29 -0500299 memcpy(header.addr1, ieee->bssid, ETH_ALEN);
300 memcpy(header.addr2, src, ETH_ALEN);
301 memcpy(header.addr3, dest, ETH_ALEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400302 } else if (ieee->iw_mode == IW_MODE_ADHOC) {
James Ketrenos1264fc02005-09-21 11:54:53 -0500303 /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
James Ketrenos18294d82005-09-13 17:40:29 -0500304 memcpy(header.addr1, dest, ETH_ALEN);
305 memcpy(header.addr2, src, ETH_ALEN);
306 memcpy(header.addr3, ieee->bssid, ETH_ALEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400307 }
308 header.frame_ctl = cpu_to_le16(fc);
309 hdr_len = IEEE80211_3ADDR_LEN;
310
James Ketrenos1264fc02005-09-21 11:54:53 -0500311 /* Encrypt msdu first on the whole data packet. */
312 if ((host_encrypt || host_encrypt_msdu) &&
313 crypt && crypt->ops && crypt->ops->encrypt_msdu) {
314 int res = 0;
315 int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len +
316 crypt->ops->extra_msdu_postfix_len;
317 struct sk_buff *skb_new = dev_alloc_skb(len);
James Ketrenos31b59ea2005-09-21 11:58:49 -0500318
James Ketrenos1264fc02005-09-21 11:54:53 -0500319 if (unlikely(!skb_new))
320 goto failed;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500321
James Ketrenos1264fc02005-09-21 11:54:53 -0500322 skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len);
323 memcpy(skb_put(skb_new, hdr_len), &header, hdr_len);
324 snapped = 1;
325 ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)),
326 ether_type);
327 memcpy(skb_put(skb_new, skb->len), skb->data, skb->len);
328 res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv);
329 if (res < 0) {
330 IEEE80211_ERROR("msdu encryption failed\n");
331 dev_kfree_skb_any(skb_new);
332 goto failed;
333 }
334 dev_kfree_skb_any(skb);
335 skb = skb_new;
336 bytes += crypt->ops->extra_msdu_prefix_len +
337 crypt->ops->extra_msdu_postfix_len;
338 skb_pull(skb, hdr_len);
339 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400340
James Ketrenos1264fc02005-09-21 11:54:53 -0500341 if (host_encrypt || ieee->host_open_frag) {
342 /* Determine fragmentation size based on destination (multicast
343 * and broadcast are not fragmented) */
Hong Liu5b74eda2005-10-19 16:31:34 -0500344 if (is_multicast_ether_addr(dest) ||
345 is_broadcast_ether_addr(dest))
James Ketrenos1264fc02005-09-21 11:54:53 -0500346 frag_size = MAX_FRAG_THRESHOLD;
347 else
348 frag_size = ieee->fts;
Jeff Garzikb4538722005-05-12 22:48:20 -0400349
James Ketrenos1264fc02005-09-21 11:54:53 -0500350 /* Determine amount of payload per fragment. Regardless of if
351 * this stack is providing the full 802.11 header, one will
352 * eventually be affixed to this fragment -- so we must account
353 * for it when determining the amount of payload space. */
354 bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN;
355 if (ieee->config &
356 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
357 bytes_per_frag -= IEEE80211_FCS_LEN;
Jeff Garzikb4538722005-05-12 22:48:20 -0400358
James Ketrenos1264fc02005-09-21 11:54:53 -0500359 /* Each fragment may need to have room for encryptiong
360 * pre/postfix */
361 if (host_encrypt)
362 bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
363 crypt->ops->extra_mpdu_postfix_len;
364
365 /* Number of fragments is the total
366 * bytes_per_frag / payload_per_fragment */
367 nr_frags = bytes / bytes_per_frag;
368 bytes_last_frag = bytes % bytes_per_frag;
369 if (bytes_last_frag)
370 nr_frags++;
371 else
372 bytes_last_frag = bytes_per_frag;
373 } else {
374 nr_frags = 1;
375 bytes_per_frag = bytes_last_frag = bytes;
376 frag_size = bytes + IEEE80211_3ADDR_LEN;
377 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400378
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500379 rts_required = (frag_size > ieee->rts
380 && ieee->config & CFG_IEEE80211_RTS);
381 if (rts_required)
382 nr_frags++;
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500383
Jeff Garzikb4538722005-05-12 22:48:20 -0400384 /* When we allocate the TXB we allocate enough space for the reserve
385 * and full fragment bytes (bytes_per_frag doesn't include prefix,
386 * postfix, header, FCS, etc.) */
387 txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC);
388 if (unlikely(!txb)) {
389 printk(KERN_WARNING "%s: Could not allocate TXB\n",
390 ieee->dev->name);
391 goto failed;
392 }
393 txb->encrypted = encrypt;
James Ketrenos1264fc02005-09-21 11:54:53 -0500394 if (host_encrypt)
395 txb->payload_size = frag_size * (nr_frags - 1) +
396 bytes_last_frag;
397 else
398 txb->payload_size = bytes;
Jeff Garzikb4538722005-05-12 22:48:20 -0400399
James Ketrenos3cdd00c2005-09-21 11:54:43 -0500400 if (rts_required) {
401 skb_frag = txb->fragments[0];
402 frag_hdr =
403 (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len);
404
405 /*
406 * Set header frame_ctl to the RTS.
407 */
408 header.frame_ctl =
409 cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
410 memcpy(frag_hdr, &header, hdr_len);
411
412 /*
413 * Restore header frame_ctl to the original data setting.
414 */
415 header.frame_ctl = cpu_to_le16(fc);
416
417 if (ieee->config &
418 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
419 skb_put(skb_frag, 4);
420
421 txb->rts_included = 1;
422 i = 1;
423 } else
424 i = 0;
425
426 for (; i < nr_frags; i++) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400427 skb_frag = txb->fragments[i];
428
James Ketrenos31b59ea2005-09-21 11:58:49 -0500429 if (host_encrypt || host_build_iv)
James Ketrenos1264fc02005-09-21 11:54:53 -0500430 skb_reserve(skb_frag,
431 crypt->ops->extra_mpdu_prefix_len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400432
James Ketrenosee34af32005-09-21 11:54:36 -0500433 frag_hdr =
434 (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400435 memcpy(frag_hdr, &header, hdr_len);
436
437 /* If this is not the last fragment, then add the MOREFRAGS
438 * bit to the frame control */
439 if (i != nr_frags - 1) {
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400440 frag_hdr->frame_ctl =
441 cpu_to_le16(fc | IEEE80211_FCTL_MOREFRAGS);
Jeff Garzikb4538722005-05-12 22:48:20 -0400442 bytes = bytes_per_frag;
443 } else {
444 /* The last fragment takes the remaining length */
445 bytes = bytes_last_frag;
446 }
447
James Ketrenos1264fc02005-09-21 11:54:53 -0500448 if (i == 0 && !snapped) {
449 ieee80211_copy_snap(skb_put
450 (skb_frag, SNAP_SIZE + sizeof(u16)),
451 ether_type);
Jeff Garzikb4538722005-05-12 22:48:20 -0400452 bytes -= SNAP_SIZE + sizeof(u16);
453 }
454
455 memcpy(skb_put(skb_frag, bytes), skb->data, bytes);
456
457 /* Advance the SKB... */
458 skb_pull(skb, bytes);
459
460 /* Encryption routine will move the header forward in order
461 * to insert the IV between the header and the payload */
James Ketrenosf1bf6632005-09-21 11:53:54 -0500462 if (host_encrypt)
Jeff Garzikb4538722005-05-12 22:48:20 -0400463 ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
James Ketrenos31b59ea2005-09-21 11:58:49 -0500464 else if (host_build_iv) {
465 struct ieee80211_crypt_data *crypt;
466
467 crypt = ieee->crypt[ieee->tx_keyidx];
468 atomic_inc(&crypt->refcnt);
469 if (crypt->ops->build_iv)
470 crypt->ops->build_iv(skb_frag, hdr_len,
471 crypt->priv);
472 atomic_dec(&crypt->refcnt);
473 }
James Ketrenosf1bf6632005-09-21 11:53:54 -0500474
Jeff Garzikb4538722005-05-12 22:48:20 -0400475 if (ieee->config &
476 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
477 skb_put(skb_frag, 4);
478 }
479
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400480 success:
Jeff Garzikb4538722005-05-12 22:48:20 -0400481 spin_unlock_irqrestore(&ieee->lock, flags);
482
483 dev_kfree_skb_any(skb);
484
485 if (txb) {
James Ketrenos9e8571a2005-09-21 11:56:33 -0500486 int ret = (*ieee->hard_start_xmit) (txb, dev, priority);
James Ketrenos1264fc02005-09-21 11:54:53 -0500487 if (ret == 0) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400488 stats->tx_packets++;
489 stats->tx_bytes += txb->payload_size;
490 return 0;
491 }
James Ketrenos2c0aa2a2005-09-21 11:56:27 -0500492
493 if (ret == NETDEV_TX_BUSY) {
494 printk(KERN_ERR "%s: NETDEV_TX_BUSY returned; "
495 "driver should report queue full via "
496 "ieee_device->is_queue_full.\n",
497 ieee->dev->name);
498 }
499
Jeff Garzikb4538722005-05-12 22:48:20 -0400500 ieee80211_txb_free(txb);
501 }
502
503 return 0;
504
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400505 failed:
Jeff Garzikb4538722005-05-12 22:48:20 -0400506 spin_unlock_irqrestore(&ieee->lock, flags);
507 netif_stop_queue(dev);
508 stats->tx_errors++;
509 return 1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400510}
511
James Ketrenos3f552bb2005-09-21 11:54:47 -0500512/* Incoming 802.11 strucure is converted to a TXB
513 * a block of 802.11 fragment packets (stored as skbs) */
514int ieee80211_tx_frame(struct ieee80211_device *ieee,
515 struct ieee80211_hdr *frame, int len)
516{
517 struct ieee80211_txb *txb = NULL;
518 unsigned long flags;
519 struct net_device_stats *stats = &ieee->stats;
520 struct sk_buff *skb_frag;
James Ketrenos9e8571a2005-09-21 11:56:33 -0500521 int priority = -1;
James Ketrenos3f552bb2005-09-21 11:54:47 -0500522
523 spin_lock_irqsave(&ieee->lock, flags);
524
525 /* If there is no driver handler to take the TXB, dont' bother
526 * creating it... */
527 if (!ieee->hard_start_xmit) {
528 printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
529 goto success;
530 }
531
532 if (unlikely(len < 24)) {
533 printk(KERN_WARNING "%s: skb too small (%d).\n",
534 ieee->dev->name, len);
535 goto success;
536 }
537
538 /* When we allocate the TXB we allocate enough space for the reserve
539 * and full fragment bytes (bytes_per_frag doesn't include prefix,
540 * postfix, header, FCS, etc.) */
541 txb = ieee80211_alloc_txb(1, len, GFP_ATOMIC);
542 if (unlikely(!txb)) {
543 printk(KERN_WARNING "%s: Could not allocate TXB\n",
544 ieee->dev->name);
545 goto failed;
546 }
547 txb->encrypted = 0;
548 txb->payload_size = len;
549
550 skb_frag = txb->fragments[0];
551
552 memcpy(skb_put(skb_frag, len), frame, len);
553
554 if (ieee->config &
555 (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
556 skb_put(skb_frag, 4);
557
558 success:
559 spin_unlock_irqrestore(&ieee->lock, flags);
560
561 if (txb) {
James Ketrenos9e8571a2005-09-21 11:56:33 -0500562 if ((*ieee->hard_start_xmit) (txb, ieee->dev, priority) == 0) {
James Ketrenos3f552bb2005-09-21 11:54:47 -0500563 stats->tx_packets++;
564 stats->tx_bytes += txb->payload_size;
565 return 0;
566 }
567 ieee80211_txb_free(txb);
568 }
569 return 0;
570
571 failed:
572 spin_unlock_irqrestore(&ieee->lock, flags);
573 stats->tx_errors++;
574 return 1;
575}
576
577EXPORT_SYMBOL(ieee80211_tx_frame);
Jeff Garzikb4538722005-05-12 22:48:20 -0400578EXPORT_SYMBOL(ieee80211_txb_free);