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

📄 ieee80211_output.c.svn-base

📁 最新之atheros芯片driver source code, 基于linux操作系统,內含atheros芯片HAL全部代码
💻 SVN-BASE
📖 第 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$ */#ifndef EXPORT_SYMTAB#define	EXPORT_SYMTAB#endif/* * IEEE 802.11 output handling. */#ifndef AUTOCONF_INCLUDED#include <linux/config.h>#endif#include <linux/version.h>#include <linux/module.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/if_vlan.h>#include <linux/ip.h>			/* XXX for TOS */#include "if_llc.h"#include "if_ethersubr.h"#include "if_media.h"#include <net80211/ieee80211_var.h>#include <net80211/ieee80211_monitor.h>#include <net80211/if_athproto.h>#ifdef IEEE80211_DEBUG/* * Decide if an outbound 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){	if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)		return (vap->iv_opmode == IEEE80211_M_IBSS);	return 1;}#endif/* * Determine the priority based on VLAN and/or IP TOS. Priority is * written into the skb->priority field. On success, returns 0. Failure * due to bad or mis-matched vlan tag is indicated by non-zero return. */static intieee80211_classify(struct ieee80211_node *ni, struct sk_buff *skb){	struct ieee80211vap *vap = ni->ni_vap;	struct ether_header *eh = (struct ether_header *)skb->data;	int v_wme_ac = 0, d_wme_ac = 0;	/* default priority */	skb->priority = WME_AC_BE;	if (!(ni->ni_flags & IEEE80211_NODE_QOS))		return 0;	/* 	 * If node has a vlan tag then all traffic	 * to it must have a matching vlan id.	 */	if (ni->ni_vlan != 0 && vlan_tx_tag_present(skb)) {		u_int32_t tag=0;		int v_pri;		if (vap->iv_vlgrp == NULL) {			IEEE80211_NODE_STAT(ni, tx_novlantag);			ni->ni_stats.ns_tx_novlantag++;			return 1;		}		if (((tag = vlan_tx_tag_get(skb)) & VLAN_VID_MASK) !=		    (ni->ni_vlan & VLAN_VID_MASK)) {			IEEE80211_NODE_STAT(ni, tx_vlanmismatch);			ni->ni_stats.ns_tx_vlanmismatch++;			return 1;		}		if (ni->ni_flags & IEEE80211_NODE_QOS) {			v_pri = (tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;			switch (v_pri) {			case 1:			case 2:		/* Background (BK) */				v_wme_ac = WME_AC_BK;				break;			case 0:			case 3:		/* Best Effort (BE) */				v_wme_ac = WME_AC_BE;				break;			case 4:			case 5:		/* Video (VI) */				v_wme_ac = WME_AC_VI;				break;			case 6:			case 7:		/* Voice (VO) */				v_wme_ac = WME_AC_VO;				break;			}		}	}	if (eh->ether_type == __constant_htons(ETHERTYPE_IP)) {		const struct iphdr *ip = (struct iphdr *)			(skb->data + sizeof (struct ether_header));		/*		 * IP frame, map the TOS field.		 *		 * XXX: fill out these mappings???		 */		switch (ip->tos) {		case 0x08:				/* Background */		case 0x20:			d_wme_ac = WME_AC_BK;			break;		case 0x28:				/* Video */		case 0xa0:			d_wme_ac = WME_AC_VI;			break;		case 0x30:				/* Voice */		case 0xe0:		case 0x88:				/* XXX UPSD */		case 0xb8:			d_wme_ac = WME_AC_VO;			break;		default:				/* All others */			d_wme_ac = WME_AC_BE;			break;		}	} else {		d_wme_ac = WME_AC_BE;	}	skb->priority = d_wme_ac;	if (v_wme_ac > d_wme_ac)		skb->priority = v_wme_ac;	/* Applying ACM policy */	if (vap->iv_opmode == IEEE80211_M_STA) {		struct ieee80211com *ic = ni->ni_ic;		while (skb->priority != WME_AC_BK &&		    ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[skb->priority].wmep_acm) {			switch (skb->priority) {			case WME_AC_BE:				skb->priority = WME_AC_BK;				break;			case WME_AC_VI:				skb->priority = WME_AC_BE;				break;			case WME_AC_VO:				skb->priority = WME_AC_VI;				break;			default:				skb->priority = WME_AC_BK;				break;			}		}	}	return 0;}/* * Context: process context (BHs disabled) * It must return either NETDEV_TX_OK or NETDEV_TX_BUSY */intieee80211_hardstart(struct sk_buff *skb, struct net_device *dev){	struct ieee80211vap *vap = netdev_priv(dev);	struct ieee80211com *ic = vap->iv_ic;	struct net_device *parent = ic->ic_dev;	struct ieee80211_node *ni = NULL;	struct ether_header *eh;	/* Reset the SKB of new frames reaching this layer BEFORE	 * we invoke ieee80211_skb_track. */	memset(SKB_CB(skb), 0, sizeof(struct ieee80211_cb));	/* If an SKB is passed in directly from the kernel, 	 * we take responsibility for the reference. */	ieee80211_skb_track(skb);	/* NB: parent must be up and running. */	if ((parent->flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP))		goto bad;	/* No data frames go out unless we're running. */	if (vap->iv_state != IEEE80211_S_RUN) {		IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,			"%s: ignore data packet, state %u\n",			__func__, vap->iv_state);#if 0		vap->iv_stats.ist_tx_discard++;#endif		goto bad;	}		if (vap->iv_opmode == IEEE80211_M_MONITOR) {		ieee80211_monitor_encap(vap, skb);		ieee80211_parent_queue_xmit(skb);		return NETDEV_TX_OK;	}		/* Cancel any running BG scan */	ieee80211_cancel_scan(vap);	/* Find the node for the destination so we can do	 * things like power save. */	eh = (struct ether_header *)skb->data;	if (vap->iv_opmode == IEEE80211_M_WDS)		ni = ieee80211_find_txnode(vap, vap->wds_mac);	else		ni = ieee80211_find_txnode(vap, eh->ether_dhost);	if (ni == NULL) {		/* NB: ieee80211_find_txnode does stat+msg */		goto bad;	}	/* Calculate priority so drivers can find the TX queue. */	if (ieee80211_classify(ni, skb)) {		IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,			"%s: discard, classification failure", __func__);		goto bad;	}	SKB_NI(skb) = ieee80211_ref_node(ni);	/* Power-save checks. */	if (WME_UAPSD_AC_CAN_TRIGGER(skb->priority, ni)) {		/* U-APSD power save queue */		/* XXXAPSD: assuming triggerable means deliverable */		M_FLAG_SET(skb, M_UAPSD);	} else if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT)) {		/* Station in power save mode; stick the frame		 * on the STA's power save queue and continue.		 * We'll get the frame back when the time is right. */		ieee80211_unref_node(&ni);		return ieee80211_pwrsave(skb);	}	dev->trans_start = jiffies;#ifdef ATH_SUPERG_XR	/* Broadcast/multicast packets need to be sent on XR vap in addition to	 * normal vap. */	if (vap->iv_xrvap && (ni == vap->iv_bss) &&	    vap->iv_xrvap->iv_sta_assoc) {		struct sk_buff *skb1 = skb_copy(skb, GFP_ATOMIC);		if (skb1) {			memset(SKB_CB(skb1), 0, sizeof(struct ieee80211_cb));#ifdef IEEE80211_DEBUG_REFCNT			M_FLAG_SET(skb1, M_SKB_TRACKED);#endif /* #ifdef IEEE80211_DEBUG_REFCNT */			SKB_NI(skb1) = ieee80211_find_txnode(vap->iv_xrvap, 						       eh->ether_dhost);			/* Ignore this return code. */			ieee80211_parent_queue_xmit(skb1);		}	}#endif	ieee80211_unref_node(&ni);	ieee80211_parent_queue_xmit(skb);	return NETDEV_TX_OK;bad:	if (skb != NULL)		ieee80211_dev_kfree_skb(&skb);	if (ni != NULL)		ieee80211_unref_node(&ni);	return NETDEV_TX_OK;}/* * SKB is consumed in all cases. */void ieee80211_parent_queue_xmit(struct sk_buff *skb) {	struct ieee80211vap *vap = netdev_priv(skb->dev);	vap->iv_devstats.tx_packets++;	vap->iv_devstats.tx_bytes += skb->len;	vap->iv_ic->ic_lastdata = jiffies;	/* Dispatch the packet to the parent device */	skb->dev = vap->iv_ic->ic_dev;	if (dev_queue_xmit(skb) == NET_XMIT_DROP)		vap->iv_devstats.tx_dropped++;}/* * Set the direction field and address fields of an outgoing * non-QoS frame.  Note this should be called early on in * constructing a frame as it sets i_fc[1]; other bits can * then be or'd in. */static voidieee80211_send_setup(struct ieee80211vap *vap,	struct ieee80211_node *ni,	struct ieee80211_frame *wh,	int type,	const u_int8_t sa[IEEE80211_ADDR_LEN],	const u_int8_t da[IEEE80211_ADDR_LEN],	const u_int8_t bssid[IEEE80211_ADDR_LEN]){#define	WH4(wh)	((struct ieee80211_frame_addr4 *)wh)	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type;	if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {		switch (vap->iv_opmode) {		case IEEE80211_M_STA:			wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;			IEEE80211_ADDR_COPY(wh->i_addr1, bssid);			IEEE80211_ADDR_COPY(wh->i_addr2, sa);			IEEE80211_ADDR_COPY(wh->i_addr3, da);			break;		case IEEE80211_M_IBSS:		case IEEE80211_M_AHDEMO:			wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;			IEEE80211_ADDR_COPY(wh->i_addr1, da);			IEEE80211_ADDR_COPY(wh->i_addr2, sa);			IEEE80211_ADDR_COPY(wh->i_addr3, bssid);			break;		case IEEE80211_M_HOSTAP:			wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;			IEEE80211_ADDR_COPY(wh->i_addr1, da);			IEEE80211_ADDR_COPY(wh->i_addr2, bssid);			IEEE80211_ADDR_COPY(wh->i_addr3, sa);			break;		case IEEE80211_M_WDS:			wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;			/* XXX cheat, bssid holds RA */			IEEE80211_ADDR_COPY(wh->i_addr1, bssid);			IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);			IEEE80211_ADDR_COPY(wh->i_addr3, da);			IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa);			break;		case IEEE80211_M_MONITOR:	/* NB: to quiet compiler */			break;		}	} else {		wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;		IEEE80211_ADDR_COPY(wh->i_addr1, da);		IEEE80211_ADDR_COPY(wh->i_addr2, sa);		IEEE80211_ADDR_COPY(wh->i_addr3, bssid);	}	wh->i_dur = 0;	/* NB: use non-QoS tid */	*(__le16 *)&wh->i_seq[0] =	    htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT);	ni->ni_txseqs[0]++;#undef WH4}/* * Send a management frame to the specified node.  The node pointer * must have a reference as the pointer will be passed to the driver * and potentially held for a long time.  If the frame is successfully * dispatched to the driver, then it is responsible for freeing the * reference (and potentially freeing up any associated storage). */static voidieee80211_mgmt_output(struct ieee80211_node *ni, struct sk_buff *skb, int type){	struct ieee80211vap *vap = ni->ni_vap;	struct ieee80211com *ic = ni->ni_ic;	struct ieee80211_frame *wh;	KASSERT(ni != NULL, ("null node"));	SKB_NI(skb) = ni;	wh = (struct ieee80211_frame *)		skb_push(skb, sizeof(struct ieee80211_frame));	ieee80211_send_setup(vap, ni, wh,		IEEE80211_FC0_TYPE_MGT | type,		vap->iv_myaddr, ni->ni_macaddr, vap->iv_bssid);	/* XXX power management */	if ((SKB_CB(skb)->flags & M_LINK0) != 0 && ni->ni_challenge != NULL) {		SKB_CB(skb)->flags &= ~M_LINK0;		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1,			"encrypting frame (%s)", __func__);		wh->i_fc[1] |= IEEE80211_FC1_PROT;	}	if (IEEE80211_VAP_IS_SLEEPING(ni->ni_vap))		wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;#ifdef IEEE80211_DEBUG	/* avoid printing too many frames */	if ((ieee80211_msg_debug(vap) && doprint(vap, type)) ||	    ieee80211_msg_dumppkts(vap)) {		printk(KERN_DEBUG "[" MAC_FMT "] send %s on channel %u\n",			MAC_ADDR(wh->i_addr1),			ieee80211_mgt_subtype_name[				(type & IEEE80211_FC0_SUBTYPE_MASK) >>					IEEE80211_FC0_SUBTYPE_SHIFT],		    	ieee80211_chan2ieee(ic, ic->ic_curchan));	}#endif	IEEE80211_NODE_STAT(ni, tx_mgmt);	(void) ic->ic_mgtstart(ic, skb);}/* Send a null data frame to the specified node. * * NB: the caller provides us with our own node reference this must not be  *     leaked; this is necessary to deal with a race condition when  *     probing for inactive stations. */intieee80211_send_nulldata(struct ieee80211_node *ni){	struct ieee80211vap *vap = ni->ni_vap;	struct ieee80211com *ic = ni->ni_ic;

⌨️ 快捷键说明

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