|
@@ -1190,11 +1190,14 @@ out:
|
|
|
/**
|
|
|
* skb_gso_segment - Perform segmentation on skb.
|
|
|
* @skb: buffer to segment
|
|
|
- * @sg: whether scatter-gather is supported on the target.
|
|
|
+ * @features: features for the output path (see dev->features)
|
|
|
*
|
|
|
* This function segments the given skb and returns a list of segments.
|
|
|
+ *
|
|
|
+ * It may return NULL if the skb requires no segmentation. This is
|
|
|
+ * only possible when GSO is used for verifying header integrity.
|
|
|
*/
|
|
|
-struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg)
|
|
|
+struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
|
|
|
{
|
|
|
struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
|
|
|
struct packet_type *ptype;
|
|
@@ -1210,12 +1213,14 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg)
|
|
|
rcu_read_lock();
|
|
|
list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
|
|
|
if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
|
|
|
- segs = ptype->gso_segment(skb, sg);
|
|
|
+ segs = ptype->gso_segment(skb, features);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
+ __skb_push(skb, skb->data - skb->mac.raw);
|
|
|
+
|
|
|
return segs;
|
|
|
}
|
|
|
|
|
@@ -1291,9 +1296,15 @@ static int dev_gso_segment(struct sk_buff *skb)
|
|
|
{
|
|
|
struct net_device *dev = skb->dev;
|
|
|
struct sk_buff *segs;
|
|
|
+ int features = dev->features & ~(illegal_highdma(dev, skb) ?
|
|
|
+ NETIF_F_SG : 0);
|
|
|
+
|
|
|
+ segs = skb_gso_segment(skb, features);
|
|
|
+
|
|
|
+ /* Verifying header integrity only. */
|
|
|
+ if (!segs)
|
|
|
+ return 0;
|
|
|
|
|
|
- segs = skb_gso_segment(skb, dev->features & NETIF_F_SG &&
|
|
|
- !illegal_highdma(dev, skb));
|
|
|
if (unlikely(IS_ERR(segs)))
|
|
|
return PTR_ERR(segs);
|
|
|
|
|
@@ -1310,13 +1321,17 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
|
if (netdev_nit)
|
|
|
dev_queue_xmit_nit(skb, dev);
|
|
|
|
|
|
- if (!netif_needs_gso(dev, skb))
|
|
|
- return dev->hard_start_xmit(skb, dev);
|
|
|
+ if (netif_needs_gso(dev, skb)) {
|
|
|
+ if (unlikely(dev_gso_segment(skb)))
|
|
|
+ goto out_kfree_skb;
|
|
|
+ if (skb->next)
|
|
|
+ goto gso;
|
|
|
+ }
|
|
|
|
|
|
- if (unlikely(dev_gso_segment(skb)))
|
|
|
- goto out_kfree_skb;
|
|
|
+ return dev->hard_start_xmit(skb, dev);
|
|
|
}
|
|
|
|
|
|
+gso:
|
|
|
do {
|
|
|
struct sk_buff *nskb = skb->next;
|
|
|
int rc;
|