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

📄 rx.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz> * Copyright 2007	Johannes Berg <johannes@sipsolutions.net> * * 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. */#include <linux/kernel.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/rcupdate.h>#include <net/mac80211.h>#include <net/ieee80211_radiotap.h>#include "ieee80211_i.h"#include "ieee80211_led.h"#include "wep.h"#include "wpa.h"#include "tkip.h"#include "wme.h"/* * monitor mode reception * * This function cleans up the SKB, i.e. it removes all the stuff * only useful for monitoring. */static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,					   struct sk_buff *skb,					   int rtap_len){	skb_pull(skb, rtap_len);	if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) {		if (likely(skb->len > FCS_LEN))			skb_trim(skb, skb->len - FCS_LEN);		else {			/* driver bug */			WARN_ON(1);			dev_kfree_skb(skb);			skb = NULL;		}	}	return skb;}static inline int should_drop_frame(struct ieee80211_rx_status *status,				    struct sk_buff *skb,				    int present_fcs_len,				    int radiotap_len){	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;	if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))		return 1;	if (unlikely(skb->len < 16 + present_fcs_len + radiotap_len))		return 1;	if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) ==			cpu_to_le16(IEEE80211_FTYPE_CTL))		return 1;	return 0;}/* * This function copies a received frame to all monitor interfaces and * returns a cleaned-up SKB that no longer includes the FCS nor the * radiotap header the driver might have added. */static struct sk_buff *ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,		     struct ieee80211_rx_status *status){	struct ieee80211_sub_if_data *sdata;	struct ieee80211_rate *rate;	int needed_headroom = 0;	struct ieee80211_rtap_hdr {		struct ieee80211_radiotap_header hdr;		u8 flags;		u8 rate;		__le16 chan_freq;		__le16 chan_flags;		u8 antsignal;		u8 padding_for_rxflags;		__le16 rx_flags;	} __attribute__ ((packed)) *rthdr;	struct sk_buff *skb, *skb2;	struct net_device *prev_dev = NULL;	int present_fcs_len = 0;	int rtap_len = 0;	/*	 * First, we may need to make a copy of the skb because	 *  (1) we need to modify it for radiotap (if not present), and	 *  (2) the other RX handlers will modify the skb we got.	 *	 * We don't need to, of course, if we aren't going to return	 * the SKB because it has a bad FCS/PLCP checksum.	 */	if (status->flag & RX_FLAG_RADIOTAP)		rtap_len = ieee80211_get_radiotap_len(origskb->data);	else		needed_headroom = sizeof(*rthdr);	if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)		present_fcs_len = FCS_LEN;	if (!local->monitors) {		if (should_drop_frame(status, origskb, present_fcs_len,				      rtap_len)) {			dev_kfree_skb(origskb);			return NULL;		}		return remove_monitor_info(local, origskb, rtap_len);	}	if (should_drop_frame(status, origskb, present_fcs_len, rtap_len)) {		/* only need to expand headroom if necessary */		skb = origskb;		origskb = NULL;		/*		 * This shouldn't trigger often because most devices have an		 * RX header they pull before we get here, and that should		 * be big enough for our radiotap information. We should		 * probably export the length to drivers so that we can have		 * them allocate enough headroom to start with.		 */		if (skb_headroom(skb) < needed_headroom &&		    pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) {			dev_kfree_skb(skb);			return NULL;		}	} else {		/*		 * Need to make a copy and possibly remove radiotap header		 * and FCS from the original.		 */		skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC);		origskb = remove_monitor_info(local, origskb, rtap_len);		if (!skb)			return origskb;	}	/* if necessary, prepend radiotap information */	if (!(status->flag & RX_FLAG_RADIOTAP)) {		rthdr = (void *) skb_push(skb, sizeof(*rthdr));		memset(rthdr, 0, sizeof(*rthdr));		rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));		rthdr->hdr.it_present =			cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |				    (1 << IEEE80211_RADIOTAP_RATE) |				    (1 << IEEE80211_RADIOTAP_CHANNEL) |				    (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |				    (1 << IEEE80211_RADIOTAP_RX_FLAGS));		rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ?			       IEEE80211_RADIOTAP_F_FCS : 0;		/* FIXME: when radiotap gets a 'bad PLCP' flag use it here */		rthdr->rx_flags = 0;		if (status->flag &		    (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))			rthdr->rx_flags |=				cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);		rate = ieee80211_get_rate(local, status->phymode,					  status->rate);		if (rate)			rthdr->rate = rate->rate / 5;		rthdr->chan_freq = cpu_to_le16(status->freq);		if (status->phymode == MODE_IEEE80211A)			rthdr->chan_flags =				cpu_to_le16(IEEE80211_CHAN_OFDM |					    IEEE80211_CHAN_5GHZ);		else			rthdr->chan_flags =				cpu_to_le16(IEEE80211_CHAN_DYN |					    IEEE80211_CHAN_2GHZ);		rthdr->antsignal = status->ssi;	}	skb_set_mac_header(skb, 0);	skb->ip_summed = CHECKSUM_UNNECESSARY;	skb->pkt_type = PACKET_OTHERHOST;	skb->protocol = htons(ETH_P_802_2);	list_for_each_entry_rcu(sdata, &local->interfaces, list) {		if (!netif_running(sdata->dev))			continue;		if (sdata->type != IEEE80211_IF_TYPE_MNTR)			continue;		if (prev_dev) {			skb2 = skb_clone(skb, GFP_ATOMIC);			if (skb2) {				skb2->dev = prev_dev;				netif_rx(skb2);			}		}		prev_dev = sdata->dev;		sdata->dev->stats.rx_packets++;		sdata->dev->stats.rx_bytes += skb->len;	}	if (prev_dev) {		skb->dev = prev_dev;		netif_rx(skb);	} else		dev_kfree_skb(skb);	return origskb;}/* pre-rx handlers * * these don't have dev/sdata fields in the rx data * The sta value should also not be used because it may * be NULL even though a STA (in IBSS mode) will be added. */static ieee80211_txrx_resultieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx){	u8 *data = rx->skb->data;	int tid;	/* does the frame have a qos control field? */	if (WLAN_FC_IS_QOS_DATA(rx->fc)) {		u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN;		/* frame has qos control */		tid = qc[0] & QOS_CONTROL_TID_MASK;	} else {		if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {			/* Separate TID for management frames */			tid = NUM_RX_DATA_QUEUES - 1;		} else {			/* no qos control present */			tid = 0; /* 802.1d - Best Effort */		}	}	I802_DEBUG_INC(rx->local->wme_rx_queue[tid]);	/* only a debug counter, sta might not be assigned properly yet */	if (rx->sta)		I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);	rx->u.rx.queue = tid;	/* Set skb->priority to 1d tag if highest order bit of TID is not set.	 * For now, set skb->priority to 0 for other cases. */	rx->skb->priority = (tid > 7) ? 0 : tid;	return TXRX_CONTINUE;}static ieee80211_txrx_resultieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx){	struct ieee80211_local *local = rx->local;	struct sk_buff *skb = rx->skb;	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;	u32 load = 0, hdrtime;	struct ieee80211_rate *rate;	struct ieee80211_hw_mode *mode = local->hw.conf.mode;	int i;	/* Estimate total channel use caused by this frame */	if (unlikely(mode->num_rates < 0))		return TXRX_CONTINUE;	rate = &mode->rates[0];	for (i = 0; i < mode->num_rates; i++) {		if (mode->rates[i].val == rx->u.rx.status->rate) {			rate = &mode->rates[i];			break;		}	}	/* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,	 * 1 usec = 1/8 * (1080 / 10) = 13.5 */	if (mode->mode == MODE_IEEE80211A ||	    (mode->mode == MODE_IEEE80211G &&	     rate->flags & IEEE80211_RATE_ERP))		hdrtime = CHAN_UTIL_HDR_SHORT;	else		hdrtime = CHAN_UTIL_HDR_LONG;	load = hdrtime;	if (!is_multicast_ether_addr(hdr->addr1))		load += hdrtime;	load += skb->len * rate->rate_inv;	/* Divide channel_use by 8 to avoid wrapping around the counter */	load >>= CHAN_UTIL_SHIFT;	local->channel_use_raw += load;	rx->u.rx.load = load;	return TXRX_CONTINUE;}ieee80211_rx_handler ieee80211_rx_pre_handlers[] ={	ieee80211_rx_h_parse_qos,	ieee80211_rx_h_load_stats,	NULL};/* rx handlers */static ieee80211_txrx_resultieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx){	if (rx->sta)		rx->sta->channel_use_raw += rx->u.rx.load;	rx->sdata->channel_use_raw += rx->u.rx.load;	return TXRX_CONTINUE;}static ieee80211_txrx_resultieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx){	struct ieee80211_local *local = rx->local;	struct sk_buff *skb = rx->skb;	if (unlikely(local->sta_scanning != 0)) {		ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);		return TXRX_QUEUED;	}	if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) {		/* scanning finished during invoking of handlers */		I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);		return TXRX_DROP;	}	return TXRX_CONTINUE;}static ieee80211_txrx_resultieee80211_rx_h_check(struct ieee80211_txrx_data *rx){	struct ieee80211_hdr *hdr;	hdr = (struct ieee80211_hdr *) rx->skb->data;	/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */	if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {		if (unlikely(rx->fc & IEEE80211_FCTL_RETRY &&			     rx->sta->last_seq_ctrl[rx->u.rx.queue] ==			     hdr->seq_ctrl)) {			if (rx->flags & IEEE80211_TXRXD_RXRA_MATCH) {				rx->local->dot11FrameDuplicateCount++;				rx->sta->num_duplicates++;			}			return TXRX_DROP;		} else			rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl;	}	if (unlikely(rx->skb->len < 16)) {		I802_DEBUG_INC(rx->local->rx_handlers_drop_short);		return TXRX_DROP;	}	if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))		rx->skb->pkt_type = PACKET_OTHERHOST;	else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0)		rx->skb->pkt_type = PACKET_HOST;	else if (is_multicast_ether_addr(hdr->addr1)) {		if (is_broadcast_ether_addr(hdr->addr1))			rx->skb->pkt_type = PACKET_BROADCAST;		else			rx->skb->pkt_type = PACKET_MULTICAST;	} else		rx->skb->pkt_type = PACKET_OTHERHOST;	/* Drop disallowed frame classes based on STA auth/assoc state;	 * IEEE 802.11, Chap 5.5.	 *	 * 80211.o does filtering only based on association state, i.e., it	 * drops Class 3 frames from not associated stations. hostapd sends	 * deauth/disassoc frames when needed. In addition, hostapd is	 * responsible for filtering on both auth and assoc states.	 */	if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||		      ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&		       (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&		     rx->sdata->type != IEEE80211_IF_TYPE_IBSS &&		     (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {		if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&		     !(rx->fc & IEEE80211_FCTL_TODS) &&		     (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)		    || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {			/* Drop IBSS frames and frames for other hosts			 * silently. */			return TXRX_DROP;		}		return TXRX_DROP;	}	return TXRX_CONTINUE;}static ieee80211_txrx_resultieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx){	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;	int keyidx;	int hdrlen;	ieee80211_txrx_result result = TXRX_DROP;	struct ieee80211_key *stakey = NULL;	/*	 * Key selection 101	 *	 * There are three types of keys:	 *  - GTK (group keys)	 *  - PTK (pairwise keys)	 *  - STK (station-to-station pairwise keys)	 *	 * When selecting a key, we have to distinguish between multicast	 * (including broadcast) and unicast frames, the latter can only	 * use PTKs and STKs while the former always use GTKs. Unless, of	 * course, actual WEP keys ("pre-RSNA") are used, then unicast	 * frames can also use key indizes like GTKs. Hence, if we don't	 * have a PTK/STK we check the key index for a WEP key.	 *	 * Note that in a regular BSS, multicast frames are sent by the	 * AP only, associated stations unicast the frame to the AP first	 * which then multicasts it on their behalf.	 *	 * There is also a slight problem in IBSS mode: GTKs are negotiated	 * with each station, that is something we don't currently handle.	 * The spec seems to expect that one negotiates the same key with	 * every station but there's no such requirement; VLANs could be	 * possible.	 */	if (!(rx->fc & IEEE80211_FCTL_PROTECTED))		return TXRX_CONTINUE;	/*	 * No point in finding a key and decrypting if the frame is neither	 * addressed to us nor a multicast frame.	 */	if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))		return TXRX_CONTINUE;	if (rx->sta)		stakey = rcu_dereference(rx->sta->key);	if (!is_multicast_ether_addr(hdr->addr1) && stakey) {		rx->key = stakey;	} else {		/*		 * The device doesn't give us the IV so we won't be		 * able to look up the key. That's ok though, we		 * don't need to decrypt the frame, we just won't		 * be able to keep statistics accurate.		 * Except for key threshold notifications, should		 * we somehow allow the driver to tell us which key		 * the hardware used if this flag is set?		 */		if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&		    (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))			return TXRX_CONTINUE;		hdrlen = ieee80211_get_hdrlen(rx->fc);		if (rx->skb->len < 8 + hdrlen)			return TXRX_DROP; /* TODO: count this? */		/*		 * no need to call ieee80211_wep_get_keyidx,		 * it verifies a bunch of things we've done already		 */		keyidx = rx->skb->data[hdrlen + 3] >> 6;		rx->key = rcu_dereference(rx->sdata->keys[keyidx]);		/*		 * RSNA-protected unicast frames should always be sent with		 * pairwise or station-to-station keys, but for WEP we allow		 * using a key index as well.		 */		if (rx->key && rx->key->conf.alg != ALG_WEP &&		    !is_multicast_ether_addr(hdr->addr1))			rx->key = NULL;	}	if (rx->key) {		rx->key->tx_rx_count++;		/* TODO: add threshold stuff again */	} else {#ifdef CONFIG_MAC80211_DEBUG		if (net_ratelimit())			printk(KERN_DEBUG "%s: RX protected frame,"			       " but have no key\n", rx->dev->name);#endif /* CONFIG_MAC80211_DEBUG */		return TXRX_DROP;	}	/* Check for weak IVs if possible */	if (rx->sta && rx->key->conf.alg == ALG_WEP &&	    ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&	    (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) ||	     !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) &&	    ieee80211_wep_is_weak_iv(rx->skb, rx->key))		rx->sta->wep_weak_iv_count++;	switch (rx->key->conf.alg) {	case ALG_WEP:		result = ieee80211_crypto_wep_decrypt(rx);		break;

⌨️ 快捷键说明

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