blob: 1b02cdf9d1fa8eeeb8813c776f64987e2778add2 [file] [log] [blame]
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -07001/* src/p80211/p80211conv.c
2*
3* Ether/802.11 conversions and packet buffer routines
4*
5* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
6* --------------------------------------------------------------------
7*
8* linux-wlan
9*
10* The contents of this file are subject to the Mozilla Public
11* License Version 1.1 (the "License"); you may not use this file
12* except in compliance with the License. You may obtain a copy of
13* the License at http://www.mozilla.org/MPL/
14*
15* Software distributed under the License is distributed on an "AS
16* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17* implied. See the License for the specific language governing
18* rights and limitations under the License.
19*
20* Alternatively, the contents of this file may be used under the
21* terms of the GNU Public License version 2 (the "GPL"), in which
22* case the provisions of the GPL are applicable instead of the
23* above. If you wish to allow the use of your version of this file
24* only under the terms of the GPL and not to allow others to use
25* your version of this file under the MPL, indicate your decision
26* by deleting the provisions above and replace them with the notice
27* and other provisions required by the GPL. If you do not delete
28* the provisions above, a recipient may use your version of this
29* file under either the MPL or the GPL.
30*
31* --------------------------------------------------------------------
32*
33* Inquiries regarding the linux-wlan Open Source project can be
34* made directly to:
35*
36* AbsoluteValue Systems Inc.
37* info@linux-wlan.com
38* http://www.linux-wlan.com
39*
40* --------------------------------------------------------------------
41*
42* Portions of the development of this software were funded by
43* Intersil Corporation as part of PRISM(R) chipset product development.
44*
45* --------------------------------------------------------------------
46*
47* This file defines the functions that perform Ethernet to/from
48* 802.11 frame conversions.
49*
50* --------------------------------------------------------------------
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +010051*
52*================================================================ */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070053
54#include <linux/module.h>
55#include <linux/kernel.h>
56#include <linux/sched.h>
57#include <linux/types.h>
58#include <linux/skbuff.h>
59#include <linux/slab.h>
60#include <linux/wireless.h>
61#include <linux/netdevice.h>
62#include <linux/etherdevice.h>
63#include <linux/if_ether.h>
Moritz Muehlenhoffae262302009-01-21 22:00:45 +010064#include <linux/byteorder/generic.h>
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070065
66#include <asm/byteorder.h>
67
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070068#include "p80211types.h"
69#include "p80211hdr.h"
70#include "p80211conv.h"
71#include "p80211mgmt.h"
72#include "p80211msg.h"
73#include "p80211netdev.h"
74#include "p80211ioctl.h"
75#include "p80211req.h"
76
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +010077static u8 oui_rfc1042[] = { 0x00, 0x00, 0x00 };
78static u8 oui_8021h[] = { 0x00, 0x00, 0xf8 };
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070079
80/*----------------------------------------------------------------
81* p80211pb_ether_to_80211
82*
83* Uses the contents of the ether frame and the etherconv setting
84* to build the elements of the 802.11 frame.
85*
86* We don't actually set
87* up the frame header here. That's the MAC's job. We're only handling
88* conversion of DIXII or 802.3+LLC frames to something that works
89* with 802.11.
90*
91* Note -- 802.11 header is NOT part of the skb. Likewise, the 802.11
92* FCS is also not present and will need to be added elsewhere.
93*
94* Arguments:
95* ethconv Conversion type to perform
96* skb skbuff containing the ether frame
97* p80211_hdr 802.11 header
98*
99* Returns:
100* 0 on success, non-zero otherwise
101*
102* Call context:
103* May be called in interrupt or non-interrupt context
104----------------------------------------------------------------*/
Mithlesh Thukral297f06c2009-06-10 19:36:11 +0530105int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv,
Edgardo Hames93df38e2010-07-30 22:51:55 -0300106 struct sk_buff *skb, union p80211_hdr *p80211_hdr,
Edgardo Hames51e48962010-07-31 13:06:52 -0300107 struct p80211_metawep *p80211_wep)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700108{
109
Ebru Akagunduzf474f5e2014-10-25 13:16:42 +0300110 __le16 fc;
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100111 u16 proto;
Edgardo Hames51e48962010-07-31 13:06:52 -0300112 struct wlan_ethhdr e_hdr;
113 struct wlan_llc *e_llc;
114 struct wlan_snap *e_snap;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700115 int foo;
116
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700117 memcpy(&e_hdr, skb->data, sizeof(e_hdr));
118
119 if (skb->len <= 0) {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100120 pr_debug("zero-length skb!\n");
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700121 return 1;
122 }
123
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100124 if (ethconv == WLAN_ETHCONV_ENCAP) { /* simplest case */
125 pr_debug("ENCAP len: %d\n", skb->len);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700126 /* here, we don't care what kind of ether frm. Just stick it */
127 /* in the 80211 payload */
128 /* which is to say, leave the skb alone. */
129 } else {
130 /* step 1: classify ether frame, DIX or 802.3? */
131 proto = ntohs(e_hdr.type);
Hari Prasath Gujulan Elango4c6b0ec2015-06-15 11:48:53 +0000132 if (proto <= ETH_DATA_LEN) {
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100133 pr_debug("802.3 len: %d\n", skb->len);
134 /* codes <= 1500 reserved for 802.3 lengths */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700135 /* it's 802.3, pass ether payload unchanged, */
136
137 /* trim off ethernet header */
Anish Bhatt242850f2015-09-04 14:00:30 -0700138 skb_pull(skb, ETH_HLEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700139
140 /* leave off any PAD octets. */
141 skb_trim(skb, proto);
142 } else {
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100143 pr_debug("DIXII len: %d\n", skb->len);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700144 /* it's DIXII, time for some conversion */
145
146 /* trim off ethernet header */
Anish Bhatt242850f2015-09-04 14:00:30 -0700147 skb_pull(skb, ETH_HLEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700148
149 /* tack on SNAP */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100150 e_snap =
Johan Meiring4eb28f72010-11-06 15:46:54 +0200151 (struct wlan_snap *) skb_push(skb,
152 sizeof(struct wlan_snap));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700153 e_snap->type = htons(proto);
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100154 if (ethconv == WLAN_ETHCONV_8021h
155 && p80211_stt_findproto(proto)) {
156 memcpy(e_snap->oui, oui_8021h,
157 WLAN_IEEE_OUI_LEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700158 } else {
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100159 memcpy(e_snap->oui, oui_rfc1042,
160 WLAN_IEEE_OUI_LEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700161 }
162
163 /* tack on llc */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100164 e_llc =
Johan Meiring4eb28f72010-11-06 15:46:54 +0200165 (struct wlan_llc *) skb_push(skb,
166 sizeof(struct wlan_llc));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700167 e_llc->dsap = 0xAA; /* SNAP, see IEEE 802 */
168 e_llc->ssap = 0xAA;
169 e_llc->ctl = 0x03;
170
171 }
172 }
173
174 /* Set up the 802.11 header */
175 /* It's a data frame */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100176 fc = cpu_to_le16(WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) |
177 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700178
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100179 switch (wlandev->macmode) {
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700180 case WLAN_MACMODE_IBSS_STA:
Moritz Muehlenhoff28b17a42009-01-21 22:00:41 +0100181 memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, ETH_ALEN);
182 memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, ETH_ALEN);
183 memcpy(p80211_hdr->a3.a3, wlandev->bssid, ETH_ALEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700184 break;
185 case WLAN_MACMODE_ESS_STA:
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100186 fc |= cpu_to_le16(WLAN_SET_FC_TODS(1));
Moritz Muehlenhoff28b17a42009-01-21 22:00:41 +0100187 memcpy(p80211_hdr->a3.a1, wlandev->bssid, ETH_ALEN);
188 memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, ETH_ALEN);
189 memcpy(p80211_hdr->a3.a3, &e_hdr.daddr, ETH_ALEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700190 break;
191 case WLAN_MACMODE_ESS_AP:
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100192 fc |= cpu_to_le16(WLAN_SET_FC_FROMDS(1));
Moritz Muehlenhoff28b17a42009-01-21 22:00:41 +0100193 memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, ETH_ALEN);
194 memcpy(p80211_hdr->a3.a2, wlandev->bssid, ETH_ALEN);
195 memcpy(p80211_hdr->a3.a3, &e_hdr.saddr, ETH_ALEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700196 break;
197 default:
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000198 netdev_err(wlandev->netdev,
199 "Error: Converting eth to wlan in unknown mode.\n");
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700200 return 1;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700201 }
202
203 p80211_wep->data = NULL;
204
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100205 if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
206 && (wlandev->hostwep & HOSTWEP_ENCRYPT)) {
207 /* XXXX need to pick keynum other than default? */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700208
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700209 p80211_wep->data = kmalloc(skb->len, GFP_ATOMIC);
Gujulan Elango, Hari Prasath (H.)4bff39d2015-05-13 14:35:25 +0000210 if (!p80211_wep->data)
211 return -ENOMEM;
Svenne Krap5dd8acc2010-02-14 18:59:00 +0100212 foo = wep_encrypt(wlandev, skb->data, p80211_wep->data,
Greg Kroah-Hartmanb02957d2010-03-04 08:14:54 -0800213 skb->len,
Ruslan Pisarev5813b622010-03-15 21:27:42 +0200214 (wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK),
Andrew Elwell3f4b4e72010-02-18 23:56:13 +0100215 p80211_wep->iv, p80211_wep->icv);
Svenne Krap5dd8acc2010-02-14 18:59:00 +0100216 if (foo) {
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000217 netdev_warn(wlandev->netdev,
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100218 "Host en-WEP failed, dropping frame (%d).\n",
219 foo);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700220 return 2;
221 }
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100222 fc |= cpu_to_le16(WLAN_SET_FC_ISWEP(1));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700223 }
224
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100225 /* skb->nh.raw = skb->data; */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700226
227 p80211_hdr->a3.fc = fc;
228 p80211_hdr->a3.dur = 0;
229 p80211_hdr->a3.seq = 0;
230
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700231 return 0;
232}
233
234/* jkriegl: from orinoco, modified */
Mithlesh Thukral297f06c2009-06-10 19:36:11 +0530235static void orinoco_spy_gather(wlandevice_t *wlandev, char *mac,
Edgardo Hames51e48962010-07-31 13:06:52 -0300236 struct p80211_rxmeta *rxmeta)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700237{
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100238 int i;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700239
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100240 /* Gather wireless spy statistics: for each packet, compare the
241 * source address with out list, and if match, get the stats... */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700242
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100243 for (i = 0; i < wlandev->spy_number; i++) {
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700244
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100245 if (!memcmp(wlandev->spy_address[i], mac, ETH_ALEN)) {
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700246 memcpy(wlandev->spy_address[i], mac, ETH_ALEN);
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100247 wlandev->spy_stat[i].level = rxmeta->signal;
248 wlandev->spy_stat[i].noise = rxmeta->noise;
249 wlandev->spy_stat[i].qual =
250 (rxmeta->signal >
251 rxmeta->noise) ? (rxmeta->signal -
252 rxmeta->noise) : 0;
253 wlandev->spy_stat[i].updated = 0x7;
254 }
255 }
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700256}
257
258/*----------------------------------------------------------------
259* p80211pb_80211_to_ether
260*
261* Uses the contents of a received 802.11 frame and the etherconv
262* setting to build an ether frame.
263*
264* This function extracts the src and dest address from the 802.11
265* frame to use in the construction of the eth frame.
266*
267* Arguments:
268* ethconv Conversion type to perform
269* skb Packet buffer containing the 802.11 frame
270*
271* Returns:
272* 0 on success, non-zero otherwise
273*
274* Call context:
275* May be called in interrupt or non-interrupt context
276----------------------------------------------------------------*/
Mithlesh Thukral297f06c2009-06-10 19:36:11 +0530277int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100278 struct sk_buff *skb)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700279{
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100280 netdevice_t *netdev = wlandev->netdev;
281 u16 fc;
282 unsigned int payload_length;
283 unsigned int payload_offset;
Anish Bhatt242850f2015-09-04 14:00:30 -0700284 u8 daddr[ETH_ALEN];
285 u8 saddr[ETH_ALEN];
Edgardo Hames93df38e2010-07-30 22:51:55 -0300286 union p80211_hdr *w_hdr;
Edgardo Hames51e48962010-07-31 13:06:52 -0300287 struct wlan_ethhdr *e_hdr;
288 struct wlan_llc *e_llc;
289 struct wlan_snap *e_snap;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700290
291 int foo;
292
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700293 payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN;
294 payload_offset = WLAN_HDR_A3_LEN;
295
Edgardo Hames93df38e2010-07-30 22:51:55 -0300296 w_hdr = (union p80211_hdr *) skb->data;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700297
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100298 /* setup some vars for convenience */
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100299 fc = le16_to_cpu(w_hdr->a3.fc);
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100300 if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0)) {
Anish Bhatt242850f2015-09-04 14:00:30 -0700301 ether_addr_copy(daddr, w_hdr->a3.a1);
302 ether_addr_copy(saddr, w_hdr->a3.a2);
Johan Meiring4eb28f72010-11-06 15:46:54 +0200303 } else if ((WLAN_GET_FC_TODS(fc) == 0)
304 && (WLAN_GET_FC_FROMDS(fc) == 1)) {
Anish Bhatt242850f2015-09-04 14:00:30 -0700305 ether_addr_copy(daddr, w_hdr->a3.a1);
306 ether_addr_copy(saddr, w_hdr->a3.a3);
Johan Meiring4eb28f72010-11-06 15:46:54 +0200307 } else if ((WLAN_GET_FC_TODS(fc) == 1)
308 && (WLAN_GET_FC_FROMDS(fc) == 0)) {
Anish Bhatt242850f2015-09-04 14:00:30 -0700309 ether_addr_copy(daddr, w_hdr->a3.a3);
310 ether_addr_copy(saddr, w_hdr->a3.a2);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700311 } else {
312 payload_offset = WLAN_HDR_A4_LEN;
Roel Kluin1f9e9ce2008-12-03 00:06:39 +0100313 if (payload_length < WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN) {
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000314 netdev_err(netdev, "A4 frame too short!\n");
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700315 return 1;
316 }
Roel Kluin1f9e9ce2008-12-03 00:06:39 +0100317 payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
Anish Bhatt242850f2015-09-04 14:00:30 -0700318 ether_addr_copy(daddr, w_hdr->a4.a3);
319 ether_addr_copy(saddr, w_hdr->a4.a4);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700320 }
321
322 /* perform de-wep if necessary.. */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100323 if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && WLAN_GET_FC_ISWEP(fc)
324 && (wlandev->hostwep & HOSTWEP_DECRYPT)) {
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700325 if (payload_length <= 8) {
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000326 netdev_err(netdev,
327 "WEP frame too short (%u).\n", skb->len);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700328 return 1;
329 }
Svenne Krap5dd8acc2010-02-14 18:59:00 +0100330 foo = wep_decrypt(wlandev, skb->data + payload_offset + 4,
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700331 payload_length - 8, -1,
332 skb->data + payload_offset,
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100333 skb->data + payload_offset +
Andrew Elwell3f4b4e72010-02-18 23:56:13 +0100334 payload_length - 4);
Svenne Krap5dd8acc2010-02-14 18:59:00 +0100335 if (foo) {
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700336 /* de-wep failed, drop skb. */
Mithlesh Thukral75f49e02009-05-25 19:06:16 +0530337 pr_debug("Host de-WEP failed, dropping frame (%d).\n",
338 foo);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700339 wlandev->rx.decrypt_err++;
340 return 2;
341 }
342
343 /* subtract the IV+ICV length off the payload */
344 payload_length -= 8;
345 /* chop off the IV */
346 skb_pull(skb, 4);
347 /* chop off the ICV. */
348 skb_trim(skb, skb->len - 4);
349
350 wlandev->rx.decrypt++;
351 }
352
Edgardo Hames51e48962010-07-31 13:06:52 -0300353 e_hdr = (struct wlan_ethhdr *) (skb->data + payload_offset);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700354
Edgardo Hames51e48962010-07-31 13:06:52 -0300355 e_llc = (struct wlan_llc *) (skb->data + payload_offset);
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100356 e_snap =
Johan Meiring4eb28f72010-11-06 15:46:54 +0200357 (struct wlan_snap *) (skb->data + payload_offset +
358 sizeof(struct wlan_llc));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700359
360 /* Test for the various encodings */
Edgardo Hames51e48962010-07-31 13:06:52 -0300361 if ((payload_length >= sizeof(struct wlan_ethhdr)) &&
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100362 (e_llc->dsap != 0xaa || e_llc->ssap != 0xaa) &&
Anish Bhatt242850f2015-09-04 14:00:30 -0700363 ((!ether_addr_equal_unaligned(daddr, e_hdr->daddr)) ||
364 (!ether_addr_equal_unaligned(saddr, e_hdr->saddr)))) {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100365 pr_debug("802.3 ENCAP len: %d\n", payload_length);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700366 /* 802.3 Encapsulated */
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000367 /* Test for an overlength frame */
Anish Bhatt242850f2015-09-04 14:00:30 -0700368 if (payload_length > (netdev->mtu + ETH_HLEN)) {
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000369 /* A bogus length ethfrm has been encap'd. */
370 /* Is someone trying an oflow attack? */
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000371 netdev_err(netdev, "ENCAP frame too large (%d > %d)\n",
Anish Bhatt242850f2015-09-04 14:00:30 -0700372 payload_length, netdev->mtu + ETH_HLEN);
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000373 return 1;
374 }
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700375
376 /* Chop off the 802.11 header. it's already sane. */
377 skb_pull(skb, payload_offset);
378 /* chop off the 802.11 CRC */
379 skb_trim(skb, skb->len - WLAN_CRC_LEN);
380
Johan Meiring4eb28f72010-11-06 15:46:54 +0200381 } else if ((payload_length >= sizeof(struct wlan_llc) +
382 sizeof(struct wlan_snap))
Adam Thompsone80528b2011-01-29 02:08:50 -0500383 && (e_llc->dsap == 0xaa)
Johan Meiring4eb28f72010-11-06 15:46:54 +0200384 && (e_llc->ssap == 0xaa)
385 && (e_llc->ctl == 0x03)
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100386 &&
387 (((memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) == 0)
388 && (ethconv == WLAN_ETHCONV_8021h)
389 && (p80211_stt_findproto(le16_to_cpu(e_snap->type))))
390 || (memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) !=
391 0))) {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100392 pr_debug("SNAP+RFC1042 len: %d\n", payload_length);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700393 /* it's a SNAP + RFC1042 frame && protocol is in STT */
394 /* build 802.3 + RFC1042 */
395
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000396 /* Test for an overlength frame */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100397 if (payload_length > netdev->mtu) {
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000398 /* A bogus length ethfrm has been sent. */
399 /* Is someone trying an oflow attack? */
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000400 netdev_err(netdev, "SNAP frame too large (%d > %d)\n",
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100401 payload_length, netdev->mtu);
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000402 return 1;
403 }
404
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700405 /* chop 802.11 header from skb. */
406 skb_pull(skb, payload_offset);
407
408 /* create 802.3 header at beginning of skb. */
Anish Bhatt242850f2015-09-04 14:00:30 -0700409 e_hdr = (struct wlan_ethhdr *)skb_push(skb, ETH_HLEN);
410 ether_addr_copy(e_hdr->daddr, daddr);
411 ether_addr_copy(e_hdr->saddr, saddr);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700412 e_hdr->type = htons(payload_length);
413
414 /* chop off the 802.11 CRC */
415 skb_trim(skb, skb->len - WLAN_CRC_LEN);
416
Johan Meiring4eb28f72010-11-06 15:46:54 +0200417 } else if ((payload_length >= sizeof(struct wlan_llc) +
418 sizeof(struct wlan_snap))
Adam Thompsone80528b2011-01-29 02:08:50 -0500419 && (e_llc->dsap == 0xaa)
Johan Meiring4eb28f72010-11-06 15:46:54 +0200420 && (e_llc->ssap == 0xaa)
421 && (e_llc->ctl == 0x03)) {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100422 pr_debug("802.1h/RFC1042 len: %d\n", payload_length);
Johan Meiring4eb28f72010-11-06 15:46:54 +0200423 /* it's an 802.1h frame || (an RFC1042 && protocol not in STT)
424 build a DIXII + RFC894 */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700425
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000426 /* Test for an overlength frame */
Johan Meiring4eb28f72010-11-06 15:46:54 +0200427 if ((payload_length - sizeof(struct wlan_llc) -
428 sizeof(struct wlan_snap))
429 > netdev->mtu) {
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000430 /* A bogus length ethfrm has been sent. */
431 /* Is someone trying an oflow attack? */
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000432 netdev_err(netdev, "DIXII frame too large (%ld > %d)\n",
Johan Meiring4eb28f72010-11-06 15:46:54 +0200433 (long int)(payload_length -
434 sizeof(struct wlan_llc) -
435 sizeof(struct wlan_snap)), netdev->mtu);
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000436 return 1;
437 }
438
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700439 /* chop 802.11 header from skb. */
440 skb_pull(skb, payload_offset);
441
442 /* chop llc header from skb. */
Edgardo Hames51e48962010-07-31 13:06:52 -0300443 skb_pull(skb, sizeof(struct wlan_llc));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700444
445 /* chop snap header from skb. */
Edgardo Hames51e48962010-07-31 13:06:52 -0300446 skb_pull(skb, sizeof(struct wlan_snap));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700447
448 /* create 802.3 header at beginning of skb. */
Anish Bhatt242850f2015-09-04 14:00:30 -0700449 e_hdr = (struct wlan_ethhdr *)skb_push(skb, ETH_HLEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700450 e_hdr->type = e_snap->type;
Anish Bhatt242850f2015-09-04 14:00:30 -0700451 ether_addr_copy(e_hdr->daddr, daddr);
452 ether_addr_copy(e_hdr->saddr, saddr);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700453
454 /* chop off the 802.11 CRC */
455 skb_trim(skb, skb->len - WLAN_CRC_LEN);
456 } else {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100457 pr_debug("NON-ENCAP len: %d\n", payload_length);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700458 /* any NON-ENCAP */
459 /* it's a generic 80211+LLC or IPX 'Raw 802.3' */
460 /* build an 802.3 frame */
461 /* allocate space and setup hostbuf */
462
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000463 /* Test for an overlength frame */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100464 if (payload_length > netdev->mtu) {
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000465 /* A bogus length ethfrm has been sent. */
466 /* Is someone trying an oflow attack? */
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000467 netdev_err(netdev, "OTHER frame too large (%d > %d)\n",
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100468 payload_length, netdev->mtu);
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000469 return 1;
470 }
471
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700472 /* Chop off the 802.11 header. */
473 skb_pull(skb, payload_offset);
474
475 /* create 802.3 header at beginning of skb. */
Anish Bhatt242850f2015-09-04 14:00:30 -0700476 e_hdr = (struct wlan_ethhdr *)skb_push(skb, ETH_HLEN);
477 ether_addr_copy(e_hdr->daddr, daddr);
478 ether_addr_copy(e_hdr->saddr, saddr);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700479 e_hdr->type = htons(payload_length);
480
481 /* chop off the 802.11 CRC */
482 skb_trim(skb, skb->len - WLAN_CRC_LEN);
483
484 }
485
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100486 /*
487 * Note that eth_type_trans() expects an skb w/ skb->data pointing
488 * at the MAC header, it then sets the following skb members:
489 * skb->mac_header,
490 * skb->data, and
491 * skb->pkt_type.
492 * It then _returns_ the value that _we're_ supposed to stuff in
493 * skb->protocol. This is nuts.
494 */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700495 skb->protocol = eth_type_trans(skb, netdev);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700496
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100497 /* jkriegl: process signal and noise as set in hfa384x_int_rx() */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700498 /* jkriegl: only process signal/noise if requested by iwspy */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100499 if (wlandev->spy_number)
500 orinoco_spy_gather(wlandev, eth_hdr(skb)->h_source,
501 P80211SKB_RXMETA(skb));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700502
503 /* Free the metadata */
504 p80211skb_rxmeta_detach(skb);
505
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700506 return 0;
507}
508
509/*----------------------------------------------------------------
510* p80211_stt_findproto
511*
512* Searches the 802.1h Selective Translation Table for a given
513* protocol.
514*
515* Arguments:
Masanari Iida1a6dfce2014-12-01 00:29:00 +0900516* proto protocol number (in host order) to search for.
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700517*
518* Returns:
519* 1 - if the table is empty or a match is found.
520* 0 - if the table is non-empty and a match is not found.
521*
522* Call context:
523* May be called in interrupt or non-interrupt context
524----------------------------------------------------------------*/
Solomon Peachyaaad4302008-10-29 10:42:53 -0400525int p80211_stt_findproto(u16 proto)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700526{
527 /* Always return found for now. This is the behavior used by the */
528 /* Zoom Win95 driver when 802.1h mode is selected */
529 /* TODO: If necessary, add an actual search we'll probably
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100530 need this to match the CMAC's way of doing things.
531 Need to do some testing to confirm.
532 */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700533
Hari Prasath Gujulan Elango4c6b0ec2015-06-15 11:48:53 +0000534 if (proto == ETH_P_AARP) /* APPLETALK */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700535 return 1;
536
537 return 0;
538}
539
540/*----------------------------------------------------------------
541* p80211skb_rxmeta_detach
542*
543* Disconnects the frmmeta and rxmeta from an skb.
544*
545* Arguments:
546* wlandev The wlandev this skb belongs to.
547* skb The skb we're attaching to.
548*
549* Returns:
550* 0 on success, non-zero otherwise
551*
552* Call context:
553* May be called in interrupt or non-interrupt context
554----------------------------------------------------------------*/
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100555void p80211skb_rxmeta_detach(struct sk_buff *skb)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700556{
Edgardo Hames51e48962010-07-31 13:06:52 -0300557 struct p80211_rxmeta *rxmeta;
558 struct p80211_frmmeta *frmmeta;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700559
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700560 /* Sanity checks */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100561 if (skb == NULL) { /* bad skb */
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100562 pr_debug("Called w/ null skb.\n");
Devendra Naga311e24f2012-09-09 18:40:59 +0530563 return;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700564 }
565 frmmeta = P80211SKB_FRMMETA(skb);
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100566 if (frmmeta == NULL) { /* no magic */
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100567 pr_debug("Called w/ bad frmmeta magic.\n");
Devendra Naga311e24f2012-09-09 18:40:59 +0530568 return;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700569 }
570 rxmeta = frmmeta->rx;
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100571 if (rxmeta == NULL) { /* bad meta ptr */
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100572 pr_debug("Called w/ bad rxmeta ptr.\n");
Devendra Naga311e24f2012-09-09 18:40:59 +0530573 return;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700574 }
575
576 /* Free rxmeta */
577 kfree(rxmeta);
578
579 /* Clear skb->cb */
580 memset(skb->cb, 0, sizeof(skb->cb));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700581}
582
583/*----------------------------------------------------------------
584* p80211skb_rxmeta_attach
585*
586* Allocates a p80211rxmeta structure, initializes it, and attaches
587* it to an skb.
588*
589* Arguments:
590* wlandev The wlandev this skb belongs to.
591* skb The skb we're attaching to.
592*
593* Returns:
594* 0 on success, non-zero otherwise
595*
596* Call context:
597* May be called in interrupt or non-interrupt context
598----------------------------------------------------------------*/
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100599int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700600{
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100601 int result = 0;
Edgardo Hames51e48962010-07-31 13:06:52 -0300602 struct p80211_rxmeta *rxmeta;
603 struct p80211_frmmeta *frmmeta;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700604
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700605 /* If these already have metadata, we error out! */
606 if (P80211SKB_RXMETA(skb) != NULL) {
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000607 netdev_err(wlandev->netdev,
608 "%s: RXmeta already attached!\n", wlandev->name);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700609 result = 0;
610 goto exit;
611 }
612
613 /* Allocate the rxmeta */
Edgardo Hames51e48962010-07-31 13:06:52 -0300614 rxmeta = kzalloc(sizeof(struct p80211_rxmeta), GFP_ATOMIC);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700615
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100616 if (rxmeta == NULL) {
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000617 netdev_err(wlandev->netdev,
618 "%s: Failed to allocate rxmeta.\n", wlandev->name);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700619 result = 1;
620 goto exit;
621 }
622
623 /* Initialize the rxmeta */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700624 rxmeta->wlandev = wlandev;
625 rxmeta->hosttime = jiffies;
626
627 /* Overlay a frmmeta_t onto skb->cb */
Edgardo Hames51e48962010-07-31 13:06:52 -0300628 memset(skb->cb, 0, sizeof(struct p80211_frmmeta));
629 frmmeta = (struct p80211_frmmeta *) (skb->cb);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700630 frmmeta->magic = P80211_FRMMETA_MAGIC;
631 frmmeta->rx = rxmeta;
632exit:
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700633 return result;
634}
635
636/*----------------------------------------------------------------
637* p80211skb_free
638*
639* Frees an entire p80211skb by checking and freeing the meta struct
640* and then freeing the skb.
641*
642* Arguments:
643* wlandev The wlandev this skb belongs to.
644* skb The skb we're attaching to.
645*
646* Returns:
647* 0 on success, non-zero otherwise
648*
649* Call context:
650* May be called in interrupt or non-interrupt context
651----------------------------------------------------------------*/
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100652void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700653{
Edgardo Hames51e48962010-07-31 13:06:52 -0300654 struct p80211_frmmeta *meta;
Moritz Muehlenhoff8a251b52009-01-21 22:00:44 +0100655
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700656 meta = P80211SKB_FRMMETA(skb);
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100657 if (meta && meta->rx)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700658 p80211skb_rxmeta_detach(skb);
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100659 else
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000660 netdev_err(wlandev->netdev,
661 "Freeing an skb (%p) w/ no frmmeta.\n", skb);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700662 dev_kfree_skb(skb);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700663}