📄 tx.c
字号:
/* * 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 + -