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

📄 ieee80211_input.c.svn-base

📁 最新之atheros芯片driver source code, 基于linux操作系统,內含atheros芯片HAL全部代码
💻 SVN-BASE
📖 第 1 页 / 共 5 页
字号:
		case IEEE80211_M_STA:			if ((dir != IEEE80211_FC1_DIR_FROMDS) &&			    (!((vap->iv_flags_ext & IEEE80211_FEXT_WDS) &&			    (dir == IEEE80211_FC1_DIR_DSTODS)))) {				IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,					wh, "data", "invalid dir 0x%x", dir);				vap->iv_stats.is_rx_wrongdir++;				goto out;			}	        	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {				/* Discard multicast if IFF_MULTICAST not set */				if ((0 != memcmp(wh->i_addr3, dev->broadcast, ETH_ALEN)) && 					(0 == (dev->flags & IFF_MULTICAST))) {					IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,						wh, NULL, "%s", "multicast disabled.");					printk(KERN_ERR "CONFIG ERROR: multicast flag "					       "cleared on radio, but multicast was used.\n");					vap->iv_stats.is_rx_mcastdisabled++;					goto out;				}				/* Discard echos of our own multicast or broadcast */				if (IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr)) {					/*					 * In IEEE802.11 network, multicast packet					 * sent from me is broadcasted from AP.					 * It should be silently discarded for					 * SIMPLEX interface.					 *					 * NB: Linux has no IFF_ flag to indicate					 *     if an interface is SIMPLEX or not;					 *     so we always assume it to be true.					 */					IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,						wh, NULL, "%s", "multicast echo");					vap->iv_stats.is_rx_mcastecho++;					goto out;				}				/* 				 * if it is brodcasted by me on behalf of				 * a station behind me, drop it.				 */				if (vap->iv_flags_ext & IEEE80211_FEXT_WDS) {					struct ieee80211_node_table *nt;					struct ieee80211_node *ni_wds;					nt = &ic->ic_sta;					ni_wds = ieee80211_find_wds_node(nt, wh->i_addr3);					if (ni_wds) {						ieee80211_unref_node(&ni_wds);						IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,							wh, NULL, "%s",							"multicast echo originated from node behind me");						vap->iv_stats.is_rx_mcastecho++;						goto out;					}				}			}			break;		case IEEE80211_M_IBSS:		case IEEE80211_M_AHDEMO:			if (dir != IEEE80211_FC1_DIR_NODS) {				IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,					wh, "data", "invalid dir 0x%x", dir);				vap->iv_stats.is_rx_wrongdir++;				goto out;			}			/* XXX no power-save support */			break;		case IEEE80211_M_HOSTAP:			if ((dir != IEEE80211_FC1_DIR_TODS) &&			    (dir != IEEE80211_FC1_DIR_DSTODS)) {				IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,					wh, "data", "invalid dir 0x%x", dir);				vap->iv_stats.is_rx_wrongdir++;				goto out;			}			/* check if source STA is associated */			if (ni == vap->iv_bss) {				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,					wh, "data", "%s", "unknown src");				/* NB: caller deals with reference */					if (vap->iv_state == IEEE80211_S_RUN)					ieee80211_send_error(ni, wh->i_addr2,						IEEE80211_FC0_SUBTYPE_DEAUTH,						IEEE80211_REASON_NOT_AUTHED);				vap->iv_stats.is_rx_notassoc++;				goto err;			}			if (ni->ni_associd == 0) {				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,					wh, "data", "%s", "unassoc src");				IEEE80211_SEND_MGMT(ni,					IEEE80211_FC0_SUBTYPE_DISASSOC,					IEEE80211_REASON_NOT_ASSOCED);				vap->iv_stats.is_rx_notassoc++;				goto err;			}			/*			 * If we're a 4 address packet, make sure we have an entry in			 * the node table for the packet source address (addr4).			 * If not, add one.			 */			/* XXX: Useless node mgmt API; make better */			if (dir == IEEE80211_FC1_DIR_DSTODS) {				struct ieee80211_node_table *nt;				struct ieee80211_frame_addr4 *wh4;				struct ieee80211_node *ni_wds;				if (!(vap->iv_flags_ext & IEEE80211_FEXT_WDS)) {					IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,						wh, "data", "%s", "4 addr not allowed");					goto err;				}				wh4 = (struct ieee80211_frame_addr4 *)skb->data;				nt = &ic->ic_sta;				ni_wds = ieee80211_find_wds_node(nt, wh4->i_addr4);				/* Last call increments ref count if !NULL */				if ((ni_wds != NULL) && (ni_wds != ni)) {					/*					 * node with source address (addr4) moved					 * to another WDS capable station. remove the					 * reference to the previous station and add 					 * reference to the new one					 */					 (void) ieee80211_remove_wds_addr(nt, wh4->i_addr4);					 ieee80211_add_wds_addr(nt, ni, wh4->i_addr4, 0);				}				if (ni_wds == NULL)					ieee80211_add_wds_addr(nt, ni, wh4->i_addr4, 0);				else					ieee80211_unref_node(&ni_wds);			}			/*			 * Check for power save state change.			 */			if (!(ni->ni_flags & IEEE80211_NODE_UAPSD)) {				if ((wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) ^				    (ni->ni_flags & IEEE80211_NODE_PWR_MGT))					ieee80211_node_pwrsave(ni, wh->i_fc[1] & IEEE80211_FC1_PWR_MGT);			} else if (ni->ni_flags & IEEE80211_NODE_PS_CHANGED) {				int pwr_save_changed = 0;				IEEE80211_LOCK_IRQ(ic);				if ((*(__le16 *)(&wh->i_seq[0])) == ni->ni_pschangeseq) {					ni->ni_flags &= ~IEEE80211_NODE_PS_CHANGED;					pwr_save_changed = 1;				}				IEEE80211_UNLOCK_IRQ(ic);				if (pwr_save_changed)					ieee80211_node_pwrsave(ni, wh->i_fc[1] & IEEE80211_FC1_PWR_MGT);			}			break;		case IEEE80211_M_WDS:			if (dir != IEEE80211_FC1_DIR_DSTODS) {				IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,					wh, "data", "invalid dir 0x%x", dir);				vap->iv_stats.is_rx_wrongdir++;				goto out;			}			break;		default:			/* XXX here to keep compiler happy */			goto out;		}		/* These frames have no further meaning. */		if ((subtype == IEEE80211_FC0_SUBTYPE_NULL) ||		    (subtype == IEEE80211_FC0_SUBTYPE_QOS_NULL))			goto out;		/*		 * Handle privacy requirements.  Note that we		 * must not be preempted from here until after		 * we (potentially) call ieee80211_crypto_demic;		 * otherwise we may violate assumptions in the		 * crypto cipher modules used to do delayed update		 * of replay sequence numbers.		 */		if (wh->i_fc[1] & IEEE80211_FC1_PROT) {			if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {				/*				 * Discard encrypted frames when privacy is off.				 */				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,					wh, "WEP", "%s", "PRIVACY off");				vap->iv_stats.is_rx_noprivacy++;				IEEE80211_NODE_STAT(ni, rx_noprivacy);				goto out;			}			key = ieee80211_crypto_decap(ni, skb, hdrlen);			if (key == NULL) {				/* NB: stats+msgs handled in crypto_decap */				IEEE80211_NODE_STAT(ni, rx_wepfail);				goto out;			}			wh = (struct ieee80211_frame *)skb->data;			wh->i_fc[1] &= ~IEEE80211_FC1_PROT;		} else			key = NULL;		/* Next up, any fragmentation. */		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {			skb = ieee80211_defrag(ni, skb, hdrlen);			if (skb == NULL) {				/* Fragment dropped or frame not complete yet */				goto out;			}		}		wh = NULL;		/* no longer valid, catch any uses */		/* Next strip any MSDU crypto. bits. */		if (key != NULL &&		    !ieee80211_crypto_demic(vap, key, skb, hdrlen, 0)) {			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,				ni->ni_macaddr, "data", "%s", "demic error");			IEEE80211_NODE_STAT(ni, rx_demicfail);			goto out;		}		/* Finally, strip the 802.11 header. */		skb = ieee80211_decap(vap, skb, hdrlen);		if (skb == NULL) {			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,				ni->ni_macaddr, "data", "%s", "decap error");			vap->iv_stats.is_rx_decap++;			IEEE80211_NODE_STAT(ni, rx_decap);			goto err;		}		eh = (struct ether_header *)skb->data;		if (!accept_data_frame(vap, ni, key, skb, eh))			goto out;		vap->iv_devstats.rx_packets++;		vap->iv_devstats.rx_bytes += skb->len;		IEEE80211_NODE_STAT(ni, rx_data);		IEEE80211_NODE_STAT_ADD(ni, rx_bytes, skb->len);		ic->ic_lastdata = jiffies;#ifdef ATH_SUPERG_FF		/* check for FF */		llc = (struct llc *)(skb->data + sizeof(struct ether_header));		if (ntohs(llc->llc_snap.ether_type) == (u_int16_t)ATH_ETH_TYPE) {			struct sk_buff *skb1 = NULL;			struct ether_header *eh_tmp;			struct athl2p_tunnel_hdr *ath_hdr;			unsigned int frame_len;			/* NB: assumes linear (i.e., non-fragmented) skb */			/* get to the tunneled headers */			ath_hdr = (struct athl2p_tunnel_hdr *)				skb_pull(skb, sizeof(struct ether_header) + LLC_SNAPFRAMELEN); 			/* ignore invalid frames */ 			if (ath_hdr == NULL) 				goto err;			/* only implementing FF now. drop all others. */			if (ath_hdr->proto != ATH_L2TUNNEL_PROTO_FF) {				IEEE80211_DISCARD_MAC(vap,					IEEE80211_MSG_SUPG | IEEE80211_MSG_INPUT,					eh->ether_shost, "fast-frame",					"bad atheros tunnel prot %u",					ath_hdr->proto);				vap->iv_stats.is_rx_badathtnl++;				goto err;			}			vap->iv_stats.is_rx_ffcnt++;			/* move past the tunneled header, with alignment */ 			skb_pull(skb, roundup(sizeof(struct athl2p_tunnel_hdr) - 2, 4) + 2); 			eh_tmp = (struct ether_header *)skb->data; 			/* ether_type must be length as FF frames are always LLC/SNAP encap'd */ 			frame_len = ntohs(eh_tmp->ether_type); 			skb1 = skb_copy(skb, GFP_ATOMIC);			if (skb1 == NULL)				goto err;			ieee80211_skb_copy_noderef(skb, skb1);			/* we now have 802.3 MAC hdr followed by 802.2 LLC/SNAP; convert to EthernetII.			 * Note that the frame is at least IEEE80211_MIN_LEN, due to the driver code. */			athff_decap(skb);			/* remove second frame from end of first */			skb_trim(skb, sizeof(struct ether_header) + frame_len - LLC_SNAPFRAMELEN);			/* prepare second tunneled frame */			skb_pull(skb1, roundup(sizeof(struct ether_header) + frame_len, 4));			/* Fail if there is no space left for at least the necessary headers */			if (athff_decap(skb1)) {				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,						ni->ni_macaddr, "data", "%s", "Decapsulation error");				vap->iv_stats.is_rx_decap++;				IEEE80211_NODE_STAT(ni, rx_decap);				ieee80211_dev_kfree_skb(&skb1); /* This is a copy! */				goto err;			}			/* Deliver the frames. */			ieee80211_deliver_data(ni, skb);			ieee80211_deliver_data(ni, skb1);		} else {			/* Assume non-atheros LLC type. */			ieee80211_deliver_data(ni, skb);		}#else /* !ATH_SUPERG_FF */		ieee80211_deliver_data(ni, skb);#endif		if (ni_or_null == NULL)			ieee80211_unref_node(&ni);		/* XXX: Why doesn't this use 'goto out'? 		 *      If it did, then the SKB would be accessed after we		 *      have given it to ieee80211_deliver_data and we get		 *      crashes/errors. */		return IEEE80211_FC0_TYPE_DATA;	case IEEE80211_FC0_TYPE_MGT:		/* WDS opmode does not support management frames. */		if (vap->iv_opmode == IEEE80211_M_WDS) {			vap->iv_stats.is_rx_mgtdiscard++;			goto out;		}		IEEE80211_NODE_STAT(ni, rx_mgmt);		if (dir != IEEE80211_FC1_DIR_NODS) {			vap->iv_stats.is_rx_wrongdir++;			goto err;		}		if (skb->len < sizeof(struct ieee80211_frame)) {			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,				ni->ni_macaddr, "mgt", "too short: len %u",				skb->len);			vap->iv_stats.is_rx_tooshort++;			goto out;		}#ifdef IEEE80211_DEBUG		if ((ieee80211_msg_debug(vap) && doprint(vap, subtype)) ||		    ieee80211_msg_dumppkts(vap)) {			ieee80211_note(vap, 				"received %s from " MAC_FMT " rssi %d\n",				ieee80211_mgt_subtype_name[subtype >>				IEEE80211_FC0_SUBTYPE_SHIFT],				MAC_ADDR(wh->i_addr2), rssi);		}#endif		if (wh->i_fc[1] & IEEE80211_FC1_PROT) {			if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) {				/*				 * Only shared key auth frames with a challenge				 * should be encrypted, discard all others.				 */				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,					wh, ieee80211_mgt_subtype_name[subtype >>					IEEE80211_FC0_SUBTYPE_SHIFT],					"%s", "WEP set but not permitted");				vap->iv_stats.is_rx_mgtdiscard++; /* XXX */				goto out;			}			if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) {				/*				 * Discard encrypted frames when privacy is off.				 */				IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,					wh, "mgt", "%s", "WEP set but PRIVACY off");				vap->iv_stats.is_rx_noprivacy++;				goto out;			}			hdrlen = ieee80211_hdrsize(wh);			key = ieee80211_crypto_decap(ni, skb, hdrlen);			if (key == NULL) {				/* NB: stats+msgs handled in crypto_decap */				goto out;			}			wh = (struct ieee80211_frame *)skb->data;			wh->i_fc[1] &= ~IEEE80211_FC1_PROT;		}		ic->ic_recv_mgmt(vap, ni_or_null, skb, subtype, rssi, rtsf);		goto out;	case IEEE80211_FC0_TYPE_CTL:		IEEE80211_NODE_STAT(ni, rx_ctrl);		vap->iv_stats.is_rx_ctl++;		if (vap->iv_opmode == IEEE80211_M_HOSTAP)			if (subtype == IEEE80211_FC0_SUBTYPE_PS_POLL)				ieee80211_recv_pspoll(ni, skb);		goto out;	default:		IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,			wh, NULL, "bad frame type 0x%x", type);		/* should not come here */		break;	}err:	vap->iv_devstats.rx_errors++;out:	ieee80211_dev_kfree_skb(&skb);	if (ni_or_null == NULL)		ieee80211_unref_node(&ni);	return type;#undef HAS_SEQ}EXPORT_SYMBOL(ieee80211_input);/*  * Context: softIRQ (tasklet)  */ int ieee80211_input_all(struct ieee80211com *ic, 		struct sk_buff *skb, int rssi, u_int64_t rtsf) { 	struct ieee80211vap *vap, *next_vap; 	struct sk_buff *tskb = NULL;	int type = -1;	/* Used to determine when to blinks LEDs. */	/* Create a new SKB copy for each VAP except the last	 * one, which gets the original SKB. */	vap = TAILQ_FIRST(&ic->ic_vaps);	while (vap) {		for (next_vap = TAILQ_NEXT(vap, iv_next); next_vap;				next_vap = TAILQ_NEXT(next_vap, iv_next)) {			if ((next_vap->iv_dev->flags & (IFF_RUNNING | IFF_UP))					== (IFF_RUNNING | IFF_UP))				break;		}		if (!next_vap) {			tskb = skb;			skb = NULL;		} else			tskb = skb_copy(skb, GFP_ATOMIC);		if (!tskb)			/* XXX: Brilliant OOM handling. */			vap->iv_devstats.tx_dropped++;		else			type = ieee80211_input(vap, NULL, tskb, rssi, rtsf);		vap = next_vap;	};

⌨️ 快捷键说明

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