aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/udp_offload.c
diff options
context:
space:
mode:
authorTom Herbert <therbert@google.com>2014-07-13 22:49:56 -0400
committerDavid S. Miller <davem@davemloft.net>2014-07-14 19:12:15 -0400
commit155e010edbc168f43bb332887c43e8579ee3894a (patch)
treefe501117127ec38d2ef4402681ff3bc53f245379 /net/ipv4/udp_offload.c
parent85644b4d0c6f7be64dad461057d78a484b45bf5b (diff)
udp: Move udp_tunnel_segment into udp_offload.c
Signed-off-by: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/udp_offload.c')
-rw-r--r--net/ipv4/udp_offload.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 546d2d439dda..4807544d018b 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -47,6 +47,82 @@ static int udp4_ufo_send_check(struct sk_buff *skb)
47 return 0; 47 return 0;
48} 48}
49 49
50struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
51 netdev_features_t features)
52{
53 struct sk_buff *segs = ERR_PTR(-EINVAL);
54 u16 mac_offset = skb->mac_header;
55 int mac_len = skb->mac_len;
56 int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
57 __be16 protocol = skb->protocol;
58 netdev_features_t enc_features;
59 int udp_offset, outer_hlen;
60 unsigned int oldlen;
61 bool need_csum;
62
63 oldlen = (u16)~skb->len;
64
65 if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
66 goto out;
67
68 skb->encapsulation = 0;
69 __skb_pull(skb, tnl_hlen);
70 skb_reset_mac_header(skb);
71 skb_set_network_header(skb, skb_inner_network_offset(skb));
72 skb->mac_len = skb_inner_network_offset(skb);
73 skb->protocol = htons(ETH_P_TEB);
74
75 need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM);
76 if (need_csum)
77 skb->encap_hdr_csum = 1;
78
79 /* segment inner packet. */
80 enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
81 segs = skb_mac_gso_segment(skb, enc_features);
82 if (!segs || IS_ERR(segs)) {
83 skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset,
84 mac_len);
85 goto out;
86 }
87
88 outer_hlen = skb_tnl_header_len(skb);
89 udp_offset = outer_hlen - tnl_hlen;
90 skb = segs;
91 do {
92 struct udphdr *uh;
93 int len;
94
95 skb_reset_inner_headers(skb);
96 skb->encapsulation = 1;
97
98 skb->mac_len = mac_len;
99
100 skb_push(skb, outer_hlen);
101 skb_reset_mac_header(skb);
102 skb_set_network_header(skb, mac_len);
103 skb_set_transport_header(skb, udp_offset);
104 len = skb->len - udp_offset;
105 uh = udp_hdr(skb);
106 uh->len = htons(len);
107
108 if (need_csum) {
109 __be32 delta = htonl(oldlen + len);
110
111 uh->check = ~csum_fold((__force __wsum)
112 ((__force u32)uh->check +
113 (__force u32)delta));
114 uh->check = gso_make_checksum(skb, ~uh->check);
115
116 if (uh->check == 0)
117 uh->check = CSUM_MANGLED_0;
118 }
119
120 skb->protocol = protocol;
121 } while ((skb = skb->next));
122out:
123 return segs;
124}
125
50static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, 126static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
51 netdev_features_t features) 127 netdev_features_t features)
52{ 128{