1 /* 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 * --------------------------------------------------------------------
51 *
52 *================================================================ */
53 
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>
64 #include <linux/byteorder/generic.h>
65 
66 #include <asm/byteorder.h>
67 
68 #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 
77 static u8 oui_rfc1042[] = { 0x00, 0x00, 0x00 };
78 static u8 oui_8021h[] = { 0x00, 0x00, 0xf8 };
79 
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 ----------------------------------------------------------------*/
skb_ether_to_p80211(wlandevice_t * wlandev,u32 ethconv,struct sk_buff * skb,union p80211_hdr * p80211_hdr,struct p80211_metawep * p80211_wep)105 int skb_ether_to_p80211(wlandevice_t *wlandev, u32 ethconv,
106 			struct sk_buff *skb, union p80211_hdr *p80211_hdr,
107 			struct p80211_metawep *p80211_wep)
108 {
109 
110 	__le16 fc;
111 	u16 proto;
112 	struct wlan_ethhdr e_hdr;
113 	struct wlan_llc *e_llc;
114 	struct wlan_snap *e_snap;
115 	int foo;
116 
117 	memcpy(&e_hdr, skb->data, sizeof(e_hdr));
118 
119 	if (skb->len <= 0) {
120 		pr_debug("zero-length skb!\n");
121 		return 1;
122 	}
123 
124 	if (ethconv == WLAN_ETHCONV_ENCAP) {	/* simplest case */
125 		pr_debug("ENCAP len: %d\n", skb->len);
126 		/* 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);
132 		if (proto <= ETH_DATA_LEN) {
133 			pr_debug("802.3 len: %d\n", skb->len);
134 			/* codes <= 1500 reserved for 802.3 lengths */
135 			/* it's 802.3, pass ether payload unchanged,  */
136 
137 			/* trim off ethernet header */
138 			skb_pull(skb, ETH_HLEN);
139 
140 			/*   leave off any PAD octets.  */
141 			skb_trim(skb, proto);
142 		} else {
143 			pr_debug("DIXII len: %d\n", skb->len);
144 			/* it's DIXII, time for some conversion */
145 
146 			/* trim off ethernet header */
147 			skb_pull(skb, ETH_HLEN);
148 
149 			/* tack on SNAP */
150 			e_snap =
151 			    (struct wlan_snap *) skb_push(skb,
152 				sizeof(struct wlan_snap));
153 			e_snap->type = htons(proto);
154 			if (ethconv == WLAN_ETHCONV_8021h
155 			    && p80211_stt_findproto(proto)) {
156 				memcpy(e_snap->oui, oui_8021h,
157 				       WLAN_IEEE_OUI_LEN);
158 			} else {
159 				memcpy(e_snap->oui, oui_rfc1042,
160 				       WLAN_IEEE_OUI_LEN);
161 			}
162 
163 			/* tack on llc */
164 			e_llc =
165 			    (struct wlan_llc *) skb_push(skb,
166 				sizeof(struct wlan_llc));
167 			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 */
176 	fc = cpu_to_le16(WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) |
177 			 WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY));
178 
179 	switch (wlandev->macmode) {
180 	case WLAN_MACMODE_IBSS_STA:
181 		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);
184 		break;
185 	case WLAN_MACMODE_ESS_STA:
186 		fc |= cpu_to_le16(WLAN_SET_FC_TODS(1));
187 		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);
190 		break;
191 	case WLAN_MACMODE_ESS_AP:
192 		fc |= cpu_to_le16(WLAN_SET_FC_FROMDS(1));
193 		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);
196 		break;
197 	default:
198 		netdev_err(wlandev->netdev,
199 			   "Error: Converting eth to wlan in unknown mode.\n");
200 		return 1;
201 	}
202 
203 	p80211_wep->data = NULL;
204 
205 	if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED)
206 	    && (wlandev->hostwep & HOSTWEP_ENCRYPT)) {
207 		/* XXXX need to pick keynum other than default? */
208 
209 		p80211_wep->data = kmalloc(skb->len, GFP_ATOMIC);
210 		if (!p80211_wep->data)
211 			return -ENOMEM;
212 		foo = wep_encrypt(wlandev, skb->data, p80211_wep->data,
213 				  skb->len,
214 				  (wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK),
215 				  p80211_wep->iv, p80211_wep->icv);
216 		if (foo) {
217 			netdev_warn(wlandev->netdev,
218 			       "Host en-WEP failed, dropping frame (%d).\n",
219 			       foo);
220 			return 2;
221 		}
222 		fc |= cpu_to_le16(WLAN_SET_FC_ISWEP(1));
223 	}
224 
225 	/*      skb->nh.raw = skb->data; */
226 
227 	p80211_hdr->a3.fc = fc;
228 	p80211_hdr->a3.dur = 0;
229 	p80211_hdr->a3.seq = 0;
230 
231 	return 0;
232 }
233 
234 /* jkriegl: from orinoco, modified */
orinoco_spy_gather(wlandevice_t * wlandev,char * mac,struct p80211_rxmeta * rxmeta)235 static void orinoco_spy_gather(wlandevice_t *wlandev, char *mac,
236 			       struct p80211_rxmeta *rxmeta)
237 {
238 	int i;
239 
240 	/* Gather wireless spy statistics: for each packet, compare the
241 	 * source address with out list, and if match, get the stats... */
242 
243 	for (i = 0; i < wlandev->spy_number; i++) {
244 
245 		if (!memcmp(wlandev->spy_address[i], mac, ETH_ALEN)) {
246 			memcpy(wlandev->spy_address[i], mac, ETH_ALEN);
247 			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 	}
256 }
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 ----------------------------------------------------------------*/
skb_p80211_to_ether(wlandevice_t * wlandev,u32 ethconv,struct sk_buff * skb)277 int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
278 			struct sk_buff *skb)
279 {
280 	netdevice_t *netdev = wlandev->netdev;
281 	u16 fc;
282 	unsigned int payload_length;
283 	unsigned int payload_offset;
284 	u8 daddr[ETH_ALEN];
285 	u8 saddr[ETH_ALEN];
286 	union p80211_hdr *w_hdr;
287 	struct wlan_ethhdr *e_hdr;
288 	struct wlan_llc *e_llc;
289 	struct wlan_snap *e_snap;
290 
291 	int foo;
292 
293 	payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN;
294 	payload_offset = WLAN_HDR_A3_LEN;
295 
296 	w_hdr = (union p80211_hdr *) skb->data;
297 
298 	/* setup some vars for convenience */
299 	fc = le16_to_cpu(w_hdr->a3.fc);
300 	if ((WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0)) {
301 		ether_addr_copy(daddr, w_hdr->a3.a1);
302 		ether_addr_copy(saddr, w_hdr->a3.a2);
303 	} else if ((WLAN_GET_FC_TODS(fc) == 0)
304 			&& (WLAN_GET_FC_FROMDS(fc) == 1)) {
305 		ether_addr_copy(daddr, w_hdr->a3.a1);
306 		ether_addr_copy(saddr, w_hdr->a3.a3);
307 	} else if ((WLAN_GET_FC_TODS(fc) == 1)
308 			&& (WLAN_GET_FC_FROMDS(fc) == 0)) {
309 		ether_addr_copy(daddr, w_hdr->a3.a3);
310 		ether_addr_copy(saddr, w_hdr->a3.a2);
311 	} else {
312 		payload_offset = WLAN_HDR_A4_LEN;
313 		if (payload_length < WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN) {
314 			netdev_err(netdev, "A4 frame too short!\n");
315 			return 1;
316 		}
317 		payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN);
318 		ether_addr_copy(daddr, w_hdr->a4.a3);
319 		ether_addr_copy(saddr, w_hdr->a4.a4);
320 	}
321 
322 	/* perform de-wep if necessary.. */
323 	if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && WLAN_GET_FC_ISWEP(fc)
324 	    && (wlandev->hostwep & HOSTWEP_DECRYPT)) {
325 		if (payload_length <= 8) {
326 			netdev_err(netdev,
327 				   "WEP frame too short (%u).\n", skb->len);
328 			return 1;
329 		}
330 		foo = wep_decrypt(wlandev, skb->data + payload_offset + 4,
331 				       payload_length - 8, -1,
332 				       skb->data + payload_offset,
333 				       skb->data + payload_offset +
334 				       payload_length - 4);
335 		if (foo) {
336 			/* de-wep failed, drop skb. */
337 			pr_debug("Host de-WEP failed, dropping frame (%d).\n",
338 				 foo);
339 			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 
353 	e_hdr = (struct wlan_ethhdr *) (skb->data + payload_offset);
354 
355 	e_llc = (struct wlan_llc *) (skb->data + payload_offset);
356 	e_snap =
357 	    (struct wlan_snap *) (skb->data + payload_offset +
358 		sizeof(struct wlan_llc));
359 
360 	/* Test for the various encodings */
361 	if ((payload_length >= sizeof(struct wlan_ethhdr)) &&
362 	    (e_llc->dsap != 0xaa || e_llc->ssap != 0xaa) &&
363 	    ((!ether_addr_equal_unaligned(daddr, e_hdr->daddr)) ||
364 	     (!ether_addr_equal_unaligned(saddr, e_hdr->saddr)))) {
365 		pr_debug("802.3 ENCAP len: %d\n", payload_length);
366 		/* 802.3 Encapsulated */
367 		/* Test for an overlength frame */
368 		if (payload_length > (netdev->mtu + ETH_HLEN)) {
369 			/* A bogus length ethfrm has been encap'd. */
370 			/* Is someone trying an oflow attack? */
371 			netdev_err(netdev, "ENCAP frame too large (%d > %d)\n",
372 			       payload_length, netdev->mtu + ETH_HLEN);
373 			return 1;
374 		}
375 
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 
381 	} else if ((payload_length >= sizeof(struct wlan_llc) +
382 		sizeof(struct wlan_snap))
383 		&& (e_llc->dsap == 0xaa)
384 		&& (e_llc->ssap == 0xaa)
385 		&& (e_llc->ctl == 0x03)
386 		   &&
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))) {
392 		pr_debug("SNAP+RFC1042 len: %d\n", payload_length);
393 		/* it's a SNAP + RFC1042 frame && protocol is in STT */
394 		/* build 802.3 + RFC1042 */
395 
396 		/* Test for an overlength frame */
397 		if (payload_length > netdev->mtu) {
398 			/* A bogus length ethfrm has been sent. */
399 			/* Is someone trying an oflow attack? */
400 			netdev_err(netdev, "SNAP frame too large (%d > %d)\n",
401 			       payload_length, netdev->mtu);
402 			return 1;
403 		}
404 
405 		/* chop 802.11 header from skb. */
406 		skb_pull(skb, payload_offset);
407 
408 		/* create 802.3 header at beginning of skb. */
409 		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);
412 		e_hdr->type = htons(payload_length);
413 
414 		/* chop off the 802.11 CRC */
415 		skb_trim(skb, skb->len - WLAN_CRC_LEN);
416 
417 	} else if ((payload_length >= sizeof(struct wlan_llc) +
418 		sizeof(struct wlan_snap))
419 		&& (e_llc->dsap == 0xaa)
420 		&& (e_llc->ssap == 0xaa)
421 		&& (e_llc->ctl == 0x03)) {
422 		pr_debug("802.1h/RFC1042 len: %d\n", payload_length);
423 		/* it's an 802.1h frame || (an RFC1042 && protocol not in STT)
424 		   build a DIXII + RFC894 */
425 
426 		/* Test for an overlength frame */
427 		if ((payload_length - sizeof(struct wlan_llc) -
428 			sizeof(struct wlan_snap))
429 			> netdev->mtu) {
430 			/* A bogus length ethfrm has been sent. */
431 			/* Is someone trying an oflow attack? */
432 			netdev_err(netdev, "DIXII frame too large (%ld > %d)\n",
433 			       (long int)(payload_length -
434 					sizeof(struct wlan_llc) -
435 					sizeof(struct wlan_snap)), netdev->mtu);
436 			return 1;
437 		}
438 
439 		/* chop 802.11 header from skb. */
440 		skb_pull(skb, payload_offset);
441 
442 		/* chop llc header from skb. */
443 		skb_pull(skb, sizeof(struct wlan_llc));
444 
445 		/* chop snap header from skb. */
446 		skb_pull(skb, sizeof(struct wlan_snap));
447 
448 		/* create 802.3 header at beginning of skb. */
449 		e_hdr = (struct wlan_ethhdr *)skb_push(skb, ETH_HLEN);
450 		e_hdr->type = e_snap->type;
451 		ether_addr_copy(e_hdr->daddr, daddr);
452 		ether_addr_copy(e_hdr->saddr, saddr);
453 
454 		/* chop off the 802.11 CRC */
455 		skb_trim(skb, skb->len - WLAN_CRC_LEN);
456 	} else {
457 		pr_debug("NON-ENCAP len: %d\n", payload_length);
458 		/* 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 
463 		/* Test for an overlength frame */
464 		if (payload_length > netdev->mtu) {
465 			/* A bogus length ethfrm has been sent. */
466 			/* Is someone trying an oflow attack? */
467 			netdev_err(netdev, "OTHER frame too large (%d > %d)\n",
468 			       payload_length, netdev->mtu);
469 			return 1;
470 		}
471 
472 		/* Chop off the 802.11 header. */
473 		skb_pull(skb, payload_offset);
474 
475 		/* create 802.3 header at beginning of skb. */
476 		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);
479 		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 
486 	/*
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 	 */
495 	skb->protocol = eth_type_trans(skb, netdev);
496 
497 	/* jkriegl: process signal and noise as set in hfa384x_int_rx() */
498 	/* jkriegl: only process signal/noise if requested by iwspy */
499 	if (wlandev->spy_number)
500 		orinoco_spy_gather(wlandev, eth_hdr(skb)->h_source,
501 				   P80211SKB_RXMETA(skb));
502 
503 	/* Free the metadata */
504 	p80211skb_rxmeta_detach(skb);
505 
506 	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:
516 *	proto	protocol number (in host order) to search for.
517 *
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 ----------------------------------------------------------------*/
p80211_stt_findproto(u16 proto)525 int p80211_stt_findproto(u16 proto)
526 {
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
530 	   need this to match the CMAC's way of doing things.
531 	   Need to do some testing to confirm.
532 	 */
533 
534 	if (proto == ETH_P_AARP)	/* APPLETALK */
535 		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 ----------------------------------------------------------------*/
p80211skb_rxmeta_detach(struct sk_buff * skb)555 void p80211skb_rxmeta_detach(struct sk_buff *skb)
556 {
557 	struct p80211_rxmeta *rxmeta;
558 	struct p80211_frmmeta *frmmeta;
559 
560 	/* Sanity checks */
561 	if (skb == NULL) {	/* bad skb */
562 		pr_debug("Called w/ null skb.\n");
563 		return;
564 	}
565 	frmmeta = P80211SKB_FRMMETA(skb);
566 	if (frmmeta == NULL) {	/* no magic */
567 		pr_debug("Called w/ bad frmmeta magic.\n");
568 		return;
569 	}
570 	rxmeta = frmmeta->rx;
571 	if (rxmeta == NULL) {	/* bad meta ptr */
572 		pr_debug("Called w/ bad rxmeta ptr.\n");
573 		return;
574 	}
575 
576 	/* Free rxmeta */
577 	kfree(rxmeta);
578 
579 	/* Clear skb->cb */
580 	memset(skb->cb, 0, sizeof(skb->cb));
581 }
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 ----------------------------------------------------------------*/
p80211skb_rxmeta_attach(struct wlandevice * wlandev,struct sk_buff * skb)599 int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb)
600 {
601 	int result = 0;
602 	struct p80211_rxmeta *rxmeta;
603 	struct p80211_frmmeta *frmmeta;
604 
605 	/* If these already have metadata, we error out! */
606 	if (P80211SKB_RXMETA(skb) != NULL) {
607 		netdev_err(wlandev->netdev,
608 			   "%s: RXmeta already attached!\n", wlandev->name);
609 		result = 0;
610 		goto exit;
611 	}
612 
613 	/* Allocate the rxmeta */
614 	rxmeta = kzalloc(sizeof(struct p80211_rxmeta), GFP_ATOMIC);
615 
616 	if (rxmeta == NULL) {
617 		netdev_err(wlandev->netdev,
618 			   "%s: Failed to allocate rxmeta.\n", wlandev->name);
619 		result = 1;
620 		goto exit;
621 	}
622 
623 	/* Initialize the rxmeta */
624 	rxmeta->wlandev = wlandev;
625 	rxmeta->hosttime = jiffies;
626 
627 	/* Overlay a frmmeta_t onto skb->cb */
628 	memset(skb->cb, 0, sizeof(struct p80211_frmmeta));
629 	frmmeta = (struct p80211_frmmeta *) (skb->cb);
630 	frmmeta->magic = P80211_FRMMETA_MAGIC;
631 	frmmeta->rx = rxmeta;
632 exit:
633 	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 ----------------------------------------------------------------*/
p80211skb_free(struct wlandevice * wlandev,struct sk_buff * skb)652 void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb)
653 {
654 	struct p80211_frmmeta *meta;
655 
656 	meta = P80211SKB_FRMMETA(skb);
657 	if (meta && meta->rx)
658 		p80211skb_rxmeta_detach(skb);
659 	else
660 		netdev_err(wlandev->netdev,
661 			   "Freeing an skb (%p) w/ no frmmeta.\n", skb);
662 	dev_kfree_skb(skb);
663 }
664