diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/bridge/br_device.c | 4 | ||||
-rw-r--r-- | net/bridge/br_if.c | 3 | ||||
-rw-r--r-- | net/core/dev.c | 33 | ||||
-rw-r--r-- | net/core/skbuff.c | 5 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 6 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 8 |
6 files changed, 40 insertions, 19 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 2afdc7c0736c..f8dbcee80eba 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
@@ -184,6 +184,6 @@ void br_dev_setup(struct net_device *dev) | |||
184 | dev->set_mac_address = br_set_mac_address; | 184 | dev->set_mac_address = br_set_mac_address; |
185 | dev->priv_flags = IFF_EBRIDGE; | 185 | dev->priv_flags = IFF_EBRIDGE; |
186 | 186 | ||
187 | dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | 187 | dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | |
188 | | NETIF_F_HIGHDMA | NETIF_F_TSO | NETIF_F_NO_CSUM; | 188 | NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_GSO_ROBUST; |
189 | } | 189 | } |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 07956ecf545e..f55ef682ef84 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -392,7 +392,8 @@ void br_features_recompute(struct net_bridge *br) | |||
392 | features &= feature; | 392 | features &= feature; |
393 | } | 393 | } |
394 | 394 | ||
395 | br->dev->features = features | checksum | NETIF_F_LLTX; | 395 | br->dev->features = features | checksum | NETIF_F_LLTX | |
396 | NETIF_F_GSO_ROBUST; | ||
396 | } | 397 | } |
397 | 398 | ||
398 | /* called with RTNL */ | 399 | /* called with RTNL */ |
diff --git a/net/core/dev.c b/net/core/dev.c index f1c52cbd6ef7..4f2014994a84 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1190,11 +1190,14 @@ out: | |||
1190 | /** | 1190 | /** |
1191 | * skb_gso_segment - Perform segmentation on skb. | 1191 | * skb_gso_segment - Perform segmentation on skb. |
1192 | * @skb: buffer to segment | 1192 | * @skb: buffer to segment |
1193 | * @sg: whether scatter-gather is supported on the target. | 1193 | * @features: features for the output path (see dev->features) |
1194 | * | 1194 | * |
1195 | * This function segments the given skb and returns a list of segments. | 1195 | * This function segments the given skb and returns a list of segments. |
1196 | * | ||
1197 | * It may return NULL if the skb requires no segmentation. This is | ||
1198 | * only possible when GSO is used for verifying header integrity. | ||
1196 | */ | 1199 | */ |
1197 | struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg) | 1200 | struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features) |
1198 | { | 1201 | { |
1199 | struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); | 1202 | struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); |
1200 | struct packet_type *ptype; | 1203 | struct packet_type *ptype; |
@@ -1210,12 +1213,14 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg) | |||
1210 | rcu_read_lock(); | 1213 | rcu_read_lock(); |
1211 | list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) { | 1214 | list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) { |
1212 | if (ptype->type == type && !ptype->dev && ptype->gso_segment) { | 1215 | if (ptype->type == type && !ptype->dev && ptype->gso_segment) { |
1213 | segs = ptype->gso_segment(skb, sg); | 1216 | segs = ptype->gso_segment(skb, features); |
1214 | break; | 1217 | break; |
1215 | } | 1218 | } |
1216 | } | 1219 | } |
1217 | rcu_read_unlock(); | 1220 | rcu_read_unlock(); |
1218 | 1221 | ||
1222 | __skb_push(skb, skb->data - skb->mac.raw); | ||
1223 | |||
1219 | return segs; | 1224 | return segs; |
1220 | } | 1225 | } |
1221 | 1226 | ||
@@ -1291,9 +1296,15 @@ static int dev_gso_segment(struct sk_buff *skb) | |||
1291 | { | 1296 | { |
1292 | struct net_device *dev = skb->dev; | 1297 | struct net_device *dev = skb->dev; |
1293 | struct sk_buff *segs; | 1298 | struct sk_buff *segs; |
1299 | int features = dev->features & ~(illegal_highdma(dev, skb) ? | ||
1300 | NETIF_F_SG : 0); | ||
1301 | |||
1302 | segs = skb_gso_segment(skb, features); | ||
1303 | |||
1304 | /* Verifying header integrity only. */ | ||
1305 | if (!segs) | ||
1306 | return 0; | ||
1294 | 1307 | ||
1295 | segs = skb_gso_segment(skb, dev->features & NETIF_F_SG && | ||
1296 | !illegal_highdma(dev, skb)); | ||
1297 | if (unlikely(IS_ERR(segs))) | 1308 | if (unlikely(IS_ERR(segs))) |
1298 | return PTR_ERR(segs); | 1309 | return PTR_ERR(segs); |
1299 | 1310 | ||
@@ -1310,13 +1321,17 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1310 | if (netdev_nit) | 1321 | if (netdev_nit) |
1311 | dev_queue_xmit_nit(skb, dev); | 1322 | dev_queue_xmit_nit(skb, dev); |
1312 | 1323 | ||
1313 | if (!netif_needs_gso(dev, skb)) | 1324 | if (netif_needs_gso(dev, skb)) { |
1314 | return dev->hard_start_xmit(skb, dev); | 1325 | if (unlikely(dev_gso_segment(skb))) |
1326 | goto out_kfree_skb; | ||
1327 | if (skb->next) | ||
1328 | goto gso; | ||
1329 | } | ||
1315 | 1330 | ||
1316 | if (unlikely(dev_gso_segment(skb))) | 1331 | return dev->hard_start_xmit(skb, dev); |
1317 | goto out_kfree_skb; | ||
1318 | } | 1332 | } |
1319 | 1333 | ||
1334 | gso: | ||
1320 | do { | 1335 | do { |
1321 | struct sk_buff *nskb = skb->next; | 1336 | struct sk_buff *nskb = skb->next; |
1322 | int rc; | 1337 | int rc; |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6edbb90cbcec..dfef9eece83e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -1848,13 +1848,13 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum); | |||
1848 | /** | 1848 | /** |
1849 | * skb_segment - Perform protocol segmentation on skb. | 1849 | * skb_segment - Perform protocol segmentation on skb. |
1850 | * @skb: buffer to segment | 1850 | * @skb: buffer to segment |
1851 | * @sg: whether scatter-gather can be used for generated segments | 1851 | * @features: features for the output path (see dev->features) |
1852 | * | 1852 | * |
1853 | * This function performs segmentation on the given skb. It returns | 1853 | * This function performs segmentation on the given skb. It returns |
1854 | * the segment at the given position. It returns NULL if there are | 1854 | * the segment at the given position. It returns NULL if there are |
1855 | * no more segments to generate, or when an error is encountered. | 1855 | * no more segments to generate, or when an error is encountered. |
1856 | */ | 1856 | */ |
1857 | struct sk_buff *skb_segment(struct sk_buff *skb, int sg) | 1857 | struct sk_buff *skb_segment(struct sk_buff *skb, int features) |
1858 | { | 1858 | { |
1859 | struct sk_buff *segs = NULL; | 1859 | struct sk_buff *segs = NULL; |
1860 | struct sk_buff *tail = NULL; | 1860 | struct sk_buff *tail = NULL; |
@@ -1863,6 +1863,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int sg) | |||
1863 | unsigned int offset = doffset; | 1863 | unsigned int offset = doffset; |
1864 | unsigned int headroom; | 1864 | unsigned int headroom; |
1865 | unsigned int len; | 1865 | unsigned int len; |
1866 | int sg = features & NETIF_F_SG; | ||
1866 | int nfrags = skb_shinfo(skb)->nr_frags; | 1867 | int nfrags = skb_shinfo(skb)->nr_frags; |
1867 | int err = -ENOMEM; | 1868 | int err = -ENOMEM; |
1868 | int i = 0; | 1869 | int i = 0; |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 461216b47948..8d157157bf8e 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -1097,7 +1097,7 @@ int inet_sk_rebuild_header(struct sock *sk) | |||
1097 | 1097 | ||
1098 | EXPORT_SYMBOL(inet_sk_rebuild_header); | 1098 | EXPORT_SYMBOL(inet_sk_rebuild_header); |
1099 | 1099 | ||
1100 | static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int sg) | 1100 | static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features) |
1101 | { | 1101 | { |
1102 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 1102 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
1103 | struct iphdr *iph; | 1103 | struct iphdr *iph; |
@@ -1126,10 +1126,10 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int sg) | |||
1126 | rcu_read_lock(); | 1126 | rcu_read_lock(); |
1127 | ops = rcu_dereference(inet_protos[proto]); | 1127 | ops = rcu_dereference(inet_protos[proto]); |
1128 | if (ops && ops->gso_segment) | 1128 | if (ops && ops->gso_segment) |
1129 | segs = ops->gso_segment(skb, sg); | 1129 | segs = ops->gso_segment(skb, features); |
1130 | rcu_read_unlock(); | 1130 | rcu_read_unlock(); |
1131 | 1131 | ||
1132 | if (IS_ERR(segs)) | 1132 | if (!segs || unlikely(IS_ERR(segs))) |
1133 | goto out; | 1133 | goto out; |
1134 | 1134 | ||
1135 | skb = segs; | 1135 | skb = segs; |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c04176be7ed1..0336422c88a0 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -2145,7 +2145,7 @@ int compat_tcp_getsockopt(struct sock *sk, int level, int optname, | |||
2145 | EXPORT_SYMBOL(compat_tcp_getsockopt); | 2145 | EXPORT_SYMBOL(compat_tcp_getsockopt); |
2146 | #endif | 2146 | #endif |
2147 | 2147 | ||
2148 | struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg) | 2148 | struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) |
2149 | { | 2149 | { |
2150 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 2150 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
2151 | struct tcphdr *th; | 2151 | struct tcphdr *th; |
@@ -2166,10 +2166,14 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg) | |||
2166 | if (!pskb_may_pull(skb, thlen)) | 2166 | if (!pskb_may_pull(skb, thlen)) |
2167 | goto out; | 2167 | goto out; |
2168 | 2168 | ||
2169 | segs = NULL; | ||
2170 | if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) | ||
2171 | goto out; | ||
2172 | |||
2169 | oldlen = (u16)~skb->len; | 2173 | oldlen = (u16)~skb->len; |
2170 | __skb_pull(skb, thlen); | 2174 | __skb_pull(skb, thlen); |
2171 | 2175 | ||
2172 | segs = skb_segment(skb, sg); | 2176 | segs = skb_segment(skb, features); |
2173 | if (IS_ERR(segs)) | 2177 | if (IS_ERR(segs)) |
2174 | goto out; | 2178 | goto out; |
2175 | 2179 | ||