staticint libipw_encrypt_fragment(struct libipw_device *ieee, struct sk_buff *frag, int hdr_len)
{ struct libipw_crypt_data *crypt =
ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; int res;
if (crypt == NULL) return -1;
/* To encrypt, frame format is:
* IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
atomic_inc(&crypt->refcnt);
res = 0; if (crypt->ops && crypt->ops->encrypt_mpdu)
res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
void libipw_txb_free(struct libipw_txb *txb)
{ int i; if (unlikely(!txb)) return; for (i = 0; i < txb->nr_frags; i++) if (txb->fragments[i])
dev_kfree_skb_any(txb->fragments[i]);
kfree(txb);
}
staticstruct libipw_txb *libipw_alloc_txb(int nr_frags, int txb_size, int headroom, gfp_t gfp_mask)
{ struct libipw_txb *txb; int i;
txb = kzalloc(struct_size(txb, fragments, nr_frags), gfp_mask); if (!txb) return NULL;
/* Incoming skb is converted to a txb which consists of
* a block of 802.11 fragment packets (stored as skbs) */
netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev)
{ struct libipw_device *ieee = netdev_priv(dev); struct libipw_txb *txb = NULL; struct libipw_hdr_3addrqos *frag_hdr; int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
rts_required; unsignedlong flags; int encrypt, host_encrypt, host_encrypt_msdu;
__be16 ether_type; int bytes, fc, hdr_len; struct sk_buff *skb_frag; struct libipw_hdr_3addrqos header = {/* Ensure zero initialized */
.duration_id = 0,
.seq_ctl = 0,
.qos_ctl = 0
};
u8 dest[ETH_ALEN], src[ETH_ALEN]; struct libipw_crypt_data *crypt; int priority = skb->priority; int snapped = 0;
if (ieee->is_queue_full && (*ieee->is_queue_full) (dev, priority)) return NETDEV_TX_BUSY;
spin_lock_irqsave(&ieee->lock, flags);
/* If there is no driver handler to take the TXB, dont' bother
* creating it... */ if (!ieee->hard_start_xmit) {
printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name); goto success;
}
if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
printk(KERN_WARNING "%s: skb too small (%d).\n",
ieee->dev->name, skb->len); goto success;
}
/* Advance the SKB to the start of the payload */
skb_pull(skb, sizeof(struct ethhdr));
/* Determine total amount of storage required for TXB packets */
bytes = skb->len + SNAP_SIZE + sizeof(u16);
/* Encrypt msdu first on the whole data packet. */ if ((host_encrypt || host_encrypt_msdu) &&
crypt && crypt->ops && crypt->ops->encrypt_msdu) { int res = 0; int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len +
crypt->ops->extra_msdu_postfix_len; struct sk_buff *skb_new = dev_alloc_skb(len);
if (host_encrypt || ieee->host_open_frag) { /* Determine fragmentation size based on destination (multicast
* and broadcast are not fragmented) */ if (is_multicast_ether_addr(dest) ||
is_broadcast_ether_addr(dest))
frag_size = MAX_FRAG_THRESHOLD; else
frag_size = ieee->fts;
/* Determine amount of payload per fragment. Regardless of if *thisstackisprovidingthefull802.11header,onewill *eventuallybeaffixedtothisfragment--sowemustaccount
* for it when determining the amount of payload space. */
bytes_per_frag = frag_size - hdr_len; if (ieee->config &
(CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
bytes_per_frag -= LIBIPW_FCS_LEN;
/* Each fragment may need to have room for encryption
* pre/postfix */ if (host_encrypt && crypt && crypt->ops)
bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
crypt->ops->extra_mpdu_postfix_len;
/* Number of fragments is the total
* bytes_per_frag / payload_per_fragment */
nr_frags = bytes / bytes_per_frag;
bytes_last_frag = bytes % bytes_per_frag; if (bytes_last_frag)
nr_frags++; else
bytes_last_frag = bytes_per_frag;
} else {
nr_frags = 1;
bytes_per_frag = bytes_last_frag = bytes;
frag_size = bytes + hdr_len;
}
/* If this is not the last fragment, then add the MOREFRAGS
* bit to the frame control */ if (i != nr_frags - 1) {
frag_hdr->frame_ctl =
cpu_to_le16(fc | IEEE80211_FCTL_MOREFRAGS);
bytes = bytes_per_frag;
} else { /* The last fragment takes the remaining length */
bytes = bytes_last_frag;
}
if (i == 0 && !snapped) {
libipw_copy_snap(skb_put
(skb_frag, SNAP_SIZE + sizeof(u16)),
ether_type);
bytes -= SNAP_SIZE + sizeof(u16);
}
/* Encryption routine will move the header forward in order
* to insert the IV between the header and the payload */ if (host_encrypt)
libipw_encrypt_fragment(ieee, skb_frag, hdr_len);
if (ieee->config &
(CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
skb_put(skb_frag, 4);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.