Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -840,7 +840,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)

	/* Only HW csum features are currently compatible with mac80211 */
	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))
		return -EINVAL;

+46 −24
Original line number Diff line number Diff line
@@ -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 sta_info *sta;
	struct sk_buff *next;

	if (unlikely(skb->len < ETH_HLEN)) {
		kfree_skb(skb);
@@ -2864,15 +2865,26 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
			goto out;
	}

	if (skb_is_gso(skb)) {
		struct sk_buff *segs;

		segs = skb_gso_segment(skb, 0);
		if (IS_ERR(segs)) {
			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.
		/* 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)
@@ -2884,6 +2896,15 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
			if (skb_checksum_help(skb))
				goto out_free;
		}
	}

	next = skb;
	while (next) {
		skb = next;
		next = skb->next;

		skb->prev = NULL;
		skb->next = NULL;

		skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
		if (IS_ERR(skb))
@@ -2894,6 +2915,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
		dev->trans_start = jiffies;

		ieee80211_xmit(sdata, sta, skb);
	}
	goto out;
 out_free:
	kfree_skb(skb);