diff options
author | Tom Herbert <therbert@google.com> | 2014-07-13 22:49:56 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-14 19:12:15 -0400 |
commit | 155e010edbc168f43bb332887c43e8579ee3894a (patch) | |
tree | fe501117127ec38d2ef4402681ff3bc53f245379 /net/ipv4/udp_offload.c | |
parent | 85644b4d0c6f7be64dad461057d78a484b45bf5b (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.c | 76 |
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 | ||
50 | struct 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)); | ||
122 | out: | ||
123 | return segs; | ||
124 | } | ||
125 | |||
50 | static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, | 126 | static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, |
51 | netdev_features_t features) | 127 | netdev_features_t features) |
52 | { | 128 | { |