1ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman/******************************************************************************
2ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
3ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
4ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
5ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  This program is free software; you can redistribute it and/or modify it
6ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  under the terms of version 2 of the GNU General Public License as
7ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  published by the Free Software Foundation.
8ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
9ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  This program is distributed in the hope that it will be useful, but WITHOUT
10ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  more details.
13ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
14ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  You should have received a copy of the GNU General Public License along with
15ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  this program; if not, write to the Free Software Foundation, Inc., 59
16ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
18ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  The full GNU General Public License is included in this distribution in the
19ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  file called LICENSE.
20ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
21ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  Contact Information:
22ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  James P. Ketrenos <ipw2100-admin@linux.intel.com>
23ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
25ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman******************************************************************************
26ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
27ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  Few modifications for Realtek's Wi-Fi drivers by
28ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  Andrea Merello <andreamrl@tiscali.it>
29ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
30ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman  A special thanks goes to Realtek for their support !
31ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
32ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman******************************************************************************/
33ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
34ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/compiler.h>
35ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/errno.h>
36ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/if_arp.h>
37ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/in6.h>
38ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/in.h>
39ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/ip.h>
40ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/kernel.h>
41ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/module.h>
42ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/netdevice.h>
43ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/pci.h>
44ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/proc_fs.h>
45ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/skbuff.h>
46ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/slab.h>
47ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/tcp.h>
48ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/types.h>
49ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/wireless.h>
50ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/etherdevice.h>
51f38d223b692742e77c70033d145245615c8f3aa5Larry Finger#include <linux/uaccess.h>
52ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman#include <linux/if_vlan.h>
53ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
5494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger#include "rtllib.h"
55ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
56ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman/*
57ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
58ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
59ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman802.11 Data Frame
60ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
61ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
62ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman802.11 frame_contorl for data frames - 2 bytes
63ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman     ,-----------------------------------------------------------------------------------------.
64ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartmanbits | 0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  |  a  |  b  |  c  |  d  |  e   |
65ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman     |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------|
66ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartmanval  | 0  |  0  |  0  |  1  |  x  |  0  |  0  |  0  |  1  |  0  |  x  |  x  |  x  |  x  |  x   |
67ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman     |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------|
68ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartmandesc | ^-ver-^  |  ^type-^  |  ^-----subtype-----^  | to  |from |more |retry| pwr |more |wep   |
69f38d223b692742e77c70033d145245615c8f3aa5Larry Finger     |	  |	   | x=0 data,x=1 data+ack | DS  | DS  |frag |     | mgm |data |      |
70ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman     '-----------------------------------------------------------------------------------------'
71f38d223b692742e77c70033d145245615c8f3aa5Larry Finger						    /\
72f38d223b692742e77c70033d145245615c8f3aa5Larry Finger						    |
73f38d223b692742e77c70033d145245615c8f3aa5Larry Finger802.11 Data Frame				   |
74f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	   ,--------- 'ctrl' expands to >-----------'
75f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	  |
76ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman      ,--'---,-------------------------------------------------------------.
77ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanBytes |  2   |  2   |    6    |    6    |    6    |  2   | 0..2312 |   4  |
78ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman      |------|------|---------|---------|---------|------|---------|------|
79ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanDesc. | ctrl | dura |  DA/RA  |   TA    |    SA   | Sequ |  Frame  |  fcs |
80f38d223b692742e77c70033d145245615c8f3aa5Larry Finger      |      | tion | (BSSID) |	 |	 | ence |  data   |      |
81f38d223b692742e77c70033d145245615c8f3aa5Larry Finger      `--------------------------------------------------|	 |------'
82f38d223b692742e77c70033d145245615c8f3aa5Larry FingerTotal: 28 non-data bytes				 `----.----'
83f38d223b692742e77c70033d145245615c8f3aa5Larry Finger							      |
84ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman       .- 'Frame data' expands to <---------------------------'
85ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman       |
86ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman       V
87ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman      ,---------------------------------------------------.
88ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanBytes |  1   |  1   |    1    |    3     |  2   |  0-2304 |
89ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman      |------|------|---------|----------|------|---------|
90ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanDesc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP      |
91f38d223b692742e77c70033d145245615c8f3aa5Larry Finger      | DSAP | SSAP |	 |	  |      | Packet  |
92f38d223b692742e77c70033d145245615c8f3aa5Larry Finger      | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8|      |	 |
93f38d223b692742e77c70033d145245615c8f3aa5Larry Finger      `-----------------------------------------|	 |
94f38d223b692742e77c70033d145245615c8f3aa5Larry FingerTotal: 8 non-data bytes			 `----.----'
95f38d223b692742e77c70033d145245615c8f3aa5Larry Finger						     |
96ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman       .- 'IP Packet' expands, if WEP enabled, to <--'
97ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman       |
98ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman       V
99ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman      ,-----------------------.
100ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanBytes |  4  |   0-2296  |  4  |
101ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman      |-----|-----------|-----|
102ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanDesc. | IV  | Encrypted | ICV |
103ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman      |     | IP Packet |     |
104ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman      `-----------------------'
105ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanTotal: 8 non-data bytes
106ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
107ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
108ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman802.3 Ethernet Data Frame
109ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
110ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman      ,-----------------------------------------.
111ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanBytes |   6   |   6   |  2   |  Variable |   4  |
112ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman      |-------|-------|------|-----------|------|
113ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanDesc. | Dest. | Source| Type | IP Packet |  fcs |
114f38d223b692742e77c70033d145245615c8f3aa5Larry Finger      |  MAC  |  MAC  |      |	   |      |
115ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman      `-----------------------------------------'
116ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanTotal: 18 non-data bytes
117ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
118ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanIn the event that fragmentation is required, the incoming payload is split into
119ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanN parts of size ieee->fts.  The first fragment contains the SNAP header and the
120ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartmanremaining packets are just data.
121ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
122ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanIf encryption is enabled, each fragment payload size is reduced by enough space
123ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartmanto add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP)
124ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanSo if you have 1500 bytes of payload with ieee->fts set to 500 without
125ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartmanencryption it will take 3 frames.  With WEP it will take 4 frames as the
126ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartmanpayload of each frame is reduced to 492 bytes.
127ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
128ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman* SKB visualization
129ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman*
130ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman*  ,- skb->data
131ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman* |
132f38d223b692742e77c70033d145245615c8f3aa5Larry Finger* |    ETHERNET HEADER	,-<-- PAYLOAD
133f38d223b692742e77c70033d145245615c8f3aa5Larry Finger* |			   |     14 bytes from skb->data
134ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman* |  2 bytes for Type --> ,T. |     (sizeof ethhdr)
135f38d223b692742e77c70033d145245615c8f3aa5Larry Finger* |		       | | |
136ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman* |,-Dest.--. ,--Src.---. | | |
137ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman* |  6 bytes| | 6 bytes | | | |
138f38d223b692742e77c70033d145245615c8f3aa5Larry Finger* v	 | |	 | | | |
139f38d223b692742e77c70033d145245615c8f3aa5Larry Finger* 0	 | v       1 | v | v	   2
140ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman* 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
141f38d223b692742e77c70033d145245615c8f3aa5Larry Finger*     ^     | ^	 | ^ |
142f38d223b692742e77c70033d145245615c8f3aa5Larry Finger*     |     | |	 | | |
143f38d223b692742e77c70033d145245615c8f3aa5Larry Finger*     |     | |	 | `T' <---- 2 bytes for Type
144f38d223b692742e77c70033d145245615c8f3aa5Larry Finger*     |     | |	 |
145ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman*     |     | '---SNAP--' <-------- 6 bytes for SNAP
146ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman*     |     |
147ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman*     `-IV--' <-------------------- 4 bytes for IV (WEP)
148ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman*
149ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman*      SNAP HEADER
150ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman*
151ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman*/
152ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
153ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartmanstatic u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
154ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartmanstatic u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
155ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
15694a799425eee8225a1e3fbe5f473d2ef04002577Larry Fingerinline int rtllib_put_snap(u8 *data, u16 h_proto)
157ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
15894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_snap_hdr *snap;
159ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u8 *oui;
160ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
16194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	snap = (struct rtllib_snap_hdr *)data;
162ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	snap->dsap = 0xaa;
163ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	snap->ssap = 0xaa;
164ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	snap->ctrl = 0x03;
165ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
166ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (h_proto == 0x8137 || h_proto == 0x80f3)
167ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		oui = P802_1H_OUI;
168ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	else
169ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		oui = RFC1042_OUI;
170ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	snap->oui[0] = oui[0];
171ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	snap->oui[1] = oui[1];
172ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	snap->oui[2] = oui[2];
173ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
174ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	*(u16 *)(data + SNAP_SIZE) = htons(h_proto);
175ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
176ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return SNAP_SIZE + sizeof(u16);
177ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
178ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
179f38d223b692742e77c70033d145245615c8f3aa5Larry Fingerint rtllib_encrypt_fragment(struct rtllib_device *ieee, struct sk_buff *frag,
180f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			    int hdr_len)
181ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
18232c44cb5b9fdc6eaa445bd622008dd672a3dd1a7Sean MacLennan	struct lib80211_crypt_data *crypt = NULL;
183ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	int res;
184ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
1850ddcf5fdfac6bd80e153ee5c405bdfc9cb868b95Sean MacLennan	crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
18694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger
187f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (!(crypt && crypt->ops)) {
188f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		printk(KERN_INFO "=========>%s(), crypt is null\n", __func__);
189ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return -1;
190ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
191ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	/* To encrypt, frame format is:
192ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	 * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
193ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
194ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	/* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
195ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	 * call both MSDU and MPDU encryption functions from here. */
196ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	atomic_inc(&crypt->refcnt);
197ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	res = 0;
198ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (crypt->ops->encrypt_msdu)
199ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv);
200ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (res == 0 && crypt->ops->encrypt_mpdu)
201ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
202ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
203ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	atomic_dec(&crypt->refcnt);
204ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (res < 0) {
205ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		printk(KERN_INFO "%s: Encryption failed: len=%d.\n",
206ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		       ieee->dev->name, frag->len);
207ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		ieee->ieee_stats.tx_discards++;
208ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return -1;
209ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
210ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
211ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return 0;
212ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
213ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
214ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
215f38d223b692742e77c70033d145245615c8f3aa5Larry Fingervoid rtllib_txb_free(struct rtllib_txb *txb)
216f38d223b692742e77c70033d145245615c8f3aa5Larry Finger{
217ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (unlikely(!txb))
218ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
219ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	kfree(txb);
220ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
221ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
222ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Fingerstatic struct rtllib_txb *rtllib_alloc_txb(int nr_frags, int txb_size,
223ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Finger					   gfp_t gfp_mask)
224ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
22594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_txb *txb;
226ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	int i;
227f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	txb = kmalloc(sizeof(struct rtllib_txb) + (sizeof(u8 *) * nr_frags),
228f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		      gfp_mask);
229ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (!txb)
230ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return NULL;
231ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
23294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	memset(txb, 0, sizeof(struct rtllib_txb));
233ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	txb->nr_frags = nr_frags;
234ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	txb->frag_size = txb_size;
235ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
236ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	for (i = 0; i < nr_frags; i++) {
237ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		txb->fragments[i] = dev_alloc_skb(txb_size);
238ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (unlikely(!txb->fragments[i])) {
239ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			i--;
240ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			break;
241ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
242ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		memset(txb->fragments[i]->cb, 0, sizeof(txb->fragments[i]->cb));
243ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
244ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (unlikely(i != nr_frags)) {
245ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		while (i >= 0)
246ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			dev_kfree_skb_any(txb->fragments[i--]);
247ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		kfree(txb);
248ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return NULL;
249ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
250ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return txb;
251ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
252ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
253ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Fingerstatic int rtllib_classify(struct sk_buff *skb, u8 bIsAmsdu)
254ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
255ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	struct ethhdr *eth;
256ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	struct iphdr *ip;
25794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger
258ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	eth = (struct ethhdr *)skb->data;
259ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (eth->h_proto != htons(ETH_P_IP))
260ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return 0;
261ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
26294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA, skb->data, skb->len);
263ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	ip = ip_hdr(skb);
264ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	switch (ip->tos & 0xfc) {
26594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	case 0x20:
26694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		return 2;
26794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	case 0x40:
26894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		return 1;
26994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	case 0x60:
27094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		return 3;
27194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	case 0x80:
27294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		return 4;
27394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	case 0xa0:
27494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		return 5;
27594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	case 0xc0:
27694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		return 6;
27794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	case 0xe0:
27894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		return 7;
27994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	default:
28094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		return 0;
281ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
282ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
283ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
284ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Fingerstatic void rtllib_tx_query_agg_cap(struct rtllib_device *ieee,
285ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Finger				    struct sk_buff *skb,
286ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Finger				    struct cb_desc *tcb_desc)
287ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
2887796d93eae46054d5a3bb5411fde735801998dc5Larry Finger	struct rt_hi_throughput *pHTInfo = ieee->pHTInfo;
28960554f2bdb1579ca54631e99642025797f860eb7Larry Finger	struct tx_ts_record *pTxTs = NULL;
290f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	struct rtllib_hdr_1addr* hdr = (struct rtllib_hdr_1addr *)skb->data;
29194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger
292f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (rtllib_act_scanning(ieee, false))
29394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		return;
294ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
295f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (!pHTInfo->bCurrentHTSupport || !pHTInfo->bEnableHT)
296ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
297ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (!IsQoSDataFrame(skb->data))
298ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
299f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (is_multicast_ether_addr(hdr->addr1) ||
300f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	    is_broadcast_ether_addr(hdr->addr1))
301ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
30265a4378471510787e080188f933913315f1afa0cdavid woo
303f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (tcb_desc->bdhcp || ieee->CntAfterLink < 2)
30494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		return;
30565a4378471510787e080188f933913315f1afa0cdavid woo
30694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	if (pHTInfo->IOTAction & HT_IOT_ACT_TX_NO_AGGREGATION)
30794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		return;
30865a4378471510787e080188f933913315f1afa0cdavid woo
30994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	if (!ieee->GetNmodeSupportBySecCfg(ieee->dev))
310ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
311f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (pHTInfo->bCurrentAMPDUEnable) {
312f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		if (!GetTs(ieee, (struct ts_common_info **)(&pTxTs), hdr->addr1,
313f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		    skb->priority, TX_DIR, true)) {
314f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			printk(KERN_INFO "%s: can't get TS\n", __func__);
315ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			return;
316ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
317f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		if (pTxTs->TxAdmittedBARecord.bValid == false) {
318f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (ieee->wpa_ie_len && (ieee->pairwise_key_type ==
319f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			    KEY_TYPE_NA)) {
32094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				;
321f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			} else if (tcb_desc->bdhcp == 1) {
32294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				;
323f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			} else if (!pTxTs->bDisable_AddBa) {
32494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				TsStartAddBaProcess(ieee, pTxTs);
32594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			}
326ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			goto FORCED_AGG_SETTING;
32794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		} else if (pTxTs->bUsingBa == false) {
328f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (SN_LESS(pTxTs->TxAdmittedBARecord.BaStartSeqCtrl.field.SeqNum,
329f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			   (pTxTs->TxCurSeq+1)%4096))
330ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				pTxTs->bUsingBa = true;
331ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			else
332ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				goto FORCED_AGG_SETTING;
333ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
33494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		if (ieee->iw_mode == IW_MODE_INFRA) {
335ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			tcb_desc->bAMPDUEnable = true;
336ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			tcb_desc->ampdu_factor = pHTInfo->CurrentAMPDUFactor;
337ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			tcb_desc->ampdu_density = pHTInfo->CurrentMPDUDensity;
338ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
339ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
340ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanFORCED_AGG_SETTING:
34194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	switch (pHTInfo->ForcedAMPDUMode) {
342f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	case HT_AGG_AUTO:
343f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		break;
344f38d223b692742e77c70033d145245615c8f3aa5Larry Finger
345f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	case HT_AGG_FORCE_ENABLE:
346f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		tcb_desc->bAMPDUEnable = true;
347f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		tcb_desc->ampdu_density = pHTInfo->ForcedMPDUDensity;
348f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		tcb_desc->ampdu_factor = pHTInfo->ForcedAMPDUFactor;
349f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		break;
350f38d223b692742e77c70033d145245615c8f3aa5Larry Finger
351f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	case HT_AGG_FORCE_DISABLE:
352f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		tcb_desc->bAMPDUEnable = false;
353f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		tcb_desc->ampdu_density = 0;
354f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		tcb_desc->ampdu_factor = 0;
355f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		break;
356ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
357f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	return;
358ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
359ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
360ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Fingerstatic void rtllib_qurey_ShortPreambleMode(struct rtllib_device *ieee,
361f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					   struct cb_desc *tcb_desc)
362ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
363ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	tcb_desc->bUseShortPreamble = false;
364ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (tcb_desc->data_rate == 2)
365ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
366f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	else if (ieee->current_network.capability &
367f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		 WLAN_CAPABILITY_SHORT_PREAMBLE)
368ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		tcb_desc->bUseShortPreamble = true;
369ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return;
370ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
37194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger
372ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Fingerstatic void rtllib_query_HTCapShortGI(struct rtllib_device *ieee,
373f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				      struct cb_desc *tcb_desc)
374ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
3757796d93eae46054d5a3bb5411fde735801998dc5Larry Finger	struct rt_hi_throughput *pHTInfo = ieee->pHTInfo;
376ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
37794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	tcb_desc->bUseShortGI		= false;
378ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
379f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (!pHTInfo->bCurrentHTSupport || !pHTInfo->bEnableHT)
380ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
381ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
382f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (pHTInfo->bForcedShortGI) {
383ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		tcb_desc->bUseShortGI = true;
384ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
385ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
386ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
387f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if ((pHTInfo->bCurBW40MHz == true) && pHTInfo->bCurShortGI40MHz)
388ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		tcb_desc->bUseShortGI = true;
389f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	else if ((pHTInfo->bCurBW40MHz == false) && pHTInfo->bCurShortGI20MHz)
390ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		tcb_desc->bUseShortGI = true;
391ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
392ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
393ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Fingerstatic void rtllib_query_BandwidthMode(struct rtllib_device *ieee,
394ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Finger				       struct cb_desc *tcb_desc)
395ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
3967796d93eae46054d5a3bb5411fde735801998dc5Larry Finger	struct rt_hi_throughput *pHTInfo = ieee->pHTInfo;
397ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
398ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	tcb_desc->bPacketBW = false;
399ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
400f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (!pHTInfo->bCurrentHTSupport || !pHTInfo->bEnableHT)
401ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
402ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
40394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	if (tcb_desc->bMulticast || tcb_desc->bBroadcast)
404ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
405ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
406f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if ((tcb_desc->data_rate & 0x80) == 0)
407ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
408f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (pHTInfo->bCurBW40MHz && pHTInfo->bCurTxBW40MHz &&
409f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	    !ieee->bandwidth_auto_switch.bforced_tx20Mhz)
410ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		tcb_desc->bPacketBW = true;
411ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return;
412ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
41394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger
414ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Fingerstatic void rtllib_query_protectionmode(struct rtllib_device *ieee,
415ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Finger					struct cb_desc *tcb_desc,
416ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Finger					struct sk_buff *skb)
417ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
418ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	tcb_desc->bRTSSTBC			= false;
41994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	tcb_desc->bRTSUseShortGI		= false;
42094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	tcb_desc->bCTSEnable			= false;
42194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	tcb_desc->RTSSC				= 0;
42294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	tcb_desc->bRTSBW			= false;
423ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
42494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	if (tcb_desc->bBroadcast || tcb_desc->bMulticast)
425ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
426ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
42794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	if (is_broadcast_ether_addr(skb->data+16))
428ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
429ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
430f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (ieee->mode < IEEE_N_24G) {
431f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		if (skb->len > ieee->rts) {
432ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			tcb_desc->bRTSEnable = true;
433ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			tcb_desc->rts_rate = MGN_24M;
434f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		} else if (ieee->current_network.buseprotection) {
435ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			tcb_desc->bRTSEnable = true;
436ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			tcb_desc->bCTSEnable = true;
437ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			tcb_desc->rts_rate = MGN_24M;
438ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
439ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		return;
440f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	} else {
4417796d93eae46054d5a3bb5411fde735801998dc5Larry Finger		struct rt_hi_throughput *pHTInfo = ieee->pHTInfo;
442f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		while (true) {
443f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (pHTInfo->IOTAction & HT_IOT_ACT_FORCED_CTS2SELF) {
44494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->bCTSEnable	= true;
44594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->rts_rate  =	MGN_24M;
44694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->bRTSEnable = true;
44794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				break;
448f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			} else if (pHTInfo->IOTAction & (HT_IOT_ACT_FORCED_RTS |
449f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				   HT_IOT_ACT_PURE_N_MODE)) {
45094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->bRTSEnable = true;
45194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->rts_rate  =	MGN_24M;
45294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				break;
45394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			}
454f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (ieee->current_network.buseprotection) {
455ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				tcb_desc->bRTSEnable = true;
456ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				tcb_desc->bCTSEnable = true;
457ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				tcb_desc->rts_rate = MGN_24M;
458ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				break;
459ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			}
460f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (pHTInfo->bCurrentHTSupport  && pHTInfo->bEnableHT) {
461ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				u8 HTOpMode = pHTInfo->CurrentOpMode;
462f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				if ((pHTInfo->bCurBW40MHz && (HTOpMode == 2 ||
463f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				     HTOpMode == 3)) ||
464f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				     (!pHTInfo->bCurBW40MHz && HTOpMode == 3)) {
46594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger					tcb_desc->rts_rate = MGN_24M;
466ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman					tcb_desc->bRTSEnable = true;
467ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman					break;
468ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				}
469ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			}
470f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (skb->len > ieee->rts) {
47194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->rts_rate = MGN_24M;
472ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				tcb_desc->bRTSEnable = true;
473ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				break;
474ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			}
475f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (tcb_desc->bAMPDUEnable) {
47694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->rts_rate = MGN_24M;
477ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				tcb_desc->bRTSEnable = false;
478ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				break;
479ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			}
480ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			goto NO_PROTECTION;
481ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
482ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
483ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
484ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		tcb_desc->bUseShortPreamble = true;
48594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	if (ieee->iw_mode == IW_MODE_MASTER)
486ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			goto NO_PROTECTION;
487ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return;
488ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-HartmanNO_PROTECTION:
489ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	tcb_desc->bRTSEnable	= false;
490ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	tcb_desc->bCTSEnable	= false;
491f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	tcb_desc->rts_rate	= 0;
492ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	tcb_desc->RTSSC		= 0;
493f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	tcb_desc->bRTSBW	= false;
494ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
495ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
496ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
497ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Fingerstatic void rtllib_txrate_selectmode(struct rtllib_device *ieee,
498ec0dc6beea5436c037707dc0f501cf07878a8e2aLarry Finger				     struct cb_desc *tcb_desc)
499ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
50094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	if (ieee->bTxDisableRateFallBack)
501ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		tcb_desc->bTxDisableRateFallBack = true;
502ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
50394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	if (ieee->bTxUseDriverAssingedRate)
504ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		tcb_desc->bTxUseDriverAssingedRate = true;
505f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (!tcb_desc->bTxDisableRateFallBack ||
506f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	    !tcb_desc->bTxUseDriverAssingedRate) {
507f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		if (ieee->iw_mode == IW_MODE_INFRA ||
508f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		    ieee->iw_mode == IW_MODE_ADHOC)
509ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			tcb_desc->RATRIndex = 0;
510ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
511ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
512ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
513f38d223b692742e77c70033d145245615c8f3aa5Larry Fingeru16 rtllib_query_seqnum(struct rtllib_device *ieee, struct sk_buff *skb,
514f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			u8 *dst)
515ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
51694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	u16 seqnum = 0;
51794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger
518ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst))
51994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		return 0;
520f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (IsQoSDataFrame(skb->data)) {
52160554f2bdb1579ca54631e99642025797f860eb7Larry Finger		struct tx_ts_record *pTS = NULL;
522f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst,
523f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		    skb->priority, TX_DIR, true))
52494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			return 0;
52594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		seqnum = pTS->TxCurSeq;
526ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		pTS->TxCurSeq = (pTS->TxCurSeq+1)%4096;
52794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		return seqnum;
52894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	}
52994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	return 0;
53094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger}
53194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger
53294a799425eee8225a1e3fbe5f473d2ef04002577Larry Fingerstatic int wme_downgrade_ac(struct sk_buff *skb)
53394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger{
53494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	switch (skb->priority) {
535f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	case 6:
536f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	case 7:
537f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		skb->priority = 5; /* VO -> VI */
538f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		return 0;
539f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	case 4:
540f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	case 5:
541f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		skb->priority = 3; /* VI -> BE */
542f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		return 0;
543f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	case 0:
544f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	case 3:
545f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		skb->priority = 1; /* BE -> BK */
546f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		return 0;
547f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	default:
548f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		return -1;
549ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
550ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
551ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
55294a799425eee8225a1e3fbe5f473d2ef04002577Larry Fingerint rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
553ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman{
554f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	struct rtllib_device *ieee = (struct rtllib_device *)
555f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				     netdev_priv_rsl(dev);
55694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_txb *txb = NULL;
55794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_hdr_3addrqos *frag_hdr;
558ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size;
559ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	unsigned long flags;
560ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	struct net_device_stats *stats = &ieee->stats;
561ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	int ether_type = 0, encrypt;
562ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	int bytes, fc, qos_ctl = 0, hdr_len;
563ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	struct sk_buff *skb_frag;
56494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	struct rtllib_hdr_3addrqos header = { /* Ensure zero initialized */
565ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		.duration_id = 0,
566ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		.seq_ctl = 0,
567ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		.qos_ctl = 0
568ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	};
569ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	u8 dest[ETH_ALEN], src[ETH_ALEN];
570ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	int qos_actived = ieee->current_network.qos_data.active;
57132c44cb5b9fdc6eaa445bd622008dd672a3dd1a7Sean MacLennan	struct lib80211_crypt_data *crypt = NULL;
5723b83db43ccbb26863f38caccc1e7fae370f31e57Larry Finger	struct cb_desc *tcb_desc;
57394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	u8 bIsMulticast = false;
57494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	u8 IsAmsdu = false;
575f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	bool	bdhcp = false;
576ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
577ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	spin_lock_irqsave(&ieee->lock, flags);
578ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
579ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	/* If there is no driver handler to take the TXB, dont' bother
580ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	 * creating it... */
581f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if ((!ieee->hard_start_xmit && !(ieee->softmac_features &
582f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	   IEEE_SOFTMAC_TX_QUEUE)) ||
583f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	   ((!ieee->softmac_data_hard_start_xmit &&
584f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	   (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) {
585ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		printk(KERN_WARNING "%s: No xmit handler.\n",
586ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		       ieee->dev->name);
587ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		goto success;
588ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
589ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
590ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
591f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (likely(ieee->raw_tx == 0)) {
592ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
593ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			printk(KERN_WARNING "%s: skb too small (%d).\n",
594ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			ieee->dev->name, skb->len);
595ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			goto success;
596ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
59794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		/* Save source and destination addresses */
59894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		memcpy(dest, skb->data, ETH_ALEN);
59994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		memcpy(src, skb->data+ETH_ALEN, ETH_ALEN);
600ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
601ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		memset(skb->cb, 0, sizeof(skb->cb));
602ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto);
603ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
604f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		if (ieee->iw_mode == IW_MODE_MONITOR) {
60594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			txb = rtllib_alloc_txb(1, skb->len, GFP_ATOMIC);
60694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			if (unlikely(!txb)) {
607f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				printk(KERN_WARNING "%s: Could not allocate "
608f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				       "TXB\n",
60994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				ieee->dev->name);
61094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				goto failed;
61194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			}
612ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
61394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			txb->encrypted = 0;
61494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			txb->payload_size = skb->len;
615f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			memcpy(skb_put(txb->fragments[0], skb->len), skb->data,
616f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			       skb->len);
617ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
618ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			goto success;
619ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
620ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
62155dc4eb35f7c191db2767c887c158a8de0e6e4f7Larry Finger		if (skb->len > 282) {
62294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			if (ETH_P_IP == ether_type) {
623f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				const struct iphdr *ip = (struct iphdr *)
624f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					((u8 *)skb->data+14);
62594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				if (IPPROTO_UDP == ip->protocol) {
626f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					struct udphdr *udp;
627f38d223b692742e77c70033d145245615c8f3aa5Larry Finger
628f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					udp = (struct udphdr *)((u8 *)ip +
629f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					      (ip->ihl << 2));
630f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					if (((((u8 *)udp)[1] == 68) &&
631f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					   (((u8 *)udp)[3] == 67)) ||
632f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					   ((((u8 *)udp)[1] == 67) &&
633f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					   (((u8 *)udp)[3] == 68))) {
63465a4378471510787e080188f933913315f1afa0cdavid woo						bdhcp = true;
63594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger						ieee->LPSDelayCnt = 200;
63665a4378471510787e080188f933913315f1afa0cdavid woo					}
63765a4378471510787e080188f933913315f1afa0cdavid woo				}
638f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			} else if (ETH_P_ARP == ether_type) {
639f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				printk(KERN_INFO "=================>DHCP "
640f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				       "Protocol start tx ARP pkt!!\n");
64194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				bdhcp = true;
642f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				ieee->LPSDelayCnt =
643f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					 ieee->current_network.tim.tim_count;
64465a4378471510787e080188f933913315f1afa0cdavid woo			}
64594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		}
64665a4378471510787e080188f933913315f1afa0cdavid woo
64794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		skb->priority = rtllib_classify(skb, IsAmsdu);
6480ddcf5fdfac6bd80e153ee5c405bdfc9cb868b95Sean MacLennan		crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
64994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) &&
65094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			ieee->host_encrypt && crypt && crypt->ops;
65194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		if (!encrypt && ieee->ieee802_1x &&
652f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		    ieee->drop_unencrypted && ether_type != ETH_P_PAE) {
65394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			stats->tx_dropped++;
65494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			goto success;
65594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		}
65694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		if (crypt && !encrypt && ether_type == ETH_P_PAE) {
65794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			struct eapol *eap = (struct eapol *)(skb->data +
658f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				sizeof(struct ethhdr) - SNAP_SIZE -
659f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				sizeof(u16));
66094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			RTLLIB_DEBUG_EAP("TX: IEEE 802.11 EAPOL frame: %s\n",
66194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				eap_get_type(eap->type));
66294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		}
663ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
66494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		/* Advance the SKB to the start of the payload */
66594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		skb_pull(skb, sizeof(struct ethhdr));
666ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
667f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		/* Determine total amount of storage required for TXB packets */
66894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		bytes = skb->len + SNAP_SIZE + sizeof(u16);
669ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
670ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (encrypt)
67194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			fc = RTLLIB_FTYPE_DATA | RTLLIB_FCTL_WEP;
672ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		else
67394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			fc = RTLLIB_FTYPE_DATA;
674ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
67594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		if (qos_actived)
67694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			fc |= RTLLIB_STYPE_QOS_DATA;
677ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		else
67894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			fc |= RTLLIB_STYPE_DATA;
679ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
680ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (ieee->iw_mode == IW_MODE_INFRA) {
68194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			fc |= RTLLIB_FCTL_TODS;
682ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			/* To DS: Addr1 = BSSID, Addr2 = SA,
683ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			Addr3 = DA */
684f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			memcpy(&header.addr1, ieee->current_network.bssid,
685f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			       ETH_ALEN);
686ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			memcpy(&header.addr2, &src, ETH_ALEN);
68794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			if (IsAmsdu)
688f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				memcpy(&header.addr3,
689f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				       ieee->current_network.bssid, ETH_ALEN);
69094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			else
69194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				memcpy(&header.addr3, &dest, ETH_ALEN);
692ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		} else if (ieee->iw_mode == IW_MODE_ADHOC) {
693ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			/* not From/To DS: Addr1 = DA, Addr2 = SA,
694ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			Addr3 = BSSID */
695ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			memcpy(&header.addr1, dest, ETH_ALEN);
696ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			memcpy(&header.addr2, src, ETH_ALEN);
697f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			memcpy(&header.addr3, ieee->current_network.bssid,
698f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			       ETH_ALEN);
699ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
700ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
701f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		bIsMulticast = is_broadcast_ether_addr(header.addr1) ||
702f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			       is_multicast_ether_addr(header.addr1);
70394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger
704f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		header.frame_ctl = cpu_to_le16(fc);
705ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
706ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		/* Determine fragmentation size based on destination (multicast
707ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		* and broadcast are not fragmented) */
70894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		if (bIsMulticast) {
709ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			frag_size = MAX_FRAG_THRESHOLD;
710ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			qos_ctl |= QOS_CTL_NOTCONTAIN_ACK;
71194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		} else {
71294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			frag_size = ieee->fts;
713ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			qos_ctl = 0;
714ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
715ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
71694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		if (qos_actived) {
71794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			hdr_len = RTLLIB_3ADDR_LEN + 2;
71894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger
719f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		/* in case we are a client verify acm is not set for this ac */
720f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		while (unlikely(ieee->wmm_acm & (0x01 << skb->priority))) {
721f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			printk(KERN_INFO "skb->priority = %x\n", skb->priority);
722f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (wme_downgrade_ac(skb))
723f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				break;
724f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			printk(KERN_INFO "converted skb->priority = %x\n",
725f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			       skb->priority);
726f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		 }
727f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			qos_ctl |= skb->priority;
728f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			header.qos_ctl = cpu_to_le16(qos_ctl & RTLLIB_QOS_TID);
729ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		} else {
73094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			hdr_len = RTLLIB_3ADDR_LEN;
731ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
732ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		/* Determine amount of payload per fragment.  Regardless of if
733f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		 * this stack is providing the full 802.11 header, one will
734f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		 * eventually be affixed to this fragment -- so we must account
735f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		 * for it when determining the amount of payload space. */
736ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		bytes_per_frag = frag_size - hdr_len;
737ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (ieee->config &
738f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		   (CFG_RTLLIB_COMPUTE_FCS | CFG_RTLLIB_RESERVE_FCS))
73994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			bytes_per_frag -= RTLLIB_FCS_LEN;
740ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
741f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		/* Each fragment may need to have room for encryptiong
742f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		 * pre/postfix */
74394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		if (encrypt) {
74432c44cb5b9fdc6eaa445bd622008dd672a3dd1a7Sean MacLennan			bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
74532c44cb5b9fdc6eaa445bd622008dd672a3dd1a7Sean MacLennan				crypt->ops->extra_mpdu_postfix_len +
74632c44cb5b9fdc6eaa445bd622008dd672a3dd1a7Sean MacLennan				crypt->ops->extra_msdu_prefix_len +
74732c44cb5b9fdc6eaa445bd622008dd672a3dd1a7Sean MacLennan				crypt->ops->extra_msdu_postfix_len;
74894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		}
749ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		/* Number of fragments is the total bytes_per_frag /
750ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		* payload_per_fragment */
751ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		nr_frags = bytes / bytes_per_frag;
752ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		bytes_last_frag = bytes % bytes_per_frag;
753ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (bytes_last_frag)
754ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			nr_frags++;
755ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		else
756ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			bytes_last_frag = bytes_per_frag;
757ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
758f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		/* When we allocate the TXB we allocate enough space for the
759f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		 * reserve and full fragment bytes (bytes_per_frag doesn't
760f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		 * include prefix, postfix, header, FCS, etc.) */
761f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		txb = rtllib_alloc_txb(nr_frags, frag_size +
762f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				       ieee->tx_headroom, GFP_ATOMIC);
763ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		if (unlikely(!txb)) {
764ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			printk(KERN_WARNING "%s: Could not allocate TXB\n",
765ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			ieee->dev->name);
766ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			goto failed;
767ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
768ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		txb->encrypted = encrypt;
769ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		txb->payload_size = bytes;
770ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
77194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		if (qos_actived)
772ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			txb->queue_index = UP2AC(skb->priority);
773f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		else
774f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			txb->queue_index = WME_AC_BE;
775ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
776ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		for (i = 0; i < nr_frags; i++) {
777ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			skb_frag = txb->fragments[i];
778f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			tcb_desc = (struct cb_desc *)(skb_frag->cb +
779f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				    MAX_DEV_ADDR_SIZE);
780f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (qos_actived) {
78194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				skb_frag->priority = skb->priority;
782ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				tcb_desc->queue_index =  UP2AC(skb->priority);
783ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			} else {
78494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				skb_frag->priority = WME_AC_BE;
78594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->queue_index = WME_AC_BE;
786ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			}
787ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			skb_reserve(skb_frag, ieee->tx_headroom);
788ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
789f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (encrypt) {
790ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				if (ieee->hwsec_active)
791ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman					tcb_desc->bHwSec = 1;
792ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				else
793ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman					tcb_desc->bHwSec = 0;
794f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				skb_reserve(skb_frag,
79532c44cb5b9fdc6eaa445bd622008dd672a3dd1a7Sean MacLennan					    crypt->ops->extra_mpdu_prefix_len +
79632c44cb5b9fdc6eaa445bd622008dd672a3dd1a7Sean MacLennan					    crypt->ops->extra_msdu_prefix_len);
79794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			} else {
798ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				tcb_desc->bHwSec = 0;
799ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			}
800f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			frag_hdr = (struct rtllib_hdr_3addrqos *)
801f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				   skb_put(skb_frag, hdr_len);
802ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			memcpy(frag_hdr, &header, hdr_len);
803ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
804f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			/* If this is not the last fragment, then add the
805f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			 * MOREFRAGS bit to the frame control */
806ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			if (i != nr_frags - 1) {
807ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				frag_hdr->frame_ctl = cpu_to_le16(
80894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger					fc | RTLLIB_FCTL_MOREFRAGS);
809ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				bytes = bytes_per_frag;
810ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
811ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			} else {
812f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				/* The last fragment has the remaining length */
813ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				bytes = bytes_last_frag;
814ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			}
815f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if ((qos_actived) && (!bIsMulticast)) {
816f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				frag_hdr->seq_ctl =
817f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					 rtllib_query_seqnum(ieee, skb_frag,
818f38d223b692742e77c70033d145245615c8f3aa5Larry Finger							     header.addr1);
819f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				frag_hdr->seq_ctl =
820f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					 cpu_to_le16(frag_hdr->seq_ctl<<4 | i);
821ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			} else {
822f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				frag_hdr->seq_ctl =
823f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					 cpu_to_le16(ieee->seq_ctrl[0]<<4 | i);
824ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			}
825ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			/* Put a SNAP header on the first fragment */
826ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			if (i == 0) {
82794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				rtllib_put_snap(
828f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					skb_put(skb_frag, SNAP_SIZE +
829f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					sizeof(u16)), ether_type);
830ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				bytes -= SNAP_SIZE + sizeof(u16);
831ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			}
832ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
833ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			memcpy(skb_put(skb_frag, bytes), skb->data, bytes);
834ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
835ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			/* Advance the SKB... */
836ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			skb_pull(skb, bytes);
837ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
838f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			/* Encryption routine will move the header forward in
839f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			 * order to insert the IV between the header and the
840f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			 * payload */
841ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			if (encrypt)
842f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				rtllib_encrypt_fragment(ieee, skb_frag,
843f38d223b692742e77c70033d145245615c8f3aa5Larry Finger							hdr_len);
844ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			if (ieee->config &
845f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			   (CFG_RTLLIB_COMPUTE_FCS | CFG_RTLLIB_RESERVE_FCS))
846ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				skb_put(skb_frag, 4);
847ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
848ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
84994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		if ((qos_actived) && (!bIsMulticast)) {
850f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (ieee->seq_ctrl[UP2AC(skb->priority) + 1] == 0xFFF)
851f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				ieee->seq_ctrl[UP2AC(skb->priority) + 1] = 0;
852f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			else
853f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				ieee->seq_ctrl[UP2AC(skb->priority) + 1]++;
854ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		} else {
855f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (ieee->seq_ctrl[0] == 0xFFF)
856f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				ieee->seq_ctrl[0] = 0;
857f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			else
858f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					ieee->seq_ctrl[0]++;
859ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
860f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	} else {
86194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		if (unlikely(skb->len < sizeof(struct rtllib_hdr_3addr))) {
862ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			printk(KERN_WARNING "%s: skb too small (%d).\n",
863ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			ieee->dev->name, skb->len);
864ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			goto success;
865ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
866ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
86794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		txb = rtllib_alloc_txb(1, skb->len, GFP_ATOMIC);
868f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		if (!txb) {
869ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			printk(KERN_WARNING "%s: Could not allocate TXB\n",
870ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			ieee->dev->name);
871ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			goto failed;
872ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
873ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
874ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		txb->encrypted = 0;
875ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		txb->payload_size = skb->len;
876f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		memcpy(skb_put(txb->fragments[0], skb->len), skb->data,
877f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		       skb->len);
878ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
879ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
880ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman success:
881f38d223b692742e77c70033d145245615c8f3aa5Larry Finger	if (txb) {
882f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		struct cb_desc *tcb_desc = (struct cb_desc *)
883f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				(txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE);
884ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		tcb_desc->bTxEnableFwCalcDur = 1;
88594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		tcb_desc->priority = skb->priority;
88665a4378471510787e080188f933913315f1afa0cdavid woo
88794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		if (ether_type == ETH_P_PAE) {
888f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (ieee->pHTInfo->IOTAction &
889f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			    HT_IOT_ACT_WA_IOT_Broadcom) {
890f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				tcb_desc->data_rate =
891f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					 MgntQuery_TxRateExcludeCCKRates(ieee);
89294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->bTxDisableRateFallBack = false;
893f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			} else {
89494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->data_rate = ieee->basic_rate;
89565a4378471510787e080188f933913315f1afa0cdavid woo				tcb_desc->bTxDisableRateFallBack = 1;
89694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			}
89794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger
89865a4378471510787e080188f933913315f1afa0cdavid woo
89965a4378471510787e080188f933913315f1afa0cdavid woo			tcb_desc->RATRIndex = 7;
90065a4378471510787e080188f933913315f1afa0cdavid woo			tcb_desc->bTxUseDriverAssingedRate = 1;
90194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		} else {
90294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			if (is_multicast_ether_addr(header.addr1))
90394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->bMulticast = 1;
90494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			if (is_broadcast_ether_addr(header.addr1))
90594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->bBroadcast = 1;
90694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			rtllib_txrate_selectmode(ieee, tcb_desc);
907f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (tcb_desc->bMulticast ||  tcb_desc->bBroadcast)
90894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->data_rate = ieee->basic_rate;
90994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			else
910f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				tcb_desc->data_rate = CURRENT_RATE(ieee->mode,
911f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					ieee->rate, ieee->HTCurrentOperaRate);
912f38d223b692742e77c70033d145245615c8f3aa5Larry Finger
913f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			if (bdhcp == true) {
914f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				if (ieee->pHTInfo->IOTAction &
915f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				    HT_IOT_ACT_WA_IOT_Broadcom) {
916f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					tcb_desc->data_rate =
917f38d223b692742e77c70033d145245615c8f3aa5Larry Finger					   MgntQuery_TxRateExcludeCCKRates(ieee);
91894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger					tcb_desc->bTxDisableRateFallBack = false;
919f38d223b692742e77c70033d145245615c8f3aa5Larry Finger				} else {
92094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger					tcb_desc->data_rate = MGN_1M;
92194a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger					tcb_desc->bTxDisableRateFallBack = 1;
92294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				}
92365a4378471510787e080188f933913315f1afa0cdavid woo
92465a4378471510787e080188f933913315f1afa0cdavid woo
92594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->RATRIndex = 7;
92694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->bTxUseDriverAssingedRate = 1;
92794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger				tcb_desc->bdhcp = 1;
92894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			}
92994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger
93094a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			rtllib_qurey_ShortPreambleMode(ieee, tcb_desc);
931f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			rtllib_tx_query_agg_cap(ieee, txb->fragments[0],
932f38d223b692742e77c70033d145245615c8f3aa5Larry Finger						tcb_desc);
93394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			rtllib_query_HTCapShortGI(ieee, tcb_desc);
93494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			rtllib_query_BandwidthMode(ieee, tcb_desc);
935f38d223b692742e77c70033d145245615c8f3aa5Larry Finger			rtllib_query_protectionmode(ieee, tcb_desc,
936f38d223b692742e77c70033d145245615c8f3aa5Larry Finger						    txb->fragments[0]);
93794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger		}
938ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
939ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	spin_unlock_irqrestore(&ieee->lock, flags);
940ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	dev_kfree_skb_any(skb);
941ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	if (txb) {
942f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) {
94394a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			dev->stats.tx_packets++;
94494a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			dev->stats.tx_bytes += txb->payload_size;
94594a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			rtllib_softmac_xmit(txb, ieee);
946f38d223b692742e77c70033d145245615c8f3aa5Larry Finger		} else {
94794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			if ((*ieee->hard_start_xmit)(txb, dev) == 0) {
948ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				stats->tx_packets++;
949ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				stats->tx_bytes += txb->payload_size;
950ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman				return 0;
951ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman			}
95294a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger			rtllib_txb_free(txb);
953ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman		}
954ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	}
955ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
956ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return 0;
957ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
958ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman failed:
959ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	spin_unlock_irqrestore(&ieee->lock, flags);
960ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	netif_stop_queue(dev);
961ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	stats->tx_errors++;
962ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman	return 1;
963ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman
964ecdfa44610fa18678c3dd481af75368b9800c6c7Greg Kroah-Hartman}
96594a799425eee8225a1e3fbe5f473d2ef04002577Larry Fingerint rtllib_xmit(struct sk_buff *skb, struct net_device *dev)
96694a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger{
96794a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	memset(skb->cb, 0, sizeof(skb->cb));
96894a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger	return rtllib_xmit_inter(skb, dev);
96994a799425eee8225a1e3fbe5f473d2ef04002577Larry Finger}
9703b28499c5519e59fbe9c2dea49ece5a3665be787Sean MacLennanEXPORT_SYMBOL(rtllib_xmit);
971