📄 ieee80211_rx.c
字号:
/* * 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 + -