1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2eb4f98d5SKalle Valo #include <linux/slab.h>
3eb4f98d5SKalle Valo #include <linux/export.h>
4eb4f98d5SKalle Valo #include <linux/etherdevice.h>
5eb4f98d5SKalle Valo
6eb4f98d5SKalle Valo #include "hostap_80211.h"
7eb4f98d5SKalle Valo #include "hostap_common.h"
8eb4f98d5SKalle Valo #include "hostap_wlan.h"
9eb4f98d5SKalle Valo #include "hostap.h"
10eb4f98d5SKalle Valo #include "hostap_ap.h"
11eb4f98d5SKalle Valo
12eb4f98d5SKalle Valo /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
13eb4f98d5SKalle Valo /* Ethernet-II snap header (RFC1042 for most EtherTypes) */
14eb4f98d5SKalle Valo static unsigned char rfc1042_header[] =
15eb4f98d5SKalle Valo { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
16eb4f98d5SKalle Valo /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
17eb4f98d5SKalle Valo static unsigned char bridge_tunnel_header[] =
18eb4f98d5SKalle Valo { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
19eb4f98d5SKalle Valo /* No encapsulation header if EtherType < 0x600 (=length) */
20eb4f98d5SKalle Valo
hostap_dump_tx_80211(const char * name,struct sk_buff * skb)21eb4f98d5SKalle Valo void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
22eb4f98d5SKalle Valo {
23eb4f98d5SKalle Valo struct ieee80211_hdr *hdr;
24eb4f98d5SKalle Valo u16 fc;
25eb4f98d5SKalle Valo
26eb4f98d5SKalle Valo hdr = (struct ieee80211_hdr *) skb->data;
27eb4f98d5SKalle Valo
28eb4f98d5SKalle Valo printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n",
29eb4f98d5SKalle Valo name, skb->len, jiffies);
30eb4f98d5SKalle Valo
31eb4f98d5SKalle Valo if (skb->len < 2)
32eb4f98d5SKalle Valo return;
33eb4f98d5SKalle Valo
34eb4f98d5SKalle Valo fc = le16_to_cpu(hdr->frame_control);
35eb4f98d5SKalle Valo printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s",
36eb4f98d5SKalle Valo fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
37eb4f98d5SKalle Valo (fc & IEEE80211_FCTL_STYPE) >> 4,
38eb4f98d5SKalle Valo fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
39eb4f98d5SKalle Valo fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
40eb4f98d5SKalle Valo
41eb4f98d5SKalle Valo if (skb->len < IEEE80211_DATA_HDR3_LEN) {
42eb4f98d5SKalle Valo printk("\n");
43eb4f98d5SKalle Valo return;
44eb4f98d5SKalle Valo }
45eb4f98d5SKalle Valo
46eb4f98d5SKalle Valo printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
47eb4f98d5SKalle Valo le16_to_cpu(hdr->seq_ctrl));
48eb4f98d5SKalle Valo
49eb4f98d5SKalle Valo printk(KERN_DEBUG " A1=%pM", hdr->addr1);
50eb4f98d5SKalle Valo printk(" A2=%pM", hdr->addr2);
51eb4f98d5SKalle Valo printk(" A3=%pM", hdr->addr3);
52eb4f98d5SKalle Valo if (skb->len >= 30)
53eb4f98d5SKalle Valo printk(" A4=%pM", hdr->addr4);
54eb4f98d5SKalle Valo printk("\n");
55eb4f98d5SKalle Valo }
56eb4f98d5SKalle Valo
57eb4f98d5SKalle Valo
58eb4f98d5SKalle Valo /* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta)
59eb4f98d5SKalle Valo * Convert Ethernet header into a suitable IEEE 802.11 header depending on
60eb4f98d5SKalle Valo * device configuration. */
hostap_data_start_xmit(struct sk_buff * skb,struct net_device * dev)61eb4f98d5SKalle Valo netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb,
62eb4f98d5SKalle Valo struct net_device *dev)
63eb4f98d5SKalle Valo {
64eb4f98d5SKalle Valo struct hostap_interface *iface;
65eb4f98d5SKalle Valo local_info_t *local;
66eb4f98d5SKalle Valo int need_headroom, need_tailroom = 0;
67eb4f98d5SKalle Valo struct ieee80211_hdr hdr;
68eb4f98d5SKalle Valo u16 fc, ethertype = 0;
69eb4f98d5SKalle Valo enum {
70eb4f98d5SKalle Valo WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME
71eb4f98d5SKalle Valo } use_wds = WDS_NO;
72eb4f98d5SKalle Valo u8 *encaps_data;
73eb4f98d5SKalle Valo int hdr_len, encaps_len, skip_header_bytes;
74eb4f98d5SKalle Valo int to_assoc_ap = 0;
75eb4f98d5SKalle Valo struct hostap_skb_tx_data *meta;
76eb4f98d5SKalle Valo
77eb4f98d5SKalle Valo iface = netdev_priv(dev);
78eb4f98d5SKalle Valo local = iface->local;
79eb4f98d5SKalle Valo
80eb4f98d5SKalle Valo if (skb->len < ETH_HLEN) {
81eb4f98d5SKalle Valo printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb "
82eb4f98d5SKalle Valo "(len=%d)\n", dev->name, skb->len);
83eb4f98d5SKalle Valo kfree_skb(skb);
84eb4f98d5SKalle Valo return NETDEV_TX_OK;
85eb4f98d5SKalle Valo }
86eb4f98d5SKalle Valo
87eb4f98d5SKalle Valo if (local->ddev != dev) {
88eb4f98d5SKalle Valo use_wds = (local->iw_mode == IW_MODE_MASTER &&
89eb4f98d5SKalle Valo !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ?
90eb4f98d5SKalle Valo WDS_OWN_FRAME : WDS_COMPLIANT_FRAME;
91eb4f98d5SKalle Valo if (dev == local->stadev) {
92eb4f98d5SKalle Valo to_assoc_ap = 1;
93eb4f98d5SKalle Valo use_wds = WDS_NO;
94eb4f98d5SKalle Valo } else if (dev == local->apdev) {
95eb4f98d5SKalle Valo printk(KERN_DEBUG "%s: prism2_tx: trying to use "
96eb4f98d5SKalle Valo "AP device with Ethernet net dev\n", dev->name);
97eb4f98d5SKalle Valo kfree_skb(skb);
98eb4f98d5SKalle Valo return NETDEV_TX_OK;
99eb4f98d5SKalle Valo }
100eb4f98d5SKalle Valo } else {
101eb4f98d5SKalle Valo if (local->iw_mode == IW_MODE_REPEAT) {
102eb4f98d5SKalle Valo printk(KERN_DEBUG "%s: prism2_tx: trying to use "
103eb4f98d5SKalle Valo "non-WDS link in Repeater mode\n", dev->name);
104eb4f98d5SKalle Valo kfree_skb(skb);
105eb4f98d5SKalle Valo return NETDEV_TX_OK;
106eb4f98d5SKalle Valo } else if (local->iw_mode == IW_MODE_INFRA &&
107eb4f98d5SKalle Valo (local->wds_type & HOSTAP_WDS_AP_CLIENT) &&
108eb4f98d5SKalle Valo !ether_addr_equal(skb->data + ETH_ALEN, dev->dev_addr)) {
109eb4f98d5SKalle Valo /* AP client mode: send frames with foreign src addr
110eb4f98d5SKalle Valo * using 4-addr WDS frames */
111eb4f98d5SKalle Valo use_wds = WDS_COMPLIANT_FRAME;
112eb4f98d5SKalle Valo }
113eb4f98d5SKalle Valo }
114eb4f98d5SKalle Valo
115eb4f98d5SKalle Valo /* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload
116eb4f98d5SKalle Valo * ==>
117eb4f98d5SKalle Valo * Prism2 TX frame with 802.11 header:
118eb4f98d5SKalle Valo * txdesc (address order depending on used mode; includes dst_addr and
119eb4f98d5SKalle Valo * src_addr), possible encapsulation (RFC1042/Bridge-Tunnel;
120eb4f98d5SKalle Valo * proto[2], payload {, possible addr4[6]} */
121eb4f98d5SKalle Valo
122eb4f98d5SKalle Valo ethertype = (skb->data[12] << 8) | skb->data[13];
123eb4f98d5SKalle Valo
124eb4f98d5SKalle Valo memset(&hdr, 0, sizeof(hdr));
125eb4f98d5SKalle Valo
126eb4f98d5SKalle Valo /* Length of data after IEEE 802.11 header */
127eb4f98d5SKalle Valo encaps_data = NULL;
128eb4f98d5SKalle Valo encaps_len = 0;
129eb4f98d5SKalle Valo skip_header_bytes = ETH_HLEN;
130eb4f98d5SKalle Valo if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
131eb4f98d5SKalle Valo encaps_data = bridge_tunnel_header;
132eb4f98d5SKalle Valo encaps_len = sizeof(bridge_tunnel_header);
133eb4f98d5SKalle Valo skip_header_bytes -= 2;
134eb4f98d5SKalle Valo } else if (ethertype >= 0x600) {
135eb4f98d5SKalle Valo encaps_data = rfc1042_header;
136eb4f98d5SKalle Valo encaps_len = sizeof(rfc1042_header);
137eb4f98d5SKalle Valo skip_header_bytes -= 2;
138eb4f98d5SKalle Valo }
139eb4f98d5SKalle Valo
140eb4f98d5SKalle Valo fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
141eb4f98d5SKalle Valo hdr_len = IEEE80211_DATA_HDR3_LEN;
142eb4f98d5SKalle Valo
143eb4f98d5SKalle Valo if (use_wds != WDS_NO) {
144eb4f98d5SKalle Valo /* Note! Prism2 station firmware has problems with sending real
145eb4f98d5SKalle Valo * 802.11 frames with four addresses; until these problems can
146eb4f98d5SKalle Valo * be fixed or worked around, 4-addr frames needed for WDS are
147eb4f98d5SKalle Valo * using incompatible format: FromDS flag is not set and the
148eb4f98d5SKalle Valo * fourth address is added after the frame payload; it is
149eb4f98d5SKalle Valo * assumed, that the receiving station knows how to handle this
150eb4f98d5SKalle Valo * frame format */
151eb4f98d5SKalle Valo
152eb4f98d5SKalle Valo if (use_wds == WDS_COMPLIANT_FRAME) {
153eb4f98d5SKalle Valo fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
154eb4f98d5SKalle Valo /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA,
155eb4f98d5SKalle Valo * Addr4 = SA */
156eb4f98d5SKalle Valo skb_copy_from_linear_data_offset(skb, ETH_ALEN,
157eb4f98d5SKalle Valo &hdr.addr4, ETH_ALEN);
158eb4f98d5SKalle Valo hdr_len += ETH_ALEN;
159eb4f98d5SKalle Valo } else {
160eb4f98d5SKalle Valo /* bogus 4-addr format to workaround Prism2 station
161eb4f98d5SKalle Valo * f/w bug */
162eb4f98d5SKalle Valo fc |= IEEE80211_FCTL_TODS;
163eb4f98d5SKalle Valo /* From DS: Addr1 = DA (used as RA),
164eb4f98d5SKalle Valo * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA),
165eb4f98d5SKalle Valo */
166eb4f98d5SKalle Valo
167eb4f98d5SKalle Valo /* SA from skb->data + ETH_ALEN will be added after
168eb4f98d5SKalle Valo * frame payload; use hdr.addr4 as a temporary buffer
169eb4f98d5SKalle Valo */
170eb4f98d5SKalle Valo skb_copy_from_linear_data_offset(skb, ETH_ALEN,
171eb4f98d5SKalle Valo &hdr.addr4, ETH_ALEN);
172eb4f98d5SKalle Valo need_tailroom += ETH_ALEN;
173eb4f98d5SKalle Valo }
174eb4f98d5SKalle Valo
175eb4f98d5SKalle Valo /* send broadcast and multicast frames to broadcast RA, if
176eb4f98d5SKalle Valo * configured; otherwise, use unicast RA of the WDS link */
177eb4f98d5SKalle Valo if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) &&
178eb4f98d5SKalle Valo is_multicast_ether_addr(skb->data))
179eb4f98d5SKalle Valo eth_broadcast_addr(hdr.addr1);
180eb4f98d5SKalle Valo else if (iface->type == HOSTAP_INTERFACE_WDS)
181eb4f98d5SKalle Valo memcpy(&hdr.addr1, iface->u.wds.remote_addr,
182eb4f98d5SKalle Valo ETH_ALEN);
183eb4f98d5SKalle Valo else
184eb4f98d5SKalle Valo memcpy(&hdr.addr1, local->bssid, ETH_ALEN);
185eb4f98d5SKalle Valo memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
186eb4f98d5SKalle Valo skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN);
187eb4f98d5SKalle Valo } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) {
188eb4f98d5SKalle Valo fc |= IEEE80211_FCTL_FROMDS;
189eb4f98d5SKalle Valo /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */
190eb4f98d5SKalle Valo skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN);
191eb4f98d5SKalle Valo memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
192eb4f98d5SKalle Valo skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr3,
193eb4f98d5SKalle Valo ETH_ALEN);
194eb4f98d5SKalle Valo } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) {
195eb4f98d5SKalle Valo fc |= IEEE80211_FCTL_TODS;
196eb4f98d5SKalle Valo /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
197eb4f98d5SKalle Valo memcpy(&hdr.addr1, to_assoc_ap ?
198eb4f98d5SKalle Valo local->assoc_ap_addr : local->bssid, ETH_ALEN);
199eb4f98d5SKalle Valo skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2,
200eb4f98d5SKalle Valo ETH_ALEN);
201eb4f98d5SKalle Valo skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN);
202eb4f98d5SKalle Valo } else if (local->iw_mode == IW_MODE_ADHOC) {
203eb4f98d5SKalle Valo /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
204eb4f98d5SKalle Valo skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN);
205eb4f98d5SKalle Valo skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2,
206eb4f98d5SKalle Valo ETH_ALEN);
207eb4f98d5SKalle Valo memcpy(&hdr.addr3, local->bssid, ETH_ALEN);
208eb4f98d5SKalle Valo }
209eb4f98d5SKalle Valo
210eb4f98d5SKalle Valo hdr.frame_control = cpu_to_le16(fc);
211eb4f98d5SKalle Valo
212eb4f98d5SKalle Valo skb_pull(skb, skip_header_bytes);
213eb4f98d5SKalle Valo need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len;
214eb4f98d5SKalle Valo if (skb_tailroom(skb) < need_tailroom) {
215eb4f98d5SKalle Valo skb = skb_unshare(skb, GFP_ATOMIC);
216eb4f98d5SKalle Valo if (skb == NULL) {
217eb4f98d5SKalle Valo iface->stats.tx_dropped++;
218eb4f98d5SKalle Valo return NETDEV_TX_OK;
219eb4f98d5SKalle Valo }
220eb4f98d5SKalle Valo if (pskb_expand_head(skb, need_headroom, need_tailroom,
221eb4f98d5SKalle Valo GFP_ATOMIC)) {
222eb4f98d5SKalle Valo kfree_skb(skb);
223eb4f98d5SKalle Valo iface->stats.tx_dropped++;
224eb4f98d5SKalle Valo return NETDEV_TX_OK;
225eb4f98d5SKalle Valo }
226eb4f98d5SKalle Valo } else if (skb_headroom(skb) < need_headroom) {
227eb4f98d5SKalle Valo struct sk_buff *tmp = skb;
228eb4f98d5SKalle Valo skb = skb_realloc_headroom(skb, need_headroom);
229eb4f98d5SKalle Valo kfree_skb(tmp);
230eb4f98d5SKalle Valo if (skb == NULL) {
231eb4f98d5SKalle Valo iface->stats.tx_dropped++;
232eb4f98d5SKalle Valo return NETDEV_TX_OK;
233eb4f98d5SKalle Valo }
234eb4f98d5SKalle Valo } else {
235eb4f98d5SKalle Valo skb = skb_unshare(skb, GFP_ATOMIC);
236eb4f98d5SKalle Valo if (skb == NULL) {
237eb4f98d5SKalle Valo iface->stats.tx_dropped++;
238eb4f98d5SKalle Valo return NETDEV_TX_OK;
239eb4f98d5SKalle Valo }
240eb4f98d5SKalle Valo }
241eb4f98d5SKalle Valo
242eb4f98d5SKalle Valo if (encaps_data)
243eb4f98d5SKalle Valo memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
244eb4f98d5SKalle Valo memcpy(skb_push(skb, hdr_len), &hdr, hdr_len);
245eb4f98d5SKalle Valo if (use_wds == WDS_OWN_FRAME) {
24659ae1d12SJohannes Berg skb_put_data(skb, &hdr.addr4, ETH_ALEN);
247eb4f98d5SKalle Valo }
248eb4f98d5SKalle Valo
249eb4f98d5SKalle Valo iface->stats.tx_packets++;
250eb4f98d5SKalle Valo iface->stats.tx_bytes += skb->len;
251eb4f98d5SKalle Valo
252eb4f98d5SKalle Valo skb_reset_mac_header(skb);
253eb4f98d5SKalle Valo meta = (struct hostap_skb_tx_data *) skb->cb;
254eb4f98d5SKalle Valo memset(meta, 0, sizeof(*meta));
255eb4f98d5SKalle Valo meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
256eb4f98d5SKalle Valo if (use_wds)
257eb4f98d5SKalle Valo meta->flags |= HOSTAP_TX_FLAGS_WDS;
258eb4f98d5SKalle Valo meta->ethertype = ethertype;
259eb4f98d5SKalle Valo meta->iface = iface;
260eb4f98d5SKalle Valo
261eb4f98d5SKalle Valo /* Send IEEE 802.11 encapsulated frame using the master radio device */
262eb4f98d5SKalle Valo skb->dev = local->dev;
263eb4f98d5SKalle Valo dev_queue_xmit(skb);
264eb4f98d5SKalle Valo return NETDEV_TX_OK;
265eb4f98d5SKalle Valo }
266eb4f98d5SKalle Valo
267eb4f98d5SKalle Valo
268eb4f98d5SKalle Valo /* hard_start_xmit function for hostapd wlan#ap interfaces */
hostap_mgmt_start_xmit(struct sk_buff * skb,struct net_device * dev)269eb4f98d5SKalle Valo netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb,
270eb4f98d5SKalle Valo struct net_device *dev)
271eb4f98d5SKalle Valo {
272eb4f98d5SKalle Valo struct hostap_interface *iface;
273eb4f98d5SKalle Valo local_info_t *local;
274eb4f98d5SKalle Valo struct hostap_skb_tx_data *meta;
275eb4f98d5SKalle Valo struct ieee80211_hdr *hdr;
276eb4f98d5SKalle Valo u16 fc;
277eb4f98d5SKalle Valo
278eb4f98d5SKalle Valo iface = netdev_priv(dev);
279eb4f98d5SKalle Valo local = iface->local;
280eb4f98d5SKalle Valo
281eb4f98d5SKalle Valo if (skb->len < 10) {
282eb4f98d5SKalle Valo printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb "
283eb4f98d5SKalle Valo "(len=%d)\n", dev->name, skb->len);
284eb4f98d5SKalle Valo kfree_skb(skb);
285eb4f98d5SKalle Valo return NETDEV_TX_OK;
286eb4f98d5SKalle Valo }
287eb4f98d5SKalle Valo
288eb4f98d5SKalle Valo iface->stats.tx_packets++;
289eb4f98d5SKalle Valo iface->stats.tx_bytes += skb->len;
290eb4f98d5SKalle Valo
291eb4f98d5SKalle Valo meta = (struct hostap_skb_tx_data *) skb->cb;
292eb4f98d5SKalle Valo memset(meta, 0, sizeof(*meta));
293eb4f98d5SKalle Valo meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
294eb4f98d5SKalle Valo meta->iface = iface;
295eb4f98d5SKalle Valo
296eb4f98d5SKalle Valo if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) {
297eb4f98d5SKalle Valo hdr = (struct ieee80211_hdr *) skb->data;
298eb4f98d5SKalle Valo fc = le16_to_cpu(hdr->frame_control);
299eb4f98d5SKalle Valo if (ieee80211_is_data(hdr->frame_control) &&
300eb4f98d5SKalle Valo (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DATA) {
301eb4f98d5SKalle Valo u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN +
302eb4f98d5SKalle Valo sizeof(rfc1042_header)];
303eb4f98d5SKalle Valo meta->ethertype = (pos[0] << 8) | pos[1];
304eb4f98d5SKalle Valo }
305eb4f98d5SKalle Valo }
306eb4f98d5SKalle Valo
307eb4f98d5SKalle Valo /* Send IEEE 802.11 encapsulated frame using the master radio device */
308eb4f98d5SKalle Valo skb->dev = local->dev;
309eb4f98d5SKalle Valo dev_queue_xmit(skb);
310eb4f98d5SKalle Valo return NETDEV_TX_OK;
311eb4f98d5SKalle Valo }
312eb4f98d5SKalle Valo
313eb4f98d5SKalle Valo
314eb4f98d5SKalle Valo /* Called only from software IRQ */
hostap_tx_encrypt(struct sk_buff * skb,struct lib80211_crypt_data * crypt)315eb4f98d5SKalle Valo static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
316eb4f98d5SKalle Valo struct lib80211_crypt_data *crypt)
317eb4f98d5SKalle Valo {
318eb4f98d5SKalle Valo struct hostap_interface *iface;
319eb4f98d5SKalle Valo local_info_t *local;
320eb4f98d5SKalle Valo struct ieee80211_hdr *hdr;
321eb4f98d5SKalle Valo int prefix_len, postfix_len, hdr_len, res;
322eb4f98d5SKalle Valo
323eb4f98d5SKalle Valo iface = netdev_priv(skb->dev);
324eb4f98d5SKalle Valo local = iface->local;
325eb4f98d5SKalle Valo
326eb4f98d5SKalle Valo if (skb->len < IEEE80211_DATA_HDR3_LEN) {
327eb4f98d5SKalle Valo kfree_skb(skb);
328eb4f98d5SKalle Valo return NULL;
329eb4f98d5SKalle Valo }
330eb4f98d5SKalle Valo
331eb4f98d5SKalle Valo if (local->tkip_countermeasures &&
332eb4f98d5SKalle Valo strcmp(crypt->ops->name, "TKIP") == 0) {
333eb4f98d5SKalle Valo hdr = (struct ieee80211_hdr *) skb->data;
334eb4f98d5SKalle Valo if (net_ratelimit()) {
335eb4f98d5SKalle Valo printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
336eb4f98d5SKalle Valo "TX packet to %pM\n",
337eb4f98d5SKalle Valo local->dev->name, hdr->addr1);
338eb4f98d5SKalle Valo }
339eb4f98d5SKalle Valo kfree_skb(skb);
340eb4f98d5SKalle Valo return NULL;
341eb4f98d5SKalle Valo }
342eb4f98d5SKalle Valo
343eb4f98d5SKalle Valo skb = skb_unshare(skb, GFP_ATOMIC);
344eb4f98d5SKalle Valo if (skb == NULL)
345eb4f98d5SKalle Valo return NULL;
346eb4f98d5SKalle Valo
347eb4f98d5SKalle Valo prefix_len = crypt->ops->extra_mpdu_prefix_len +
348eb4f98d5SKalle Valo crypt->ops->extra_msdu_prefix_len;
349eb4f98d5SKalle Valo postfix_len = crypt->ops->extra_mpdu_postfix_len +
350eb4f98d5SKalle Valo crypt->ops->extra_msdu_postfix_len;
351eb4f98d5SKalle Valo if ((skb_headroom(skb) < prefix_len ||
352eb4f98d5SKalle Valo skb_tailroom(skb) < postfix_len) &&
353eb4f98d5SKalle Valo pskb_expand_head(skb, prefix_len, postfix_len, GFP_ATOMIC)) {
354eb4f98d5SKalle Valo kfree_skb(skb);
355eb4f98d5SKalle Valo return NULL;
356eb4f98d5SKalle Valo }
357eb4f98d5SKalle Valo
358eb4f98d5SKalle Valo hdr = (struct ieee80211_hdr *) skb->data;
359eb4f98d5SKalle Valo hdr_len = hostap_80211_get_hdrlen(hdr->frame_control);
360eb4f98d5SKalle Valo
361eb4f98d5SKalle Valo /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
362eb4f98d5SKalle Valo * call both MSDU and MPDU encryption functions from here. */
363eb4f98d5SKalle Valo atomic_inc(&crypt->refcnt);
364eb4f98d5SKalle Valo res = 0;
365eb4f98d5SKalle Valo if (crypt->ops->encrypt_msdu)
366eb4f98d5SKalle Valo res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv);
367eb4f98d5SKalle Valo if (res == 0 && crypt->ops->encrypt_mpdu)
368eb4f98d5SKalle Valo res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv);
369eb4f98d5SKalle Valo atomic_dec(&crypt->refcnt);
370eb4f98d5SKalle Valo if (res < 0) {
371eb4f98d5SKalle Valo kfree_skb(skb);
372eb4f98d5SKalle Valo return NULL;
373eb4f98d5SKalle Valo }
374eb4f98d5SKalle Valo
375eb4f98d5SKalle Valo return skb;
376eb4f98d5SKalle Valo }
377eb4f98d5SKalle Valo
378eb4f98d5SKalle Valo
379eb4f98d5SKalle Valo /* hard_start_xmit function for master radio interface wifi#.
380eb4f98d5SKalle Valo * AP processing (TX rate control, power save buffering, etc.).
381eb4f98d5SKalle Valo * Use hardware TX function to send the frame. */
hostap_master_start_xmit(struct sk_buff * skb,struct net_device * dev)382eb4f98d5SKalle Valo netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb,
383eb4f98d5SKalle Valo struct net_device *dev)
384eb4f98d5SKalle Valo {
385eb4f98d5SKalle Valo struct hostap_interface *iface;
386eb4f98d5SKalle Valo local_info_t *local;
387eb4f98d5SKalle Valo netdev_tx_t ret = NETDEV_TX_BUSY;
388eb4f98d5SKalle Valo u16 fc;
389eb4f98d5SKalle Valo struct hostap_tx_data tx;
390eb4f98d5SKalle Valo ap_tx_ret tx_ret;
391eb4f98d5SKalle Valo struct hostap_skb_tx_data *meta;
392eb4f98d5SKalle Valo int no_encrypt = 0;
393eb4f98d5SKalle Valo struct ieee80211_hdr *hdr;
394eb4f98d5SKalle Valo
395eb4f98d5SKalle Valo iface = netdev_priv(dev);
396eb4f98d5SKalle Valo local = iface->local;
397eb4f98d5SKalle Valo
398eb4f98d5SKalle Valo tx.skb = skb;
399eb4f98d5SKalle Valo tx.sta_ptr = NULL;
400eb4f98d5SKalle Valo
401eb4f98d5SKalle Valo meta = (struct hostap_skb_tx_data *) skb->cb;
402eb4f98d5SKalle Valo if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {
403eb4f98d5SKalle Valo printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
404eb4f98d5SKalle Valo "expected 0x%08x)\n",
405eb4f98d5SKalle Valo dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC);
406eb4f98d5SKalle Valo ret = NETDEV_TX_OK;
407eb4f98d5SKalle Valo iface->stats.tx_dropped++;
408eb4f98d5SKalle Valo goto fail;
409eb4f98d5SKalle Valo }
410eb4f98d5SKalle Valo
411eb4f98d5SKalle Valo if (local->host_encrypt) {
412eb4f98d5SKalle Valo /* Set crypt to default algorithm and key; will be replaced in
413eb4f98d5SKalle Valo * AP code if STA has own alg/key */
414eb4f98d5SKalle Valo tx.crypt = local->crypt_info.crypt[local->crypt_info.tx_keyidx];
415eb4f98d5SKalle Valo tx.host_encrypt = 1;
416eb4f98d5SKalle Valo } else {
417eb4f98d5SKalle Valo tx.crypt = NULL;
418eb4f98d5SKalle Valo tx.host_encrypt = 0;
419eb4f98d5SKalle Valo }
420eb4f98d5SKalle Valo
421eb4f98d5SKalle Valo if (skb->len < 24) {
422eb4f98d5SKalle Valo printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb "
423eb4f98d5SKalle Valo "(len=%d)\n", dev->name, skb->len);
424eb4f98d5SKalle Valo ret = NETDEV_TX_OK;
425eb4f98d5SKalle Valo iface->stats.tx_dropped++;
426eb4f98d5SKalle Valo goto fail;
427eb4f98d5SKalle Valo }
428eb4f98d5SKalle Valo
429eb4f98d5SKalle Valo /* FIX (?):
430eb4f98d5SKalle Valo * Wi-Fi 802.11b test plan suggests that AP should ignore power save
431eb4f98d5SKalle Valo * bit in authentication and (re)association frames and assume tha
432eb4f98d5SKalle Valo * STA remains awake for the response. */
433eb4f98d5SKalle Valo tx_ret = hostap_handle_sta_tx(local, &tx);
434eb4f98d5SKalle Valo skb = tx.skb;
435eb4f98d5SKalle Valo meta = (struct hostap_skb_tx_data *) skb->cb;
436eb4f98d5SKalle Valo hdr = (struct ieee80211_hdr *) skb->data;
437eb4f98d5SKalle Valo fc = le16_to_cpu(hdr->frame_control);
438eb4f98d5SKalle Valo switch (tx_ret) {
439eb4f98d5SKalle Valo case AP_TX_CONTINUE:
440eb4f98d5SKalle Valo break;
441eb4f98d5SKalle Valo case AP_TX_CONTINUE_NOT_AUTHORIZED:
442eb4f98d5SKalle Valo if (local->ieee_802_1x &&
443eb4f98d5SKalle Valo ieee80211_is_data(hdr->frame_control) &&
444eb4f98d5SKalle Valo meta->ethertype != ETH_P_PAE &&
445eb4f98d5SKalle Valo !(meta->flags & HOSTAP_TX_FLAGS_WDS)) {
446eb4f98d5SKalle Valo printk(KERN_DEBUG "%s: dropped frame to unauthorized "
447eb4f98d5SKalle Valo "port (IEEE 802.1X): ethertype=0x%04x\n",
448eb4f98d5SKalle Valo dev->name, meta->ethertype);
449eb4f98d5SKalle Valo hostap_dump_tx_80211(dev->name, skb);
450eb4f98d5SKalle Valo
451eb4f98d5SKalle Valo ret = NETDEV_TX_OK; /* drop packet */
452eb4f98d5SKalle Valo iface->stats.tx_dropped++;
453eb4f98d5SKalle Valo goto fail;
454eb4f98d5SKalle Valo }
455eb4f98d5SKalle Valo break;
456eb4f98d5SKalle Valo case AP_TX_DROP:
457eb4f98d5SKalle Valo ret = NETDEV_TX_OK; /* drop packet */
458eb4f98d5SKalle Valo iface->stats.tx_dropped++;
459eb4f98d5SKalle Valo goto fail;
460eb4f98d5SKalle Valo case AP_TX_RETRY:
461eb4f98d5SKalle Valo goto fail;
462eb4f98d5SKalle Valo case AP_TX_BUFFERED:
463eb4f98d5SKalle Valo /* do not free skb here, it will be freed when the
464eb4f98d5SKalle Valo * buffered frame is sent/timed out */
465eb4f98d5SKalle Valo ret = NETDEV_TX_OK;
466eb4f98d5SKalle Valo goto tx_exit;
467eb4f98d5SKalle Valo }
468eb4f98d5SKalle Valo
469eb4f98d5SKalle Valo /* Request TX callback if protocol version is 2 in 802.11 header;
470eb4f98d5SKalle Valo * this version 2 is a special case used between hostapd and kernel
471eb4f98d5SKalle Valo * driver */
472eb4f98d5SKalle Valo if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) &&
473eb4f98d5SKalle Valo local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) {
474eb4f98d5SKalle Valo meta->tx_cb_idx = local->ap->tx_callback_idx;
475eb4f98d5SKalle Valo
476eb4f98d5SKalle Valo /* remove special version from the frame header */
477eb4f98d5SKalle Valo fc &= ~IEEE80211_FCTL_VERS;
478eb4f98d5SKalle Valo hdr->frame_control = cpu_to_le16(fc);
479eb4f98d5SKalle Valo }
480eb4f98d5SKalle Valo
481eb4f98d5SKalle Valo if (!ieee80211_is_data(hdr->frame_control)) {
482eb4f98d5SKalle Valo no_encrypt = 1;
483eb4f98d5SKalle Valo tx.crypt = NULL;
484eb4f98d5SKalle Valo }
485eb4f98d5SKalle Valo
486eb4f98d5SKalle Valo if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt &&
487eb4f98d5SKalle Valo !(fc & IEEE80211_FCTL_PROTECTED)) {
488eb4f98d5SKalle Valo no_encrypt = 1;
489eb4f98d5SKalle Valo PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing "
490eb4f98d5SKalle Valo "unencrypted EAPOL frame\n", dev->name);
491eb4f98d5SKalle Valo tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */
492eb4f98d5SKalle Valo }
493eb4f98d5SKalle Valo
494eb4f98d5SKalle Valo if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu))
495eb4f98d5SKalle Valo tx.crypt = NULL;
496eb4f98d5SKalle Valo else if ((tx.crypt ||
497eb4f98d5SKalle Valo local->crypt_info.crypt[local->crypt_info.tx_keyidx]) &&
498eb4f98d5SKalle Valo !no_encrypt) {
499eb4f98d5SKalle Valo /* Add ISWEP flag both for firmware and host based encryption
500eb4f98d5SKalle Valo */
501eb4f98d5SKalle Valo fc |= IEEE80211_FCTL_PROTECTED;
502eb4f98d5SKalle Valo hdr->frame_control = cpu_to_le16(fc);
503eb4f98d5SKalle Valo } else if (local->drop_unencrypted &&
504eb4f98d5SKalle Valo ieee80211_is_data(hdr->frame_control) &&
505eb4f98d5SKalle Valo meta->ethertype != ETH_P_PAE) {
506eb4f98d5SKalle Valo if (net_ratelimit()) {
507eb4f98d5SKalle Valo printk(KERN_DEBUG "%s: dropped unencrypted TX data "
508eb4f98d5SKalle Valo "frame (drop_unencrypted=1)\n", dev->name);
509eb4f98d5SKalle Valo }
510eb4f98d5SKalle Valo iface->stats.tx_dropped++;
511eb4f98d5SKalle Valo ret = NETDEV_TX_OK;
512eb4f98d5SKalle Valo goto fail;
513eb4f98d5SKalle Valo }
514eb4f98d5SKalle Valo
515eb4f98d5SKalle Valo if (tx.crypt) {
516eb4f98d5SKalle Valo skb = hostap_tx_encrypt(skb, tx.crypt);
517eb4f98d5SKalle Valo if (skb == NULL) {
518eb4f98d5SKalle Valo printk(KERN_DEBUG "%s: TX - encryption failed\n",
519eb4f98d5SKalle Valo dev->name);
520eb4f98d5SKalle Valo ret = NETDEV_TX_OK;
521eb4f98d5SKalle Valo goto fail;
522eb4f98d5SKalle Valo }
523eb4f98d5SKalle Valo meta = (struct hostap_skb_tx_data *) skb->cb;
524eb4f98d5SKalle Valo if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {
525eb4f98d5SKalle Valo printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
526eb4f98d5SKalle Valo "expected 0x%08x) after hostap_tx_encrypt\n",
527eb4f98d5SKalle Valo dev->name, meta->magic,
528eb4f98d5SKalle Valo HOSTAP_SKB_TX_DATA_MAGIC);
529eb4f98d5SKalle Valo ret = NETDEV_TX_OK;
530eb4f98d5SKalle Valo iface->stats.tx_dropped++;
531eb4f98d5SKalle Valo goto fail;
532eb4f98d5SKalle Valo }
533eb4f98d5SKalle Valo }
534eb4f98d5SKalle Valo
535eb4f98d5SKalle Valo if (local->func->tx == NULL || local->func->tx(skb, dev)) {
536eb4f98d5SKalle Valo ret = NETDEV_TX_OK;
537eb4f98d5SKalle Valo iface->stats.tx_dropped++;
538eb4f98d5SKalle Valo } else {
539eb4f98d5SKalle Valo ret = NETDEV_TX_OK;
540eb4f98d5SKalle Valo iface->stats.tx_packets++;
541eb4f98d5SKalle Valo iface->stats.tx_bytes += skb->len;
542eb4f98d5SKalle Valo }
543eb4f98d5SKalle Valo
544eb4f98d5SKalle Valo fail:
545eb4f98d5SKalle Valo if (ret == NETDEV_TX_OK && skb)
546eb4f98d5SKalle Valo dev_kfree_skb(skb);
547eb4f98d5SKalle Valo tx_exit:
548eb4f98d5SKalle Valo if (tx.sta_ptr)
549eb4f98d5SKalle Valo hostap_handle_sta_release(tx.sta_ptr);
550eb4f98d5SKalle Valo return ret;
551eb4f98d5SKalle Valo }
552eb4f98d5SKalle Valo
553eb4f98d5SKalle Valo
554eb4f98d5SKalle Valo EXPORT_SYMBOL(hostap_master_start_xmit);
555