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

📄 ieee80211_input.c

📁 Linux下wifi实现
💻 C
📖 第 1 页 / 共 5 页
字号:
/*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: ieee80211_input.c 1676 2006-07-06 03:23:08Z brian $ */#ifndef EXPORT_SYMTAB#define	EXPORT_SYMTAB#endif/* * IEEE 802.11 input handling. */#include <linux/config.h>#include <linux/version.h>#include <linux/module.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/random.h>#include <linux/if_vlan.h>#include <net/iw_handler.h> /* wireless_send_event(..) */#include <linux/wireless.h> /* SIOCGIWTHRSPY */#include <linux/if_arp.h> /* ARPHRD_ETHER */#include "if_llc.h"#include "if_ethersubr.h"#include "if_media.h"#include "if_athproto.h"#include <net80211/ieee80211_var.h>#ifdef IEEE80211_DEBUG/* * Decide if a received management frame should be * printed when debugging is enabled.  This filters some * of the less interesting frames that come frequently * (e.g. beacons). */static __inline intdoprint(struct ieee80211vap *vap, int subtype){	switch (subtype) {	case IEEE80211_FC0_SUBTYPE_BEACON:		return (vap->iv_ic->ic_flags & IEEE80211_F_SCAN);	case IEEE80211_FC0_SUBTYPE_PROBE_REQ:		return (vap->iv_opmode == IEEE80211_M_IBSS);	}	return 1;}/* * Emit a debug message about discarding a frame or information * element.  One format is for extracting the mac address from * the frame header; the other is for when a header is not * available or otherwise appropriate. */#define	IEEE80211_DISCARD(_vap, _m, _wh, _type, _fmt, ...) do {		\	if ((_vap)->iv_debug & (_m))					\		ieee80211_discard_frame(_vap, _wh, _type, _fmt, __VA_ARGS__);\} while (0)#define	IEEE80211_DISCARD_IE(_vap, _m, _wh, _type, _fmt, ...) do {	\	if ((_vap)->iv_debug & (_m))					\		ieee80211_discard_ie(_vap, _wh, _type, _fmt, __VA_ARGS__);\} while (0)#define	IEEE80211_DISCARD_MAC(_vap, _m, _mac, _type, _fmt, ...) do {	\	if ((_vap)->iv_debug & (_m))					\		ieee80211_discard_mac(_vap, _mac, _type, _fmt, __VA_ARGS__);\} while (0)static const u_int8_t *ieee80211_getbssid(struct ieee80211vap *,	const struct ieee80211_frame *);static void ieee80211_discard_frame(struct ieee80211vap *,	const struct ieee80211_frame *, const char *, const char *, ...);static void ieee80211_discard_ie(struct ieee80211vap *,	const struct ieee80211_frame *, const char *, const char *, ...);static void ieee80211_discard_mac(struct ieee80211vap *,	const u_int8_t mac[IEEE80211_ADDR_LEN], const char *,	const char *, ...);#else#define	IEEE80211_DISCARD(_vap, _m, _wh, _type, _fmt, ...)#define	IEEE80211_DISCARD_IE(_vap, _m, _wh, _type, _fmt, ...)#define	IEEE80211_DISCARD_MAC(_vap, _m, _mac, _type, _fmt, ...)#endif /* IEEE80211_DEBUG */static struct sk_buff *ieee80211_defrag(struct ieee80211_node *,	struct sk_buff *, int);static void ieee80211_deliver_data(struct ieee80211_node *, struct sk_buff *);static struct sk_buff *ieee80211_decap(struct ieee80211vap *,	struct sk_buff *, int);static void ieee80211_send_error(struct ieee80211_node *, const u_int8_t *,	int, int);static void ieee80211_recv_pspoll(struct ieee80211_node *, struct sk_buff *);static int accept_data_frame(struct ieee80211vap *, struct ieee80211_node *,	struct ieee80211_key *, struct sk_buff *, struct ether_header *);#ifdef ATH_SUPERG_FFstatic void athff_decap(struct sk_buff *);#endif#ifdef USE_HEADERLEN_RESVstatic unsigned short ath_eth_type_trans(struct sk_buff *, struct net_device *);#endif/* Enhanced iwspy support */#ifdef CONFIG_NET_WIRELESS#if WIRELESS_EXT >= 16#ifndef IW_QUAL_QUAL_UPDATED#define IW_QUAL_QUAL_UPDATED	0x01#define IW_QUAL_LEVEL_UPDATED	0x02#define IW_QUAL_NOISE_UPDATED	0x04#endif /* IW_QUAL_QUAL_UPDATED *//** * This function is a clone of set_quality(..) in ieee80211_wireless.c */static voidset_quality(struct iw_quality *iq, u_int rssi){	iq->qual = rssi;	/* NB: max is 94 because noise is hardcoded to 161 */	if (iq->qual > 94)		iq->qual = 94;	iq->noise = 161;		/* -95dBm */	iq->level = iq->noise + iq->qual;	iq->updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |		IW_QUAL_NOISE_UPDATED;}/** * Given a node and the rssi value of a just received frame from the node, this * function checks if to raise an iwspy event because we iwspy the node and rssi * exceeds threshold (if active). *  * @param vap: vap * @param ni: sender node * @param rssi: rssi value of received frame */static voidiwspy_event(struct ieee80211vap *vap, struct ieee80211_node *ni, u_int rssi){	if (vap->iv_spy.thr_low && vap->iv_spy.num && ni && (rssi <		vap->iv_spy.thr_low || rssi > vap->iv_spy.thr_high)) {		int i;		for (i = 0; i < vap->iv_spy.num; i++) {			if (IEEE80211_ADDR_EQ(ni->ni_macaddr,				&(vap->iv_spy.mac[i * IEEE80211_ADDR_LEN]))) {									union iwreq_data wrq;				struct iw_thrspy thr;				IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG,					"%s: we spy %s, threshold is active "					"and rssi exceeds it -> raise an iwspy"					" event\n", __func__, ether_sprintf(					 ni->ni_macaddr));				memset(&wrq, 0, sizeof(wrq));				wrq.data.length = 1;				memset(&thr, 0, sizeof(struct iw_thrspy));				memcpy(thr.addr.sa_data, ni->ni_macaddr,					IEEE80211_ADDR_LEN);				thr.addr.sa_family = ARPHRD_ETHER;				set_quality(&thr.qual, rssi);				set_quality(&thr.low, vap->iv_spy.thr_low);				set_quality(&thr.high, vap->iv_spy.thr_high);				wireless_send_event(vap->iv_dev,					SIOCGIWTHRSPY, &wrq, (char*) &thr);				break;			}		}	}}#else#define iwspy_event(_vap, _ni, _rssi)#endif /* WIRELESS_EXT >= 16 */#else#define iwspy_event(_vap, _ni, _rssi)#endif /* CONFIG_NET_WIRELESS *//* * Process a received frame.  The node associated with the sender * should be supplied.  If nothing was found in the node table then * the caller is assumed to supply a reference to ic_bss instead. * The RSSI and a timestamp are also supplied.  The RSSI data is used * during AP scanning to select a AP to associate with; it can have * any units so long as values have consistent units and higher values * mean ``better signal''.  The receive timestamp is currently not used * by the 802.11 layer. * * Context: softIRQ (tasklet) */intieee80211_input(struct ieee80211_node *ni,	struct sk_buff *skb, int rssi, u_int32_t rstamp){#define	HAS_SEQ(type)	((type & 0x4) == 0)	struct ieee80211vap *vap = ni->ni_vap;	struct ieee80211com *ic = vap->iv_ic;	struct ieee80211_node *ni_wds = NULL;	struct net_device *dev = vap->iv_dev;	struct ieee80211_frame *wh;	struct ieee80211_key *key;	struct ether_header *eh;#ifdef ATH_SUPERG_FF	struct llc *llc;#endif	int hdrspace;	u_int8_t dir, type, subtype;	u_int8_t *bssid;	u_int16_t rxseq;	KASSERT(ni != NULL, ("null node"));	ni->ni_inact = ni->ni_inact_reload;	KASSERT(skb->len >= sizeof(struct ieee80211_frame_min),		("frame length too short: %u", skb->len));	/* XXX adjust device in sk_buff? */	type = -1;			/* undefined */	/*	 * In monitor mode, send everything directly to bpf.	 * Also do not process frames w/o i_addr2 any further.	 * XXX may want to include the CRC	 */	if (vap->iv_opmode == IEEE80211_M_MONITOR)		goto out;	if (skb->len < sizeof(struct ieee80211_frame_min)) {		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,			ni->ni_macaddr, NULL,			"too short (1): len %u", skb->len);		vap->iv_stats.is_rx_tooshort++;		goto out;	}	/*	 * Bit of a cheat here, we use a pointer for a 3-address	 * frame format but don't reference fields past outside	 * ieee80211_frame_min w/o first validating the data is	 * present.	 */	wh = (struct ieee80211_frame *)skb->data;	if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=	    IEEE80211_FC0_VERSION_0) {		IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,			ni->ni_macaddr, NULL, "wrong version %x", wh->i_fc[0]);		vap->iv_stats.is_rx_badversion++;		goto err;	}	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;	if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {		switch (vap->iv_opmode) {		case IEEE80211_M_STA:			bssid = wh->i_addr2;			if (!IEEE80211_ADDR_EQ(bssid, ni->ni_bssid)) {				/* not interested in */				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,					bssid, NULL, "%s", "not to bss");				vap->iv_stats.is_rx_wrongbss++;				goto out;			}			iwspy_event(vap, ni, rssi);			break;		case IEEE80211_M_IBSS:		case IEEE80211_M_AHDEMO:			if (dir != IEEE80211_FC1_DIR_NODS)				bssid = wh->i_addr1;			else if (type == IEEE80211_FC0_TYPE_CTL)				bssid = wh->i_addr1;			else {				if (skb->len < sizeof(struct ieee80211_frame)) {					IEEE80211_DISCARD_MAC(vap,						IEEE80211_MSG_ANY, ni->ni_macaddr,						NULL, "too short (2): len %u",						skb->len);					vap->iv_stats.is_rx_tooshort++;					goto out;				}				bssid = wh->i_addr3;			}			if (type == IEEE80211_FC0_TYPE_DATA &&			    ni == vap->iv_bss) {				/*				 * Try to find sender in local node table.				 */				ni = ieee80211_find_node(ni->ni_table, wh->i_addr2);				if (ni == NULL) {					/*					 * Fake up a node for this newly discovered					 * member of the IBSS.  This should probably					 * done after an ACL check.					 */					ni = ieee80211_fakeup_adhoc_node(vap,							wh->i_addr2);					if (ni == NULL) {						/* NB: stat kept for alloc failure */						goto err;					}				}			}			iwspy_event(vap, ni, rssi);			break;		case IEEE80211_M_HOSTAP:			if (dir != IEEE80211_FC1_DIR_NODS)				bssid = wh->i_addr1;			else if (type == IEEE80211_FC0_TYPE_CTL)				bssid = wh->i_addr1;			else {				if (skb->len < sizeof(struct ieee80211_frame)) {					IEEE80211_DISCARD_MAC(vap,						IEEE80211_MSG_ANY, ni->ni_macaddr,						NULL, "too short (2): len %u",						skb->len);					vap->iv_stats.is_rx_tooshort++;					goto out;				}				bssid = wh->i_addr3;			}			/*			 * Validate the bssid.			 */#ifdef ATH_SUPERG_XR			if (!IEEE80211_ADDR_EQ(bssid, vap->iv_bss->ni_bssid) &&			    !IEEE80211_ADDR_EQ(bssid, dev->broadcast)) {				/*				 * allow MGT frames to vap->iv_xrvap.				 * this will allow roaming between  XR and normal vaps				 * without station dis associating from previous vap.				 */				if (!(vap->iv_xrvap && 				    IEEE80211_ADDR_EQ(bssid, vap->iv_xrvap->iv_bss->ni_bssid) &&				    type == IEEE80211_FC0_TYPE_MGT && 				    ni != vap->iv_bss)) {					/* not interested in */					IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,						bssid, NULL, "%s", "not to bss or xrbss");					vap->iv_stats.is_rx_wrongbss++;					goto out;				}			}#else			if (!IEEE80211_ADDR_EQ(bssid, vap->iv_bss->ni_bssid) &&			    !IEEE80211_ADDR_EQ(bssid, dev->broadcast)) {				/* not interested in */				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,					bssid, NULL, "%s", "not to bss");				vap->iv_stats.is_rx_wrongbss++;				goto out;			}#endif			break;		case IEEE80211_M_WDS:			if (skb->len < sizeof(struct ieee80211_frame_addr4)) {				IEEE80211_DISCARD_MAC(vap,					IEEE80211_MSG_ANY, ni->ni_macaddr,					NULL, "too short (3): len %u",					skb->len);				vap->iv_stats.is_rx_tooshort++;				goto out;			}			bssid = wh->i_addr1;			if (!IEEE80211_ADDR_EQ(bssid, vap->iv_bss->ni_bssid) &&			    !IEEE80211_ADDR_EQ(bssid, dev->broadcast)) {				/* not interested in */				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,					bssid, NULL, "%s", "not to bss");				vap->iv_stats.is_rx_wrongbss++;				goto out;			}			if (!IEEE80211_ADDR_EQ(wh->i_addr2, vap->wds_mac)) {				/* not interested in */				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,					wh->i_addr2, NULL, "%s", "not from DS");				vap->iv_stats.is_rx_wrongbss++;				goto out;				}			break;		default:			/* XXX catch bad values */			goto out;		}		ni->ni_rssi = rssi;		ni->ni_rstamp = rstamp;		ni->ni_last_rx = jiffies;		if (HAS_SEQ(type)) {			u_int8_t tid;			if (IEEE80211_QOS_HAS_SEQ(wh)) {				tid = ((struct ieee80211_qosframe *)wh)->					i_qos[0] & IEEE80211_QOS_TID;				if (TID_TO_WME_AC(tid) >= WME_AC_VI)					ic->ic_wme.wme_hipri_traffic++;				tid++;			} else				tid = 0;			rxseq = le16toh(*(u_int16_t *)wh->i_seq);			if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&			    IEEE80211_SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {				/* duplicate, discard */				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,					bssid, "duplicate",					"seqno <%u,%u> fragno <%u,%u> tid %u",					rxseq >> IEEE80211_SEQ_SEQ_SHIFT,					ni->ni_rxseqs[tid] >>						IEEE80211_SEQ_SEQ_SHIFT,					rxseq & IEEE80211_SEQ_FRAG_MASK,					ni->ni_rxseqs[tid] &						IEEE80211_SEQ_FRAG_MASK,					tid);				vap->iv_stats.is_rx_dup++;				IEEE80211_NODE_STAT(ni, rx_dup);				goto out;			}

⌨️ 快捷键说明

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