Commit 80616c0d authored by Johannes Berg's avatar Johannes Berg

mac80211: allow segmentation offloads

Implement the necessary software segmentation on the normal
TX path so that fast-xmit can use segmentation offload if
the hardware (or driver) supports it.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 680a0dab
...@@ -840,7 +840,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -840,7 +840,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
/* Only HW csum features are currently compatible with mac80211 */ /* Only HW csum features are currently compatible with mac80211 */
feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA; NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA |
NETIF_F_GSO_SOFTWARE;
if (WARN_ON(hw->netdev_features & ~feature_whitelist)) if (WARN_ON(hw->netdev_features & ~feature_whitelist))
return -EINVAL; return -EINVAL;
......
...@@ -2843,6 +2843,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, ...@@ -2843,6 +2843,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta; struct sta_info *sta;
struct sk_buff *next;
if (unlikely(skb->len < ETH_HLEN)) { if (unlikely(skb->len < ETH_HLEN)) {
kfree_skb(skb); kfree_skb(skb);
...@@ -2864,36 +2865,57 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, ...@@ -2864,36 +2865,57 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
goto out; goto out;
} }
/* we cannot process non-linear frames on this path */ if (skb_is_gso(skb)) {
if (skb_linearize(skb)) { struct sk_buff *segs;
kfree_skb(skb);
goto out;
}
/* the frame could be fragmented, software-encrypted, and other things segs = skb_gso_segment(skb, 0);
* so we cannot really handle checksum offload with it - fix it up in if (IS_ERR(segs)) {
* software before we handle anything else.
*/
if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (skb->encapsulation)
skb_set_inner_transport_header(skb,
skb_checksum_start_offset(skb));
else
skb_set_transport_header(skb,
skb_checksum_start_offset(skb));
if (skb_checksum_help(skb))
goto out_free; goto out_free;
} else if (segs) {
consume_skb(skb);
skb = segs;
}
} else {
/* we cannot process non-linear frames on this path */
if (skb_linearize(skb)) {
kfree_skb(skb);
goto out;
}
/* the frame could be fragmented, software-encrypted, and other
* things so we cannot really handle checksum offload with it -
* fix it up in software before we handle anything else.
*/
if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (skb->encapsulation)
skb_set_inner_transport_header(skb,
skb_checksum_start_offset(skb));
else
skb_set_transport_header(skb,
skb_checksum_start_offset(skb));
if (skb_checksum_help(skb))
goto out_free;
}
} }
skb = ieee80211_build_hdr(sdata, skb, info_flags, sta); next = skb;
if (IS_ERR(skb)) while (next) {
goto out; skb = next;
next = skb->next;
dev->stats.tx_packets++; skb->prev = NULL;
dev->stats.tx_bytes += skb->len; skb->next = NULL;
dev->trans_start = jiffies;
skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
if (IS_ERR(skb))
goto out;
ieee80211_xmit(sdata, sta, skb); dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
dev->trans_start = jiffies;
ieee80211_xmit(sdata, sta, skb);
}
goto out; goto out;
out_free: out_free:
kfree_skb(skb); kfree_skb(skb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment