blob: 81f36241be03b44db80ee13d3d777d0b6fd66c85 [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*
Pranjal Bhor4a552182016-01-19 01:03:49 +053052*================================================================
53*/
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070054
55#include <linux/module.h>
56#include <linux/kernel.h>
57#include <linux/sched.h>
58#include <linux/types.h>
59#include <linux/skbuff.h>
60#include <linux/slab.h>
61#include <linux/wireless.h>
62#include <linux/netdevice.h>
63#include <linux/etherdevice.h>
64#include <linux/if_ether.h>
Moritz Muehlenhoffae262302009-01-21 22:00:45 +010065#include <linux/byteorder/generic.h>
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070066
67#include <asm/byteorder.h>
68
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070069#include "p80211types.h"
70#include "p80211hdr.h"
71#include "p80211conv.h"
72#include "p80211mgmt.h"
73#include "p80211msg.h"
74#include "p80211netdev.h"
75#include "p80211ioctl.h"
76#include "p80211req.h"
77
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +010078static u8 oui_rfc1042[] = { 0x00, 0x00, 0x00 };
79static u8 oui_8021h[] = { 0x00, 0x00, 0xf8 };
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -070080
81/*----------------------------------------------------------------
82* p80211pb_ether_to_80211
83*
84* Uses the contents of the ether frame and the etherconv setting
85* to build the elements of the 802.11 frame.
86*
87* We don't actually set
88* up the frame header here. That's the MAC's job. We're only handling
89* conversion of DIXII or 802.3+LLC frames to something that works
90* with 802.11.
91*
92* Note -- 802.11 header is NOT part of the skb. Likewise, the 802.11
93* FCS is also not present and will need to be added elsewhere.
94*
95* Arguments:
96* ethconv Conversion type to perform
97* skb skbuff containing the ether frame
98* p80211_hdr 802.11 header
99*
100* Returns:
101* 0 on success, non-zero otherwise
102*
103* Call context:
104* May be called in interrupt or non-interrupt context
Pranjal Bhor4a552182016-01-19 01:03:49 +0530105*----------------------------------------------------------------
106*/
Mithlesh Thukral297f06c2009-06-10 19:36:11 +0530107int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv,
Edgardo Hames93df38e2010-07-30 22:51:55 -0300108 struct sk_buff *skb, union p80211_hdr *p80211_hdr,
Edgardo Hames51e48962010-07-31 13:06:52 -0300109 struct p80211_metawep *p80211_wep)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700110{
111
Ebru Akagunduzf474f5e2014-10-25 13:16:42 +0300112 __le16 fc;
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100113 u16 proto;
Edgardo Hames51e48962010-07-31 13:06:52 -0300114 struct wlan_ethhdr e_hdr;
115 struct wlan_llc *e_llc;
116 struct wlan_snap *e_snap;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700117 int foo;
118
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700119 memcpy(&e_hdr, skb->data, sizeof(e_hdr));
120
121 if (skb->len <= 0) {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100122 pr_debug("zero-length skb!\n");
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700123 return 1;
124 }
125
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100126 if (ethconv == WLAN_ETHCONV_ENCAP) { /* simplest case */
127 pr_debug("ENCAP len: %d\n", skb->len);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700128 /* here, we don't care what kind of ether frm. Just stick it */
129 /* in the 80211 payload */
130 /* which is to say, leave the skb alone. */
131 } else {
132 /* step 1: classify ether frame, DIX or 802.3? */
133 proto = ntohs(e_hdr.type);
Hari Prasath Gujulan Elango4c6b0ec2015-06-15 11:48:53 +0000134 if (proto <= ETH_DATA_LEN) {
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100135 pr_debug("802.3 len: %d\n", skb->len);
136 /* codes <= 1500 reserved for 802.3 lengths */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700137 /* it's 802.3, pass ether payload unchanged, */
138
139 /* trim off ethernet header */
Anish Bhatt242850f2015-09-04 14:00:30 -0700140 skb_pull(skb, ETH_HLEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700141
142 /* leave off any PAD octets. */
143 skb_trim(skb, proto);
144 } else {
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100145 pr_debug("DIXII len: %d\n", skb->len);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700146 /* it's DIXII, time for some conversion */
147
148 /* trim off ethernet header */
Anish Bhatt242850f2015-09-04 14:00:30 -0700149 skb_pull(skb, ETH_HLEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700150
151 /* tack on SNAP */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100152 e_snap =
Johan Meiring4eb28f72010-11-06 15:46:54 +0200153 (struct wlan_snap *) skb_push(skb,
154 sizeof(struct wlan_snap));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700155 e_snap->type = htons(proto);
Pranjal Bhor25845382016-01-19 01:04:09 +0530156 if (ethconv == WLAN_ETHCONV_8021h &&
157 p80211_stt_findproto(proto)) {
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100158 memcpy(e_snap->oui, oui_8021h,
159 WLAN_IEEE_OUI_LEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700160 } else {
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100161 memcpy(e_snap->oui, oui_rfc1042,
162 WLAN_IEEE_OUI_LEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700163 }
164
165 /* tack on llc */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100166 e_llc =
Johan Meiring4eb28f72010-11-06 15:46:54 +0200167 (struct wlan_llc *) skb_push(skb,
168 sizeof(struct wlan_llc));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700169 e_llc->dsap = 0xAA; /* SNAP, see IEEE 802 */
170 e_llc->ssap = 0xAA;
171 e_llc->ctl = 0x03;
172
173 }
174 }
175
176 /* Set up the 802.11 header */
177 /* It's a data frame */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100178 fc = cpu_to_le16(WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) |
179 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700180
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100181 switch (wlandev->macmode) {
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700182 case WLAN_MACMODE_IBSS_STA:
Moritz Muehlenhoff28b17a42009-01-21 22:00:41 +0100183 memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, ETH_ALEN);
184 memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, ETH_ALEN);
185 memcpy(p80211_hdr->a3.a3, wlandev->bssid, ETH_ALEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700186 break;
187 case WLAN_MACMODE_ESS_STA:
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100188 fc |= cpu_to_le16(WLAN_SET_FC_TODS(1));
Moritz Muehlenhoff28b17a42009-01-21 22:00:41 +0100189 memcpy(p80211_hdr->a3.a1, wlandev->bssid, ETH_ALEN);
190 memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, ETH_ALEN);
191 memcpy(p80211_hdr->a3.a3, &e_hdr.daddr, ETH_ALEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700192 break;
193 case WLAN_MACMODE_ESS_AP:
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100194 fc |= cpu_to_le16(WLAN_SET_FC_FROMDS(1));
Moritz Muehlenhoff28b17a42009-01-21 22:00:41 +0100195 memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, ETH_ALEN);
196 memcpy(p80211_hdr->a3.a2, wlandev->bssid, ETH_ALEN);
197 memcpy(p80211_hdr->a3.a3, &e_hdr.saddr, ETH_ALEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700198 break;
199 default:
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000200 netdev_err(wlandev->netdev,
201 "Error: Converting eth to wlan in unknown mode.\n");
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700202 return 1;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700203 }
204
205 p80211_wep->data = NULL;
206
Pranjal Bhor25845382016-01-19 01:04:09 +0530207 if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) &&
208 (wlandev->hostwep & HOSTWEP_ENCRYPT)) {
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100209 /* XXXX need to pick keynum other than default? */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700210
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700211 p80211_wep->data = kmalloc(skb->len, GFP_ATOMIC);
Gujulan Elango, Hari Prasath (H.)4bff39d2015-05-13 14:35:25 +0000212 if (!p80211_wep->data)
213 return -ENOMEM;
Svenne Krap5dd8acc2010-02-14 18:59:00 +0100214 foo = wep_encrypt(wlandev, skb->data, p80211_wep->data,
Greg Kroah-Hartmanb02957d2010-03-04 08:14:54 -0800215 skb->len,
Ruslan Pisarev5813b622010-03-15 21:27:42 +0200216 (wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK),
Andrew Elwell3f4b4e72010-02-18 23:56:13 +0100217 p80211_wep->iv, p80211_wep->icv);
Svenne Krap5dd8acc2010-02-14 18:59:00 +0100218 if (foo) {
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000219 netdev_warn(wlandev->netdev,
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100220 "Host en-WEP failed, dropping frame (%d).\n",
221 foo);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700222 return 2;
223 }
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100224 fc |= cpu_to_le16(WLAN_SET_FC_ISWEP(1));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700225 }
226
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100227 /* skb->nh.raw = skb->data; */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700228
229 p80211_hdr->a3.fc = fc;
230 p80211_hdr->a3.dur = 0;
231 p80211_hdr->a3.seq = 0;
232
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700233 return 0;
234}
235
236/* jkriegl: from orinoco, modified */
Mithlesh Thukral297f06c2009-06-10 19:36:11 +0530237static void orinoco_spy_gather(wlandevice_t *wlandev, char *mac,
Edgardo Hames51e48962010-07-31 13:06:52 -0300238 struct p80211_rxmeta *rxmeta)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700239{
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100240 int i;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700241
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100242 /* Gather wireless spy statistics: for each packet, compare the
Pranjal Bhor4a552182016-01-19 01:03:49 +0530243 * source address with out list, and if match, get the stats...
244 */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700245
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100246 for (i = 0; i < wlandev->spy_number; i++) {
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700247
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100248 if (!memcmp(wlandev->spy_address[i], mac, ETH_ALEN)) {
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700249 memcpy(wlandev->spy_address[i], mac, ETH_ALEN);
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100250 wlandev->spy_stat[i].level = rxmeta->signal;
251 wlandev->spy_stat[i].noise = rxmeta->noise;
252 wlandev->spy_stat[i].qual =
253 (rxmeta->signal >
254 rxmeta->noise) ? (rxmeta->signal -
255 rxmeta->noise) : 0;
256 wlandev->spy_stat[i].updated = 0x7;
257 }
258 }
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700259}
260
261/*----------------------------------------------------------------
262* p80211pb_80211_to_ether
263*
264* Uses the contents of a received 802.11 frame and the etherconv
265* setting to build an ether frame.
266*
267* This function extracts the src and dest address from the 802.11
268* frame to use in the construction of the eth frame.
269*
270* Arguments:
271* ethconv Conversion type to perform
272* skb Packet buffer containing the 802.11 frame
273*
274* Returns:
275* 0 on success, non-zero otherwise
276*
277* Call context:
278* May be called in interrupt or non-interrupt context
Pranjal Bhor4a552182016-01-19 01:03:49 +0530279*----------------------------------------------------------------
280*/
Mithlesh Thukral297f06c2009-06-10 19:36:11 +0530281int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100282 struct sk_buff *skb)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700283{
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100284 netdevice_t *netdev = wlandev->netdev;
285 u16 fc;
286 unsigned int payload_length;
287 unsigned int payload_offset;
Anish Bhatt242850f2015-09-04 14:00:30 -0700288 u8 daddr[ETH_ALEN];
289 u8 saddr[ETH_ALEN];
Edgardo Hames93df38e2010-07-30 22:51:55 -0300290 union p80211_hdr *w_hdr;
Edgardo Hames51e48962010-07-31 13:06:52 -0300291 struct wlan_ethhdr *e_hdr;
292 struct wlan_llc *e_llc;
293 struct wlan_snap *e_snap;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700294
295 int foo;
296
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700297 payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN;
298 payload_offset = WLAN_HDR_A3_LEN;
299
Edgardo Hames93df38e2010-07-30 22:51:55 -0300300 w_hdr = (union p80211_hdr *) skb->data;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700301
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100302 /* setup some vars for convenience */
Moritz Muehlenhoffae262302009-01-21 22:00:45 +0100303 fc = le16_to_cpu(w_hdr->a3.fc);
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100304 if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0)) {
Anish Bhatt242850f2015-09-04 14:00:30 -0700305 ether_addr_copy(daddr, w_hdr->a3.a1);
306 ether_addr_copy(saddr, w_hdr->a3.a2);
Pranjal Bhor25845382016-01-19 01:04:09 +0530307 } else if ((WLAN_GET_FC_TODS(fc) == 0) &&
308 (WLAN_GET_FC_FROMDS(fc) == 1)) {
Anish Bhatt242850f2015-09-04 14:00:30 -0700309 ether_addr_copy(daddr, w_hdr->a3.a1);
310 ether_addr_copy(saddr, w_hdr->a3.a3);
Pranjal Bhor25845382016-01-19 01:04:09 +0530311 } else if ((WLAN_GET_FC_TODS(fc) == 1) &&
312 (WLAN_GET_FC_FROMDS(fc) == 0)) {
Anish Bhatt242850f2015-09-04 14:00:30 -0700313 ether_addr_copy(daddr, w_hdr->a3.a3);
314 ether_addr_copy(saddr, w_hdr->a3.a2);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700315 } else {
316 payload_offset = WLAN_HDR_A4_LEN;
Roel Kluin1f9e9ce2008-12-03 00:06:39 +0100317 if (payload_length < WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN) {
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000318 netdev_err(netdev, "A4 frame too short!\n");
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700319 return 1;
320 }
Roel Kluin1f9e9ce2008-12-03 00:06:39 +0100321 payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
Anish Bhatt242850f2015-09-04 14:00:30 -0700322 ether_addr_copy(daddr, w_hdr->a4.a3);
323 ether_addr_copy(saddr, w_hdr->a4.a4);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700324 }
325
326 /* perform de-wep if necessary.. */
Pranjal Bhor25845382016-01-19 01:04:09 +0530327 if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) &&
328 WLAN_GET_FC_ISWEP(fc) &&
329 (wlandev->hostwep & HOSTWEP_DECRYPT)) {
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700330 if (payload_length <= 8) {
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000331 netdev_err(netdev,
332 "WEP frame too short (%u).\n", skb->len);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700333 return 1;
334 }
Svenne Krap5dd8acc2010-02-14 18:59:00 +0100335 foo = wep_decrypt(wlandev, skb->data + payload_offset + 4,
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700336 payload_length - 8, -1,
337 skb->data + payload_offset,
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100338 skb->data + payload_offset +
Andrew Elwell3f4b4e72010-02-18 23:56:13 +0100339 payload_length - 4);
Svenne Krap5dd8acc2010-02-14 18:59:00 +0100340 if (foo) {
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700341 /* de-wep failed, drop skb. */
Mithlesh Thukral75f49e02009-05-25 19:06:16 +0530342 pr_debug("Host de-WEP failed, dropping frame (%d).\n",
343 foo);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700344 wlandev->rx.decrypt_err++;
345 return 2;
346 }
347
348 /* subtract the IV+ICV length off the payload */
349 payload_length -= 8;
350 /* chop off the IV */
351 skb_pull(skb, 4);
352 /* chop off the ICV. */
353 skb_trim(skb, skb->len - 4);
354
355 wlandev->rx.decrypt++;
356 }
357
Edgardo Hames51e48962010-07-31 13:06:52 -0300358 e_hdr = (struct wlan_ethhdr *) (skb->data + payload_offset);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700359
Edgardo Hames51e48962010-07-31 13:06:52 -0300360 e_llc = (struct wlan_llc *) (skb->data + payload_offset);
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100361 e_snap =
Johan Meiring4eb28f72010-11-06 15:46:54 +0200362 (struct wlan_snap *) (skb->data + payload_offset +
363 sizeof(struct wlan_llc));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700364
365 /* Test for the various encodings */
Edgardo Hames51e48962010-07-31 13:06:52 -0300366 if ((payload_length >= sizeof(struct wlan_ethhdr)) &&
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100367 (e_llc->dsap != 0xaa || e_llc->ssap != 0xaa) &&
Anish Bhatt242850f2015-09-04 14:00:30 -0700368 ((!ether_addr_equal_unaligned(daddr, e_hdr->daddr)) ||
369 (!ether_addr_equal_unaligned(saddr, e_hdr->saddr)))) {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100370 pr_debug("802.3 ENCAP len: %d\n", payload_length);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700371 /* 802.3 Encapsulated */
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000372 /* Test for an overlength frame */
Anish Bhatt242850f2015-09-04 14:00:30 -0700373 if (payload_length > (netdev->mtu + ETH_HLEN)) {
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000374 /* A bogus length ethfrm has been encap'd. */
375 /* Is someone trying an oflow attack? */
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000376 netdev_err(netdev, "ENCAP frame too large (%d > %d)\n",
Anish Bhatt242850f2015-09-04 14:00:30 -0700377 payload_length, netdev->mtu + ETH_HLEN);
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000378 return 1;
379 }
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700380
381 /* Chop off the 802.11 header. it's already sane. */
382 skb_pull(skb, payload_offset);
383 /* chop off the 802.11 CRC */
384 skb_trim(skb, skb->len - WLAN_CRC_LEN);
385
Johan Meiring4eb28f72010-11-06 15:46:54 +0200386 } else if ((payload_length >= sizeof(struct wlan_llc) +
Pranjal Bhor25845382016-01-19 01:04:09 +0530387 sizeof(struct wlan_snap)) &&
388 (e_llc->dsap == 0xaa) &&
389 (e_llc->ssap == 0xaa) &&
390 (e_llc->ctl == 0x03) &&
391 (((memcmp(e_snap->oui, oui_rfc1042,
392 WLAN_IEEE_OUI_LEN) == 0) &&
393 (ethconv == WLAN_ETHCONV_8021h) &&
394 (p80211_stt_findproto(le16_to_cpu(e_snap->type)))) ||
395 (memcmp(e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN) !=
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100396 0))) {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100397 pr_debug("SNAP+RFC1042 len: %d\n", payload_length);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700398 /* it's a SNAP + RFC1042 frame && protocol is in STT */
399 /* build 802.3 + RFC1042 */
400
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000401 /* Test for an overlength frame */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100402 if (payload_length > netdev->mtu) {
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000403 /* A bogus length ethfrm has been sent. */
404 /* Is someone trying an oflow attack? */
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000405 netdev_err(netdev, "SNAP frame too large (%d > %d)\n",
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100406 payload_length, netdev->mtu);
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000407 return 1;
408 }
409
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700410 /* chop 802.11 header from skb. */
411 skb_pull(skb, payload_offset);
412
413 /* create 802.3 header at beginning of skb. */
Anish Bhatt242850f2015-09-04 14:00:30 -0700414 e_hdr = (struct wlan_ethhdr *)skb_push(skb, ETH_HLEN);
415 ether_addr_copy(e_hdr->daddr, daddr);
416 ether_addr_copy(e_hdr->saddr, saddr);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700417 e_hdr->type = htons(payload_length);
418
419 /* chop off the 802.11 CRC */
420 skb_trim(skb, skb->len - WLAN_CRC_LEN);
421
Johan Meiring4eb28f72010-11-06 15:46:54 +0200422 } else if ((payload_length >= sizeof(struct wlan_llc) +
Pranjal Bhor25845382016-01-19 01:04:09 +0530423 sizeof(struct wlan_snap)) &&
424 (e_llc->dsap == 0xaa) &&
425 (e_llc->ssap == 0xaa) &&
426 (e_llc->ctl == 0x03)) {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100427 pr_debug("802.1h/RFC1042 len: %d\n", payload_length);
Johan Meiring4eb28f72010-11-06 15:46:54 +0200428 /* it's an 802.1h frame || (an RFC1042 && protocol not in STT)
Pranjal Bhor4a552182016-01-19 01:03:49 +0530429 * build a DIXII + RFC894
430 */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700431
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000432 /* Test for an overlength frame */
Johan Meiring4eb28f72010-11-06 15:46:54 +0200433 if ((payload_length - sizeof(struct wlan_llc) -
434 sizeof(struct wlan_snap))
435 > netdev->mtu) {
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000436 /* A bogus length ethfrm has been sent. */
437 /* Is someone trying an oflow attack? */
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000438 netdev_err(netdev, "DIXII frame too large (%ld > %d)\n",
Johan Meiring4eb28f72010-11-06 15:46:54 +0200439 (long int)(payload_length -
440 sizeof(struct wlan_llc) -
441 sizeof(struct wlan_snap)), netdev->mtu);
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000442 return 1;
443 }
444
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700445 /* chop 802.11 header from skb. */
446 skb_pull(skb, payload_offset);
447
448 /* chop llc header from skb. */
Edgardo Hames51e48962010-07-31 13:06:52 -0300449 skb_pull(skb, sizeof(struct wlan_llc));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700450
451 /* chop snap header from skb. */
Edgardo Hames51e48962010-07-31 13:06:52 -0300452 skb_pull(skb, sizeof(struct wlan_snap));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700453
454 /* create 802.3 header at beginning of skb. */
Anish Bhatt242850f2015-09-04 14:00:30 -0700455 e_hdr = (struct wlan_ethhdr *)skb_push(skb, ETH_HLEN);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700456 e_hdr->type = e_snap->type;
Anish Bhatt242850f2015-09-04 14:00:30 -0700457 ether_addr_copy(e_hdr->daddr, daddr);
458 ether_addr_copy(e_hdr->saddr, saddr);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700459
460 /* chop off the 802.11 CRC */
461 skb_trim(skb, skb->len - WLAN_CRC_LEN);
462 } else {
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100463 pr_debug("NON-ENCAP len: %d\n", payload_length);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700464 /* any NON-ENCAP */
465 /* it's a generic 80211+LLC or IPX 'Raw 802.3' */
466 /* build an 802.3 frame */
467 /* allocate space and setup hostbuf */
468
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000469 /* Test for an overlength frame */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100470 if (payload_length > netdev->mtu) {
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000471 /* A bogus length ethfrm has been sent. */
472 /* Is someone trying an oflow attack? */
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000473 netdev_err(netdev, "OTHER frame too large (%d > %d)\n",
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100474 payload_length, netdev->mtu);
Richard Kennedy33ce0ca2008-11-03 11:24:54 +0000475 return 1;
476 }
477
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700478 /* Chop off the 802.11 header. */
479 skb_pull(skb, payload_offset);
480
481 /* create 802.3 header at beginning of skb. */
Anish Bhatt242850f2015-09-04 14:00:30 -0700482 e_hdr = (struct wlan_ethhdr *)skb_push(skb, ETH_HLEN);
483 ether_addr_copy(e_hdr->daddr, daddr);
484 ether_addr_copy(e_hdr->saddr, saddr);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700485 e_hdr->type = htons(payload_length);
486
487 /* chop off the 802.11 CRC */
488 skb_trim(skb, skb->len - WLAN_CRC_LEN);
489
490 }
491
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100492 /*
493 * Note that eth_type_trans() expects an skb w/ skb->data pointing
494 * at the MAC header, it then sets the following skb members:
495 * skb->mac_header,
496 * skb->data, and
497 * skb->pkt_type.
498 * It then _returns_ the value that _we're_ supposed to stuff in
499 * skb->protocol. This is nuts.
500 */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700501 skb->protocol = eth_type_trans(skb, netdev);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700502
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100503 /* jkriegl: process signal and noise as set in hfa384x_int_rx() */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700504 /* jkriegl: only process signal/noise if requested by iwspy */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100505 if (wlandev->spy_number)
506 orinoco_spy_gather(wlandev, eth_hdr(skb)->h_source,
507 P80211SKB_RXMETA(skb));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700508
509 /* Free the metadata */
510 p80211skb_rxmeta_detach(skb);
511
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700512 return 0;
513}
514
515/*----------------------------------------------------------------
516* p80211_stt_findproto
517*
518* Searches the 802.1h Selective Translation Table for a given
519* protocol.
520*
521* Arguments:
Masanari Iida1a6dfce2014-12-01 00:29:00 +0900522* proto protocol number (in host order) to search for.
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700523*
524* Returns:
525* 1 - if the table is empty or a match is found.
526* 0 - if the table is non-empty and a match is not found.
527*
528* Call context:
529* May be called in interrupt or non-interrupt context
Pranjal Bhor4a552182016-01-19 01:03:49 +0530530*----------------------------------------------------------------
531*/
Solomon Peachyaaad4302008-10-29 10:42:53 -0400532int p80211_stt_findproto(u16 proto)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700533{
534 /* Always return found for now. This is the behavior used by the */
Pranjal Bhor4a552182016-01-19 01:03:49 +0530535 /* Zoom Win95 driver when 802.1h mode is selected */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700536 /* TODO: If necessary, add an actual search we'll probably
Pranjal Bhor4a552182016-01-19 01:03:49 +0530537 * need this to match the CMAC's way of doing things.
538 * Need to do some testing to confirm.
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100539 */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700540
Hari Prasath Gujulan Elango4c6b0ec2015-06-15 11:48:53 +0000541 if (proto == ETH_P_AARP) /* APPLETALK */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700542 return 1;
543
544 return 0;
545}
546
547/*----------------------------------------------------------------
548* p80211skb_rxmeta_detach
549*
550* Disconnects the frmmeta and rxmeta from an skb.
551*
552* Arguments:
553* wlandev The wlandev this skb belongs to.
554* skb The skb we're attaching to.
555*
556* Returns:
557* 0 on success, non-zero otherwise
558*
559* Call context:
560* May be called in interrupt or non-interrupt context
Pranjal Bhor4a552182016-01-19 01:03:49 +0530561*----------------------------------------------------------------
562*/
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100563void p80211skb_rxmeta_detach(struct sk_buff *skb)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700564{
Edgardo Hames51e48962010-07-31 13:06:52 -0300565 struct p80211_rxmeta *rxmeta;
566 struct p80211_frmmeta *frmmeta;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700567
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700568 /* Sanity checks */
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100569 if (skb == NULL) { /* bad skb */
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100570 pr_debug("Called w/ null skb.\n");
Devendra Naga311e24f2012-09-09 18:40:59 +0530571 return;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700572 }
573 frmmeta = P80211SKB_FRMMETA(skb);
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100574 if (frmmeta == NULL) { /* no magic */
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100575 pr_debug("Called w/ bad frmmeta magic.\n");
Devendra Naga311e24f2012-09-09 18:40:59 +0530576 return;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700577 }
578 rxmeta = frmmeta->rx;
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100579 if (rxmeta == NULL) { /* bad meta ptr */
Moritz Muehlenhoffa7cf7ba2009-02-08 02:01:00 +0100580 pr_debug("Called w/ bad rxmeta ptr.\n");
Devendra Naga311e24f2012-09-09 18:40:59 +0530581 return;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700582 }
583
584 /* Free rxmeta */
585 kfree(rxmeta);
586
587 /* Clear skb->cb */
588 memset(skb->cb, 0, sizeof(skb->cb));
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700589}
590
591/*----------------------------------------------------------------
592* p80211skb_rxmeta_attach
593*
594* Allocates a p80211rxmeta structure, initializes it, and attaches
595* it to an skb.
596*
597* Arguments:
598* wlandev The wlandev this skb belongs to.
599* skb The skb we're attaching to.
600*
601* Returns:
602* 0 on success, non-zero otherwise
603*
604* Call context:
605* May be called in interrupt or non-interrupt context
Pranjal Bhor4a552182016-01-19 01:03:49 +0530606*----------------------------------------------------------------
607*/
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100608int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700609{
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100610 int result = 0;
Edgardo Hames51e48962010-07-31 13:06:52 -0300611 struct p80211_rxmeta *rxmeta;
612 struct p80211_frmmeta *frmmeta;
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700613
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700614 /* If these already have metadata, we error out! */
615 if (P80211SKB_RXMETA(skb) != NULL) {
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000616 netdev_err(wlandev->netdev,
617 "%s: RXmeta already attached!\n", wlandev->name);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700618 result = 0;
619 goto exit;
620 }
621
622 /* Allocate the rxmeta */
Edgardo Hames51e48962010-07-31 13:06:52 -0300623 rxmeta = kzalloc(sizeof(struct p80211_rxmeta), GFP_ATOMIC);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700624
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100625 if (rxmeta == NULL) {
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000626 netdev_err(wlandev->netdev,
627 "%s: Failed to allocate rxmeta.\n", wlandev->name);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700628 result = 1;
629 goto exit;
630 }
631
632 /* Initialize the rxmeta */
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700633 rxmeta->wlandev = wlandev;
634 rxmeta->hosttime = jiffies;
635
636 /* Overlay a frmmeta_t onto skb->cb */
Edgardo Hames51e48962010-07-31 13:06:52 -0300637 memset(skb->cb, 0, sizeof(struct p80211_frmmeta));
638 frmmeta = (struct p80211_frmmeta *) (skb->cb);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700639 frmmeta->magic = P80211_FRMMETA_MAGIC;
640 frmmeta->rx = rxmeta;
641exit:
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700642 return result;
643}
644
645/*----------------------------------------------------------------
646* p80211skb_free
647*
648* Frees an entire p80211skb by checking and freeing the meta struct
649* and then freeing the skb.
650*
651* Arguments:
652* wlandev The wlandev this skb belongs to.
653* skb The skb we're attaching to.
654*
655* Returns:
656* 0 on success, non-zero otherwise
657*
658* Call context:
659* May be called in interrupt or non-interrupt context
Pranjal Bhor4a552182016-01-19 01:03:49 +0530660*----------------------------------------------------------------
661*/
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100662void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700663{
Edgardo Hames51e48962010-07-31 13:06:52 -0300664 struct p80211_frmmeta *meta;
Moritz Muehlenhoff8a251b52009-01-21 22:00:44 +0100665
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700666 meta = P80211SKB_FRMMETA(skb);
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100667 if (meta && meta->rx)
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700668 p80211skb_rxmeta_detach(skb);
Moritz Muehlenhoff82eaca72009-02-08 02:20:56 +0100669 else
Vitaly Osipov02d9b1e2014-05-18 16:59:36 +1000670 netdev_err(wlandev->netdev,
671 "Freeing an skb (%p) w/ no frmmeta.\n", skb);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700672 dev_kfree_skb(skb);
Greg Kroah-Hartman00b3ed12008-10-02 11:29:28 -0700673}