diff options
Diffstat (limited to 'net/ipv4/af_inet.c')
-rw-r--r-- | net/ipv4/af_inet.c | 34 |
1 files changed, 27 insertions, 7 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4f8cd4fc451d..4049906010f7 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -1273,16 +1273,17 @@ out: | |||
1273 | } | 1273 | } |
1274 | 1274 | ||
1275 | static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | 1275 | static struct sk_buff *inet_gso_segment(struct sk_buff *skb, |
1276 | netdev_features_t features) | 1276 | netdev_features_t features) |
1277 | { | 1277 | { |
1278 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 1278 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
1279 | const struct net_offload *ops; | 1279 | const struct net_offload *ops; |
1280 | unsigned int offset = 0; | ||
1280 | struct iphdr *iph; | 1281 | struct iphdr *iph; |
1282 | bool tunnel; | ||
1281 | int proto; | 1283 | int proto; |
1284 | int nhoff; | ||
1282 | int ihl; | 1285 | int ihl; |
1283 | int id; | 1286 | int id; |
1284 | unsigned int offset = 0; | ||
1285 | bool tunnel; | ||
1286 | 1287 | ||
1287 | if (unlikely(skb_shinfo(skb)->gso_type & | 1288 | if (unlikely(skb_shinfo(skb)->gso_type & |
1288 | ~(SKB_GSO_TCPV4 | | 1289 | ~(SKB_GSO_TCPV4 | |
@@ -1290,12 +1291,15 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1290 | SKB_GSO_DODGY | | 1291 | SKB_GSO_DODGY | |
1291 | SKB_GSO_TCP_ECN | | 1292 | SKB_GSO_TCP_ECN | |
1292 | SKB_GSO_GRE | | 1293 | SKB_GSO_GRE | |
1294 | SKB_GSO_IPIP | | ||
1293 | SKB_GSO_TCPV6 | | 1295 | SKB_GSO_TCPV6 | |
1294 | SKB_GSO_UDP_TUNNEL | | 1296 | SKB_GSO_UDP_TUNNEL | |
1295 | SKB_GSO_MPLS | | 1297 | SKB_GSO_MPLS | |
1296 | 0))) | 1298 | 0))) |
1297 | goto out; | 1299 | goto out; |
1298 | 1300 | ||
1301 | skb_reset_network_header(skb); | ||
1302 | nhoff = skb_network_header(skb) - skb_mac_header(skb); | ||
1299 | if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) | 1303 | if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) |
1300 | goto out; | 1304 | goto out; |
1301 | 1305 | ||
@@ -1312,7 +1316,10 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1312 | goto out; | 1316 | goto out; |
1313 | __skb_pull(skb, ihl); | 1317 | __skb_pull(skb, ihl); |
1314 | 1318 | ||
1315 | tunnel = !!skb->encapsulation; | 1319 | tunnel = SKB_GSO_CB(skb)->encap_level > 0; |
1320 | if (tunnel) | ||
1321 | features = skb->dev->hw_enc_features & netif_skb_features(skb); | ||
1322 | SKB_GSO_CB(skb)->encap_level += ihl; | ||
1316 | 1323 | ||
1317 | skb_reset_transport_header(skb); | 1324 | skb_reset_transport_header(skb); |
1318 | 1325 | ||
@@ -1327,18 +1334,23 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1327 | 1334 | ||
1328 | skb = segs; | 1335 | skb = segs; |
1329 | do { | 1336 | do { |
1330 | iph = ip_hdr(skb); | 1337 | iph = (struct iphdr *)(skb_mac_header(skb) + nhoff); |
1331 | if (!tunnel && proto == IPPROTO_UDP) { | 1338 | if (!tunnel && proto == IPPROTO_UDP) { |
1332 | iph->id = htons(id); | 1339 | iph->id = htons(id); |
1333 | iph->frag_off = htons(offset >> 3); | 1340 | iph->frag_off = htons(offset >> 3); |
1334 | if (skb->next != NULL) | 1341 | if (skb->next != NULL) |
1335 | iph->frag_off |= htons(IP_MF); | 1342 | iph->frag_off |= htons(IP_MF); |
1336 | offset += (skb->len - skb->mac_len - iph->ihl * 4); | 1343 | offset += skb->len - nhoff - ihl; |
1337 | } else { | 1344 | } else { |
1338 | iph->id = htons(id++); | 1345 | iph->id = htons(id++); |
1339 | } | 1346 | } |
1340 | iph->tot_len = htons(skb->len - skb->mac_len); | 1347 | iph->tot_len = htons(skb->len - nhoff); |
1341 | ip_send_check(iph); | 1348 | ip_send_check(iph); |
1349 | if (tunnel) { | ||
1350 | skb_reset_inner_headers(skb); | ||
1351 | skb->encapsulation = 1; | ||
1352 | } | ||
1353 | skb->network_header = (u8 *)iph - skb->head; | ||
1342 | } while ((skb = skb->next)); | 1354 | } while ((skb = skb->next)); |
1343 | 1355 | ||
1344 | out: | 1356 | out: |
@@ -1645,6 +1657,13 @@ static struct packet_offload ip_packet_offload __read_mostly = { | |||
1645 | }, | 1657 | }, |
1646 | }; | 1658 | }; |
1647 | 1659 | ||
1660 | static const struct net_offload ipip_offload = { | ||
1661 | .callbacks = { | ||
1662 | .gso_send_check = inet_gso_send_check, | ||
1663 | .gso_segment = inet_gso_segment, | ||
1664 | }, | ||
1665 | }; | ||
1666 | |||
1648 | static int __init ipv4_offload_init(void) | 1667 | static int __init ipv4_offload_init(void) |
1649 | { | 1668 | { |
1650 | /* | 1669 | /* |
@@ -1656,6 +1675,7 @@ static int __init ipv4_offload_init(void) | |||
1656 | pr_crit("%s: Cannot add TCP protocol offload\n", __func__); | 1675 | pr_crit("%s: Cannot add TCP protocol offload\n", __func__); |
1657 | 1676 | ||
1658 | dev_add_offload(&ip_packet_offload); | 1677 | dev_add_offload(&ip_packet_offload); |
1678 | inet_add_offload(&ipip_offload, IPPROTO_IPIP); | ||
1659 | return 0; | 1679 | return 0; |
1660 | } | 1680 | } |
1661 | 1681 | ||