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

📄 ieee80211_input.c

📁 Linux下wifi实现
💻 C
📖 第 1 页 / 共 5 页
字号:
			ni->ni_rxseqs[tid] = rxseq;		}	}	switch (type) {	case IEEE80211_FC0_TYPE_DATA:		hdrspace = ieee80211_hdrspace(ic, wh);		if (skb->len < hdrspace) {			IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,				wh, "data", "too short: len %u, expecting %u",			 	skb->len, hdrspace);			vap->iv_stats.is_rx_tooshort++;			goto out;		/* XXX */		}		switch (vap->iv_opmode) {		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 ((dev->flags & IFF_MULTICAST) &&			    IEEE80211_IS_MULTICAST(wh->i_addr1)) {				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 = NULL;					nt = &ic->ic_sta;					ni_wds = ieee80211_find_wds_node(nt, wh->i_addr3);					if (ni_wds) {						ieee80211_free_node(ni_wds); /* Decr ref count */						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.			 */			if (dir == IEEE80211_FC1_DIR_DSTODS) {				struct ieee80211_node_table *nt;				struct ieee80211_frame_addr4 *wh4;				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_free_node(ni_wds); /* Decr ref count */			}						/*			 * 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 ((*(u_int16_t *)(&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;		}		/*		 * 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, hdrspace);			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, hdrspace);			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, hdrspace)) {			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, hdrspace);		if (skb == NULL) {			/* don't count Null data frames as errors */			if (subtype == IEEE80211_FC0_SUBTYPE_NODATA)				goto out;			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;			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);			skb1 = skb_clone(skb, GFP_ATOMIC); /* XXX: GFP_ATOMIC is overkill? */			eh_tmp = (struct ether_header *)skb->data;			/* ether_type must be length*/			frame_len = ntohs(eh_tmp->ether_type);			/* we now have 802.3 MAC hdr followed by 802.2 LLC/SNAP. convert to DIX */			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));			eh_tmp = (struct ether_header *)skb1->data;			frame_len = ntohs(eh_tmp->ether_type);			athff_decap(skb1);			/* 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		return IEEE80211_FC0_TYPE_DATA;	case IEEE80211_FC0_TYPE_MGT:		/*		 * WDS opmode do not support managment 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 %s rssi %d\n",				ieee80211_mgt_subtype_name[subtype >>				IEEE80211_FC0_SUBTYPE_SHIFT],				ether_sprintf(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;			}			hdrspace = ieee80211_hdrspace(ic, wh);			key = ieee80211_crypto_decap(ni, skb, hdrspace);			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(ni, skb, subtype, rssi, rstamp);		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:	if (skb != NULL)		dev_kfree_skb(skb);	return type;#undef HAS_SEQ}EXPORT_SYMBOL(ieee80211_input);/* * Determines whether a frame should be accepted, based on information * about the frame's origin and encryption, and policy for this vap. */static int accept_data_frame(struct ieee80211vap *vap,       struct ieee80211_node *ni, struct ieee80211_key *key,       struct sk_buff *skb, struct ether_header *eh){#define IS_EAPOL(eh) ((eh)->ether_type == __constant_htons(ETHERTYPE_PAE))#define PAIRWISE_SET(vap) ((vap)->iv_nw_keys[0].wk_cipher != &ieee80211_cipher_none)       if (IS_EAPOL(eh)) {               /* encrypted eapol is always OK */               if (key)                       return 1;               /* cleartext eapol is OK if we don't have pairwise keys yet */               if (! PAIRWISE_SET(vap))                       return 1;               /* cleartext eapol is OK if configured to allow it */               if (! IEEE80211_VAP_DROPUNENC_EAPOL(vap))                       return 1;               /* cleartext eapol is OK if other unencrypted is OK */               if (! (vap->iv_flags & IEEE80211_F_DROPUNENC))                       return 1;               /* not OK */               IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,                       eh->ether_shost, "data",                       "unauthorized port: ether type 0x%x len %u",                       eh->ether_type, skb->len);               vap->iv_stats.is_rx_unauth++;               vap->iv_devstats.rx_errors++;               IEEE80211_NODE_STAT(ni, rx_unauth);               return 0;       }       if (!ieee80211_node_is_authorized(ni)) {               /*                * Deny any non-PAE frames received prior to                * authorization.  For open/shared-key                * authentication the port is mark authorized                * after authentication completes.  For 802.1x                * the port is not marked authorized by the                * authenticator until the handshake has completed.                */               IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,                       eh->ether_shost, "data",                       "unauthorized port: ether type 0x%x len %u",                       eh->ether_type, skb->len);               vap->iv_stats.is_rx_unauth++;               vap->iv_devstats.rx_errors++;               IEEE80211_NODE_STAT(ni, rx_unauth);               return 0;

⌨️ 快捷键说明

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