📄 tx.c
字号:
if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED)) return TXRX_CONTINUE; first = tx->skb; hdrlen = ieee80211_get_hdrlen(tx->fc); payload_len = first->len - hdrlen; per_fragm = frag_threshold - hdrlen - FCS_LEN; num_fragm = DIV_ROUND_UP(payload_len, per_fragm); frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); if (!frags) goto fail; hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ; pos = first->data + hdrlen + per_fragm; left = payload_len - per_fragm; for (i = 0; i < num_fragm - 1; i++) { struct ieee80211_hdr *fhdr; size_t copylen; if (left <= 0) goto fail; /* reserve enough extra head and tail room for possible * encryption */ frag = frags[i] = dev_alloc_skb(tx->local->tx_headroom + frag_threshold + IEEE80211_ENCRYPT_HEADROOM + IEEE80211_ENCRYPT_TAILROOM); if (!frag) goto fail; /* Make sure that all fragments use the same priority so * that they end up using the same TX queue */ frag->priority = first->priority; skb_reserve(frag, tx->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM); fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); memcpy(fhdr, first->data, hdrlen); if (i == num_fragm - 2) fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); copylen = left > per_fragm ? per_fragm : left; memcpy(skb_put(frag, copylen), pos, copylen); pos += copylen; left -= copylen; } skb_trim(first, hdrlen + per_fragm); tx->u.tx.num_extra_frag = num_fragm - 1; tx->u.tx.extra_frag = frags; return TXRX_CONTINUE; fail: printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); if (frags) { for (i = 0; i < num_fragm - 1; i++) if (frags[i]) dev_kfree_skb(frags[i]); kfree(frags); } I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); return TXRX_DROP;}static ieee80211_txrx_resultieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx){ if (!tx->key) return TXRX_CONTINUE; switch (tx->key->conf.alg) { case ALG_WEP: return ieee80211_crypto_wep_encrypt(tx); case ALG_TKIP: return ieee80211_crypto_tkip_encrypt(tx); case ALG_CCMP: return ieee80211_crypto_ccmp_encrypt(tx); } /* not reached */ WARN_ON(1); return TXRX_DROP;}static ieee80211_txrx_resultieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx){ struct rate_control_extra extra; if (likely(!tx->u.tx.rate)) { memset(&extra, 0, sizeof(extra)); extra.mode = tx->u.tx.mode; extra.ethertype = tx->ethertype; tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb, &extra); if (unlikely(extra.probe != NULL)) { tx->u.tx.control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val; tx->u.tx.rate = extra.probe; } else tx->u.tx.control->alt_retry_rate = -1; if (!tx->u.tx.rate) return TXRX_DROP; } else tx->u.tx.control->alt_retry_rate = -1; if (tx->u.tx.mode->mode == MODE_IEEE80211G && (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) && (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && extra.nonerp) { tx->u.tx.last_frag_rate = tx->u.tx.rate; if (extra.probe) tx->flags &= ~IEEE80211_TXRXD_TXPROBE_LAST_FRAG; else tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; tx->u.tx.rate = extra.nonerp; tx->u.tx.control->rate = extra.nonerp; tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; } else { tx->u.tx.last_frag_rate = tx->u.tx.rate; tx->u.tx.control->rate = tx->u.tx.rate; } tx->u.tx.control->tx_rate = tx->u.tx.rate->val; return TXRX_CONTINUE;}static ieee80211_txrx_resultieee80211_tx_h_misc(struct ieee80211_txrx_data *tx){ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; u16 fc = le16_to_cpu(hdr->frame_control); u16 dur; struct ieee80211_tx_control *control = tx->u.tx.control; struct ieee80211_hw_mode *mode = tx->u.tx.mode; if (!control->retry_limit) { if (!is_multicast_ether_addr(hdr->addr1)) { if (tx->skb->len + FCS_LEN > tx->local->rts_threshold && tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) { control->flags |= IEEE80211_TXCTL_USE_RTS_CTS; control->flags |= IEEE80211_TXCTL_LONG_RETRY_LIMIT; control->retry_limit = tx->local->long_retry_limit; } else { control->retry_limit = tx->local->short_retry_limit; } } else { control->retry_limit = 1; } } if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { /* Do not use multiple retry rates when sending fragmented * frames. * TODO: The last fragment could still use multiple retry * rates. */ control->alt_retry_rate = -1; } /* Use CTS protection for unicast frames sent using extended rates if * there are associated non-ERP stations and RTS/CTS is not configured * for the frame. */ if (mode->mode == MODE_IEEE80211G && (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) && (tx->flags & IEEE80211_TXRXD_TXUNICAST) && (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) && !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; /* Transmit data frames using short preambles if the driver supports * short preambles at the selected rate and short preambles are * available on the network at the current point in time. */ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && (tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) && (tx->sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) && (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { tx->u.tx.control->tx_rate = tx->u.tx.rate->val2; } /* Setup duration field for the first fragment of the frame. Duration * for remaining fragments will be updated when they are being sent * to low-level driver in ieee80211_tx(). */ dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), (tx->flags & IEEE80211_TXRXD_FRAGMENTED) ? tx->u.tx.extra_frag[0]->len : 0); hdr->duration_id = cpu_to_le16(dur); if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { struct ieee80211_rate *rate; /* Do not use multiple retry rates when using RTS/CTS */ control->alt_retry_rate = -1; /* Use min(data rate, max base rate) as CTS/RTS rate */ rate = tx->u.tx.rate; while (rate > mode->rates && !(rate->flags & IEEE80211_RATE_BASIC)) rate--; control->rts_cts_rate = rate->val; control->rts_rate = rate; } if (tx->sta) { tx->sta->tx_packets++; tx->sta->tx_fragments++; tx->sta->tx_bytes += tx->skb->len; if (tx->u.tx.extra_frag) { int i; tx->sta->tx_fragments += tx->u.tx.num_extra_frag; for (i = 0; i < tx->u.tx.num_extra_frag; i++) { tx->sta->tx_bytes += tx->u.tx.extra_frag[i]->len; } } } /* * Tell hardware to not encrypt when we had sw crypto. * Because we use the same flag to internally indicate that * no (software) encryption should be done, we have to set it * after all crypto handlers. */ if (tx->key && !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; return TXRX_CONTINUE;}static ieee80211_txrx_resultieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx){ struct ieee80211_local *local = tx->local; struct ieee80211_hw_mode *mode = tx->u.tx.mode; struct sk_buff *skb = tx->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u32 load = 0, hdrtime; /* TODO: this could be part of tx_status handling, so that the number * of retries would be known; TX rate should in that case be stored * somewhere with the packet */ /* Estimate total channel use caused by this frame */ /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, * 1 usec = 1/8 * (1080 / 10) = 13.5 */ if (mode->mode == MODE_IEEE80211A || (mode->mode == MODE_IEEE80211G && tx->u.tx.rate->flags & IEEE80211_RATE_ERP)) hdrtime = CHAN_UTIL_HDR_SHORT; else hdrtime = CHAN_UTIL_HDR_LONG; load = hdrtime; if (!is_multicast_ether_addr(hdr->addr1)) load += hdrtime; if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_RTS_CTS) load += 2 * hdrtime; else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) load += hdrtime; load += skb->len * tx->u.tx.rate->rate_inv; if (tx->u.tx.extra_frag) { int i; for (i = 0; i < tx->u.tx.num_extra_frag; i++) { load += 2 * hdrtime; load += tx->u.tx.extra_frag[i]->len * tx->u.tx.rate->rate; } } /* Divide channel_use by 8 to avoid wrapping around the counter */ load >>= CHAN_UTIL_SHIFT; local->channel_use_raw += load; if (tx->sta) tx->sta->channel_use_raw += load; tx->sdata->channel_use_raw += load; return TXRX_CONTINUE;}/* TODO: implement register/unregister functions for adding TX/RX handlers * into ordered list */ieee80211_tx_handler ieee80211_tx_handlers[] ={ ieee80211_tx_h_check_assoc, ieee80211_tx_h_sequence, ieee80211_tx_h_ps_buf, ieee80211_tx_h_select_key, ieee80211_tx_h_michael_mic_add, ieee80211_tx_h_fragment, ieee80211_tx_h_encrypt, ieee80211_tx_h_rate_ctrl, ieee80211_tx_h_misc, ieee80211_tx_h_load_stats, NULL};/* actual transmit path *//* * deal with packet injection down monitor interface * with Radiotap Header -- only called for monitor mode interface */static ieee80211_txrx_result__ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, struct sk_buff *skb){ /* * this is the moment to interpret and discard the radiotap header that * must be at the start of the packet injected in Monitor mode * * Need to take some care with endian-ness since radiotap * args are little-endian */ struct ieee80211_radiotap_iterator iterator; struct ieee80211_radiotap_header *rthdr = (struct ieee80211_radiotap_header *) skb->data; struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode; int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); struct ieee80211_tx_control *control = tx->u.tx.control; control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; tx->flags |= IEEE80211_TXRXD_TX_INJECTED; tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; /* * for every radiotap entry that is present * (ieee80211_radiotap_iterator_next returns -ENOENT when no more * entries present, or -EINVAL on error) */ while (!ret) { int i, target_rate; ret = ieee80211_radiotap_iterator_next(&iterator); if (ret) continue; /* see if this argument is something we can use */ switch (iterator.this_arg_index) { /* * You must take care when dereferencing iterator.this_arg * for multibyte types... the pointer is not aligned. Use * get_unaligned((type *)iterator.this_arg) to dereference * iterator.this_arg for type "type" safely on all arches. */ case IEEE80211_RADIOTAP_RATE: /* * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps */ target_rate = (*iterator.this_arg) * 5; for (i = 0; i < mode->num_rates; i++) { struct ieee80211_rate *r = &mode->rates[i]; if (r->rate == target_rate) { tx->u.tx.rate = r; break; } } break; case IEEE80211_RADIOTAP_ANTENNA: /* * radiotap uses 0 for 1st ant, mac80211 is 1 for * 1st ant */ control->antenna_sel_tx = (*iterator.this_arg) + 1; break; case IEEE80211_RADIOTAP_DBM_TX_POWER: control->power_level = *iterator.this_arg; break; case IEEE80211_RADIOTAP_FLAGS: if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) { /* * this indicates that the skb we have been * handed has the 32-bit FCS CRC at the end... * we should react to that by snipping it off * because it will be recomputed and added * on transmission */ if (skb->len < (iterator.max_length + FCS_LEN)) return TXRX_DROP; skb_trim(skb, skb->len - FCS_LEN); } if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) control->flags &= ~IEEE80211_TXCTL_DO_NOT_ENCRYPT; if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) tx->flags |= IEEE80211_TXRXD_FRAGMENTED; break; /* * Please update the file * Documentation/networking/mac80211-injection.txt * when parsing new fields here. */ default: break; } } if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ return TXRX_DROP; /* * remove the radiotap header * iterator->max_length was sanity-checked against * skb->len by iterator init */ skb_pull(skb, iterator.max_length); return TXRX_CONTINUE;}/* * initialises @tx */static ieee80211_txrx_result__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, struct sk_buff *skb, struct net_device *dev, struct ieee80211_tx_control *control){ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr; struct ieee80211_sub_if_data *sdata; ieee80211_txrx_result res = TXRX_CONTINUE; int hdrlen; memset(tx, 0, sizeof(*tx)); tx->skb = skb; tx->dev = dev; /* use original interface */ tx->local = local; tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); tx->u.tx.control = control; /* * Set this flag (used below to indicate "automatic fragmentation"), * it will be cleared/left by radiotap as desired. */ tx->flags |= IEEE80211_TXRXD_FRAGMENTED; /* process and remove the injection radiotap header */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) { if (__ieee80211_parse_tx_radiotap(tx, skb) == TXRX_DROP) return TXRX_DROP; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -