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

📄 tx.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz> * Copyright 2007	Johannes Berg <johannes@sipsolutions.net> * * 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. * * * Transmit and frame generation functions. */#include <linux/kernel.h>#include <linux/slab.h>#include <linux/skbuff.h>#include <linux/etherdevice.h>#include <linux/bitmap.h>#include <linux/rcupdate.h>#include <net/net_namespace.h>#include <net/ieee80211_radiotap.h>#include <net/cfg80211.h>#include <net/mac80211.h>#include <asm/unaligned.h>#include "ieee80211_i.h"#include "ieee80211_led.h"#include "wep.h"#include "wpa.h"#include "wme.h"#include "ieee80211_rate.h"#define IEEE80211_TX_OK		0#define IEEE80211_TX_AGAIN	1#define IEEE80211_TX_FRAG_AGAIN	2/* misc utils */static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,					      struct ieee80211_hdr *hdr){	/* Set the sequence number for this frame. */	hdr->seq_ctrl = cpu_to_le16(sdata->sequence);	/* Increase the sequence number. */	sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ;}#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMPstatic void ieee80211_dump_frame(const char *ifname, const char *title,				 const struct sk_buff *skb){	const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;	u16 fc;	int hdrlen;	DECLARE_MAC_BUF(mac);	printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len);	if (skb->len < 4) {		printk("\n");		return;	}	fc = le16_to_cpu(hdr->frame_control);	hdrlen = ieee80211_get_hdrlen(fc);	if (hdrlen > skb->len)		hdrlen = skb->len;	if (hdrlen >= 4)		printk(" FC=0x%04x DUR=0x%04x",		       fc, le16_to_cpu(hdr->duration_id));	if (hdrlen >= 10)		printk(" A1=%s", print_mac(mac, hdr->addr1));	if (hdrlen >= 16)		printk(" A2=%s", print_mac(mac, hdr->addr2));	if (hdrlen >= 24)		printk(" A3=%s", print_mac(mac, hdr->addr3));	if (hdrlen >= 30)		printk(" A4=%s", print_mac(mac, hdr->addr4));	printk("\n");}#else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */static inline void ieee80211_dump_frame(const char *ifname, const char *title,					struct sk_buff *skb){}#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,			      int next_frag_len){	int rate, mrate, erp, dur, i;	struct ieee80211_rate *txrate = tx->u.tx.rate;	struct ieee80211_local *local = tx->local;	struct ieee80211_hw_mode *mode = tx->u.tx.mode;	erp = txrate->flags & IEEE80211_RATE_ERP;	/*	 * data and mgmt (except PS Poll):	 * - during CFP: 32768	 * - during contention period:	 *   if addr1 is group address: 0	 *   if more fragments = 0 and addr1 is individual address: time to	 *      transmit one ACK plus SIFS	 *   if more fragments = 1 and addr1 is individual address: time to	 *      transmit next fragment plus 2 x ACK plus 3 x SIFS	 *	 * IEEE 802.11, 9.6:	 * - control response frame (CTS or ACK) shall be transmitted using the	 *   same rate as the immediately previous frame in the frame exchange	 *   sequence, if this rate belongs to the PHY mandatory rates, or else	 *   at the highest possible rate belonging to the PHY rates in the	 *   BSSBasicRateSet	 */	if ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) {		/* TODO: These control frames are not currently sent by		 * 80211.o, but should they be implemented, this function		 * needs to be updated to support duration field calculation.		 *		 * RTS: time needed to transmit pending data/mgmt frame plus		 *    one CTS frame plus one ACK frame plus 3 x SIFS		 * CTS: duration of immediately previous RTS minus time		 *    required to transmit CTS and its SIFS		 * ACK: 0 if immediately previous directed data/mgmt had		 *    more=0, with more=1 duration in ACK frame is duration		 *    from previous frame minus time needed to transmit ACK		 *    and its SIFS		 * PS Poll: BIT(15) | BIT(14) | aid		 */		return 0;	}	/* data/mgmt */	if (0 /* FIX: data/mgmt during CFP */)		return 32768;	if (group_addr) /* Group address as the destination - no ACK */		return 0;	/* Individual destination address:	 * IEEE 802.11, Ch. 9.6 (after IEEE 802.11g changes)	 * CTS and ACK frames shall be transmitted using the highest rate in	 * basic rate set that is less than or equal to the rate of the	 * immediately previous frame and that is using the same modulation	 * (CCK or OFDM). If no basic rate set matches with these requirements,	 * the highest mandatory rate of the PHY that is less than or equal to	 * the rate of the previous frame is used.	 * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps	 */	rate = -1;	mrate = 10; /* use 1 Mbps if everything fails */	for (i = 0; i < mode->num_rates; i++) {		struct ieee80211_rate *r = &mode->rates[i];		if (r->rate > txrate->rate)			break;		if (IEEE80211_RATE_MODULATION(txrate->flags) !=		    IEEE80211_RATE_MODULATION(r->flags))			continue;		if (r->flags & IEEE80211_RATE_BASIC)			rate = r->rate;		else if (r->flags & IEEE80211_RATE_MANDATORY)			mrate = r->rate;	}	if (rate == -1) {		/* No matching basic rate found; use highest suitable mandatory		 * PHY rate */		rate = mrate;	}	/* Time needed to transmit ACK	 * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up	 * to closest integer */	dur = ieee80211_frame_duration(local, 10, rate, erp,		       tx->sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE);	if (next_frag_len) {		/* Frame is fragmented: duration increases with time needed to		 * transmit next fragment plus ACK and 2 x SIFS. */		dur *= 2; /* ACK + SIFS */		/* next fragment */		dur += ieee80211_frame_duration(local, next_frag_len,				txrate->rate, erp,				tx->sdata->flags &					IEEE80211_SDATA_SHORT_PREAMBLE);	}	return dur;}static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local,					    int queue){	return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);}static inline int __ieee80211_queue_pending(const struct ieee80211_local *local,					    int queue){	return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]);}static int inline is_ieee80211_device(struct net_device *dev,				      struct net_device *master){	return (wdev_priv(dev->ieee80211_ptr) ==		wdev_priv(master->ieee80211_ptr));}/* tx handlers */static ieee80211_txrx_resultieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx){#ifdef CONFIG_MAC80211_VERBOSE_DEBUG	struct sk_buff *skb = tx->skb;	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */	u32 sta_flags;	if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED))		return TXRX_CONTINUE;	if (unlikely(tx->local->sta_scanning != 0) &&	    ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||	     (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))		return TXRX_DROP;	if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)		return TXRX_CONTINUE;	sta_flags = tx->sta ? tx->sta->flags : 0;	if (likely(tx->flags & IEEE80211_TXRXD_TXUNICAST)) {		if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&			     tx->sdata->type != IEEE80211_IF_TYPE_IBSS &&			     (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {#ifdef CONFIG_MAC80211_VERBOSE_DEBUG			DECLARE_MAC_BUF(mac);			printk(KERN_DEBUG "%s: dropped data frame to not "			       "associated station %s\n",			       tx->dev->name, print_mac(mac, hdr->addr1));#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */			I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);			return TXRX_DROP;		}	} else {		if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&			     tx->local->num_sta == 0 &&			     tx->sdata->type != IEEE80211_IF_TYPE_IBSS)) {			/*			 * No associated STAs - no need to send multicast			 * frames.			 */			return TXRX_DROP;		}		return TXRX_CONTINUE;	}	if (unlikely(/* !injected && */ tx->sdata->ieee802_1x &&		     !(sta_flags & WLAN_STA_AUTHORIZED))) {#ifdef CONFIG_MAC80211_VERBOSE_DEBUG		DECLARE_MAC_BUF(mac);		printk(KERN_DEBUG "%s: dropped frame to %s"		       " (unauthorized port)\n", tx->dev->name,		       print_mac(mac, hdr->addr1));#endif		I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port);		return TXRX_DROP;	}	return TXRX_CONTINUE;}static ieee80211_txrx_resultieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx){	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;	if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)		ieee80211_include_sequence(tx->sdata, hdr);	return TXRX_CONTINUE;}/* This function is called whenever the AP is about to exceed the maximum limit * of buffered frames for power saving STAs. This situation should not really * happen often during normal operation, so dropping the oldest buffered packet * from each queue should be OK to make some room for new frames. */static void purge_old_ps_buffers(struct ieee80211_local *local){	int total = 0, purged = 0;	struct sk_buff *skb;	struct ieee80211_sub_if_data *sdata;	struct sta_info *sta;	/*	 * virtual interfaces are protected by RCU	 */	rcu_read_lock();	list_for_each_entry_rcu(sdata, &local->interfaces, list) {		struct ieee80211_if_ap *ap;		if (sdata->dev == local->mdev ||		    sdata->type != IEEE80211_IF_TYPE_AP)			continue;		ap = &sdata->u.ap;		skb = skb_dequeue(&ap->ps_bc_buf);		if (skb) {			purged++;			dev_kfree_skb(skb);		}		total += skb_queue_len(&ap->ps_bc_buf);	}	rcu_read_unlock();	read_lock_bh(&local->sta_lock);	list_for_each_entry(sta, &local->sta_list, list) {		skb = skb_dequeue(&sta->ps_tx_buf);		if (skb) {			purged++;			dev_kfree_skb(skb);		}		total += skb_queue_len(&sta->ps_tx_buf);	}	read_unlock_bh(&local->sta_lock);	local->total_ps_buffered = total;	printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",	       wiphy_name(local->hw.wiphy), purged);}static inline ieee80211_txrx_resultieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx){	/* broadcast/multicast frame */	/* If any of the associated stations is in power save mode,	 * the frame is buffered to be sent after DTIM beacon frame */	if ((tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) &&	    tx->sdata->type != IEEE80211_IF_TYPE_WDS &&	    tx->sdata->bss && atomic_read(&tx->sdata->bss->num_sta_ps) &&	    !(tx->fc & IEEE80211_FCTL_ORDER)) {		if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)			purge_old_ps_buffers(tx->local);		if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >=		    AP_MAX_BC_BUFFER) {			if (net_ratelimit()) {				printk(KERN_DEBUG "%s: BC TX buffer full - "				       "dropping the oldest frame\n",				       tx->dev->name);			}			dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));		} else			tx->local->total_ps_buffered++;		skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);		return TXRX_QUEUED;	}	return TXRX_CONTINUE;}static inline ieee80211_txrx_resultieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx){	struct sta_info *sta = tx->sta;	DECLARE_MAC_BUF(mac);	if (unlikely(!sta ||		     ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&		      (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))		return TXRX_CONTINUE;	if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) {		struct ieee80211_tx_packet_data *pkt_data;#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG		printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "		       "before %d)\n",		       print_mac(mac, sta->addr), sta->aid,		       skb_queue_len(&sta->ps_tx_buf));#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */		sta->flags |= WLAN_STA_TIM;		if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)			purge_old_ps_buffers(tx->local);		if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) {			struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf);			if (net_ratelimit()) {				printk(KERN_DEBUG "%s: STA %s TX "				       "buffer full - dropping oldest frame\n",				       tx->dev->name, print_mac(mac, sta->addr));			}			dev_kfree_skb(old);		} else			tx->local->total_ps_buffered++;		/* Queue frame to be sent after STA sends an PS Poll frame */		if (skb_queue_empty(&sta->ps_tx_buf)) {			if (tx->local->ops->set_tim)				tx->local->ops->set_tim(local_to_hw(tx->local),						       sta->aid, 1);			if (tx->sdata->bss)				bss_tim_set(tx->local, tx->sdata->bss, sta->aid);		}		pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb;		pkt_data->jiffies = jiffies;		skb_queue_tail(&sta->ps_tx_buf, tx->skb);		return TXRX_QUEUED;	}#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG	else if (unlikely(sta->flags & WLAN_STA_PS)) {		printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll "		       "set -> send frame\n", tx->dev->name,		       print_mac(mac, sta->addr));	}#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */	sta->pspoll = 0;	return TXRX_CONTINUE;}static ieee80211_txrx_resultieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx){	if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED))		return TXRX_CONTINUE;	if (tx->flags & IEEE80211_TXRXD_TXUNICAST)		return ieee80211_tx_h_unicast_ps_buf(tx);	else		return ieee80211_tx_h_multicast_ps_buf(tx);}static ieee80211_txrx_resultieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx){	struct ieee80211_key *key;	if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))		tx->key = NULL;	else if (tx->sta && (key = rcu_dereference(tx->sta->key)))		tx->key = key;	else if ((key = rcu_dereference(tx->sdata->default_key)))		tx->key = key;	else if (tx->sdata->drop_unencrypted &&		 !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) {		I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);		return TXRX_DROP;	} else {		tx->key = NULL;		tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;	}	if (tx->key) {		tx->key->tx_rx_count++;		/* TODO: add threshold stuff again */	}	return TXRX_CONTINUE;}static ieee80211_txrx_resultieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx){	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;	size_t hdrlen, per_fragm, num_fragm, payload_len, left;	struct sk_buff **frags, *first, *frag;	int i;	u16 seq;	u8 *pos;	int frag_threshold = tx->local->fragmentation_threshold;

⌨️ 快捷键说明

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