⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ieee80211_rx.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Original code based Host AP (software wireless LAN access point) driver * for Intersil Prism2/2.5/3 - hostap.o module, common routines * * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen * <j@w1.fi> * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> * Copyright (c) 2004-2005, Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See README and COPYING for * more details. */#include <linux/compiler.h>#include <linux/errno.h>#include <linux/if_arp.h>#include <linux/in6.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/netdevice.h>#include <linux/proc_fs.h>#include <linux/skbuff.h>#include <linux/slab.h>#include <linux/tcp.h>#include <linux/types.h>#include <linux/wireless.h>#include <linux/etherdevice.h>#include <asm/uaccess.h>#include <linux/ctype.h>#include <net/ieee80211.h>static void ieee80211_monitor_rx(struct ieee80211_device *ieee,					struct sk_buff *skb,					struct ieee80211_rx_stats *rx_stats){	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;	u16 fc = le16_to_cpu(hdr->frame_ctl);	skb->dev = ieee->dev;	skb_reset_mac_header(skb);	skb_pull(skb, ieee80211_get_hdrlen(fc));	skb->pkt_type = PACKET_OTHERHOST;	skb->protocol = __constant_htons(ETH_P_80211_RAW);	memset(skb->cb, 0, sizeof(skb->cb));	netif_rx(skb);}/* Called only as a tasklet (software IRQ) */static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct							      ieee80211_device							      *ieee,							      unsigned int seq,							      unsigned int frag,							      u8 * src,							      u8 * dst){	struct ieee80211_frag_entry *entry;	int i;	for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) {		entry = &ieee->frag_cache[i];		if (entry->skb != NULL &&		    time_after(jiffies, entry->first_frag_time + 2 * HZ)) {			IEEE80211_DEBUG_FRAG("expiring fragment cache entry "					     "seq=%u last_frag=%u\n",					     entry->seq, entry->last_frag);			dev_kfree_skb_any(entry->skb);			entry->skb = NULL;		}		if (entry->skb != NULL && entry->seq == seq &&		    (entry->last_frag + 1 == frag || frag == -1) &&		    !compare_ether_addr(entry->src_addr, src) &&		    !compare_ether_addr(entry->dst_addr, dst))			return entry;	}	return NULL;}/* Called only as a tasklet (software IRQ) */static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee,						struct ieee80211_hdr_4addr *hdr){	struct sk_buff *skb = NULL;	u16 sc;	unsigned int frag, seq;	struct ieee80211_frag_entry *entry;	sc = le16_to_cpu(hdr->seq_ctl);	frag = WLAN_GET_SEQ_FRAG(sc);	seq = WLAN_GET_SEQ_SEQ(sc);	if (frag == 0) {		/* Reserve enough space to fit maximum frame length */		skb = dev_alloc_skb(ieee->dev->mtu +				    sizeof(struct ieee80211_hdr_4addr) +				    8 /* LLC */  +				    2 /* alignment */  +				    8 /* WEP */  + ETH_ALEN /* WDS */ );		if (skb == NULL)			return NULL;		entry = &ieee->frag_cache[ieee->frag_next_idx];		ieee->frag_next_idx++;		if (ieee->frag_next_idx >= IEEE80211_FRAG_CACHE_LEN)			ieee->frag_next_idx = 0;		if (entry->skb != NULL)			dev_kfree_skb_any(entry->skb);		entry->first_frag_time = jiffies;		entry->seq = seq;		entry->last_frag = frag;		entry->skb = skb;		memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);		memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);	} else {		/* received a fragment of a frame for which the head fragment		 * should have already been received */		entry = ieee80211_frag_cache_find(ieee, seq, frag, hdr->addr2,						  hdr->addr1);		if (entry != NULL) {			entry->last_frag = frag;			skb = entry->skb;		}	}	return skb;}/* Called only as a tasklet (software IRQ) */static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,					   struct ieee80211_hdr_4addr *hdr){	u16 sc;	unsigned int seq;	struct ieee80211_frag_entry *entry;	sc = le16_to_cpu(hdr->seq_ctl);	seq = WLAN_GET_SEQ_SEQ(sc);	entry = ieee80211_frag_cache_find(ieee, seq, -1, hdr->addr2,					  hdr->addr1);	if (entry == NULL) {		IEEE80211_DEBUG_FRAG("could not invalidate fragment cache "				     "entry (seq=%u)\n", seq);		return -1;	}	entry->skb = NULL;	return 0;}#ifdef NOT_YET/* ieee80211_rx_frame_mgtmt * * Responsible for handling management control frames * * Called by ieee80211_rx */static intieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,			struct ieee80211_rx_stats *rx_stats, u16 type,			u16 stype){	if (ieee->iw_mode == IW_MODE_MASTER) {		printk(KERN_DEBUG "%s: Master mode not yet suppported.\n",		       ieee->dev->name);		return 0;/*  hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr_4addr *)  skb->data);*/	}	if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) {		if (stype == WLAN_FC_STYPE_BEACON &&		    ieee->iw_mode == IW_MODE_MASTER) {			struct sk_buff *skb2;			/* Process beacon frames also in kernel driver to			 * update STA(AP) table statistics */			skb2 = skb_clone(skb, GFP_ATOMIC);			if (skb2)				hostap_rx(skb2->dev, skb2, rx_stats);		}		/* send management frames to the user space daemon for		 * processing */		ieee->apdevstats.rx_packets++;		ieee->apdevstats.rx_bytes += skb->len;		prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT);		return 0;	}	if (ieee->iw_mode == IW_MODE_MASTER) {		if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) {			printk(KERN_DEBUG "%s: unknown management frame "			       "(type=0x%02x, stype=0x%02x) dropped\n",			       skb->dev->name, type, stype);			return -1;		}		hostap_rx(skb->dev, skb, rx_stats);		return 0;	}	printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame "	       "received in non-Host AP mode\n", skb->dev->name);	return -1;}#endif/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation *//* Ethernet-II snap header (RFC1042 for most EtherTypes) */static unsigned char rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */static unsigned char bridge_tunnel_header[] =    { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };/* No encapsulation header if EtherType < 0x600 (=length) *//* Called by ieee80211_rx_frame_decrypt */static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,				    struct sk_buff *skb){	struct net_device *dev = ieee->dev;	u16 fc, ethertype;	struct ieee80211_hdr_3addr *hdr;	u8 *pos;	if (skb->len < 24)		return 0;	hdr = (struct ieee80211_hdr_3addr *)skb->data;	fc = le16_to_cpu(hdr->frame_ctl);	/* check that the frame is unicast frame to us */	if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==	    IEEE80211_FCTL_TODS &&	    !compare_ether_addr(hdr->addr1, dev->dev_addr) &&	    !compare_ether_addr(hdr->addr3, dev->dev_addr)) {		/* ToDS frame with own addr BSSID and DA */	} else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==		   IEEE80211_FCTL_FROMDS &&		   !compare_ether_addr(hdr->addr1, dev->dev_addr)) {		/* FromDS frame with own addr as DA */	} else		return 0;	if (skb->len < 24 + 8)		return 0;	/* check for port access entity Ethernet type */	pos = skb->data + 24;	ethertype = (pos[6] << 8) | pos[7];	if (ethertype == ETH_P_PAE)		return 1;	return 0;}/* Called only as a tasklet (software IRQ), by ieee80211_rx */static intieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,			   struct ieee80211_crypt_data *crypt){	struct ieee80211_hdr_3addr *hdr;	int res, hdrlen;	DECLARE_MAC_BUF(mac);	if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)		return 0;	hdr = (struct ieee80211_hdr_3addr *)skb->data;	hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));	atomic_inc(&crypt->refcnt);	res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);	atomic_dec(&crypt->refcnt);	if (res < 0) {		IEEE80211_DEBUG_DROP("decryption failed (SA=%s"				     ") res=%d\n", print_mac(mac, hdr->addr2), res);		if (res == -2)			IEEE80211_DEBUG_DROP("Decryption failed ICV "					     "mismatch (key %d)\n",					     skb->data[hdrlen + 3] >> 6);		ieee->ieee_stats.rx_discards_undecryptable++;		return -1;	}	return res;}/* Called only as a tasklet (software IRQ), by ieee80211_rx */static intieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee,				struct sk_buff *skb, int keyidx,				struct ieee80211_crypt_data *crypt){	struct ieee80211_hdr_3addr *hdr;	int res, hdrlen;	DECLARE_MAC_BUF(mac);	if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)		return 0;	hdr = (struct ieee80211_hdr_3addr *)skb->data;	hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));	atomic_inc(&crypt->refcnt);	res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);	atomic_dec(&crypt->refcnt);	if (res < 0) {		printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"		       " (SA=%s keyidx=%d)\n",		       ieee->dev->name, print_mac(mac, hdr->addr2), keyidx);		return -1;	}	return 0;}/* All received frames are sent to this function. @skb contains the frame in * IEEE 802.11 format, i.e., in the format it was sent over air. * This function is called only as a tasklet (software IRQ). */int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,		 struct ieee80211_rx_stats *rx_stats){	struct net_device *dev = ieee->dev;	struct ieee80211_hdr_4addr *hdr;	size_t hdrlen;	u16 fc, type, stype, sc;	struct net_device_stats *stats;	unsigned int frag;	u8 *payload;	u16 ethertype;#ifdef NOT_YET	struct net_device *wds = NULL;	struct sk_buff *skb2 = NULL;	struct net_device *wds = NULL;	int frame_authorized = 0;	int from_assoc_ap = 0;	void *sta = NULL;#endif	u8 dst[ETH_ALEN];	u8 src[ETH_ALEN];	struct ieee80211_crypt_data *crypt = NULL;	int keyidx = 0;	int can_be_decrypted = 0;	DECLARE_MAC_BUF(mac);	hdr = (struct ieee80211_hdr_4addr *)skb->data;	stats = &ieee->stats;	if (skb->len < 10) {		printk(KERN_INFO "%s: SKB length < 10\n", dev->name);		goto rx_dropped;	}	fc = le16_to_cpu(hdr->frame_ctl);	type = WLAN_FC_GET_TYPE(fc);	stype = WLAN_FC_GET_STYPE(fc);	sc = le16_to_cpu(hdr->seq_ctl);	frag = WLAN_GET_SEQ_FRAG(sc);	hdrlen = ieee80211_get_hdrlen(fc);	if (skb->len < hdrlen) {		printk(KERN_INFO "%s: invalid SKB length %d\n",			dev->name, skb->len);		goto rx_dropped;	}	/* Put this code here so that we avoid duplicating it in all	 * Rx paths. - Jean II */#ifdef CONFIG_WIRELESS_EXT#ifdef IW_WIRELESS_SPY		/* defined in iw_handler.h */	/* If spy monitoring on */	if (ieee->spy_data.spy_number > 0) {		struct iw_quality wstats;		wstats.updated = 0;		if (rx_stats->mask & IEEE80211_STATMASK_RSSI) {			wstats.level = rx_stats->rssi;			wstats.updated |= IW_QUAL_LEVEL_UPDATED;		} else			wstats.updated |= IW_QUAL_LEVEL_INVALID;		if (rx_stats->mask & IEEE80211_STATMASK_NOISE) {			wstats.noise = rx_stats->noise;			wstats.updated |= IW_QUAL_NOISE_UPDATED;		} else			wstats.updated |= IW_QUAL_NOISE_INVALID;		if (rx_stats->mask & IEEE80211_STATMASK_SIGNAL) {			wstats.qual = rx_stats->signal;			wstats.updated |= IW_QUAL_QUAL_UPDATED;		} else			wstats.updated |= IW_QUAL_QUAL_INVALID;		/* Update spy records */		wireless_spy_update(ieee->dev, hdr->addr2, &wstats);	}#endif				/* IW_WIRELESS_SPY */#endif				/* CONFIG_WIRELESS_EXT */#ifdef NOT_YET	hostap_update_rx_stats(local->ap, hdr, rx_stats);#endif	if (ieee->iw_mode == IW_MODE_MONITOR) {		stats->rx_packets++;		stats->rx_bytes += skb->len;		ieee80211_monitor_rx(ieee, skb, rx_stats);		return 1;	}	can_be_decrypted = (is_multicast_ether_addr(hdr->addr1) ||			    is_broadcast_ether_addr(hdr->addr2)) ?	    ieee->host_mc_decrypt : ieee->host_decrypt;	if (can_be_decrypted) {		if (skb->len >= hdrlen + 3) {			/* Top two-bits of byte 3 are the key index */			keyidx = skb->data[hdrlen + 3] >> 6;		}		/* ieee->crypt[] is WEP_KEY (4) in length.  Given that keyidx		 * is only allowed 2-bits of storage, no value of keyidx can		 * be provided via above code that would result in keyidx		 * being out of range */		crypt = ieee->crypt[keyidx];#ifdef NOT_YET		sta = NULL;		/* Use station specific key to override default keys if the		 * receiver address is a unicast address ("individual RA"). If		 * bcrx_sta_key parameter is set, station specific key is used		 * even with broad/multicast targets (this is against IEEE		 * 802.11, but makes it easier to use different keys with		 * stations that do not support WEP key mapping). */		if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key)			(void)hostap_handle_sta_crypto(local, hdr, &crypt,						       &sta);#endif		/* allow NULL decrypt to indicate an station specific override		 * for default encryption */		if (crypt && (crypt->ops == NULL ||

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -