|
55 | 55 | #include <net/inet_common.h>
|
56 | 56 | #include <net/inet_ecn.h>
|
57 | 57 | #include <net/sctp/sctp.h>
|
| 58 | +#include <net/udp_tunnel.h> |
58 | 59 |
|
59 | 60 | #include <linux/uaccess.h>
|
60 | 61 |
|
@@ -191,33 +192,53 @@ static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
191 | 192 | return ret;
|
192 | 193 | }
|
193 | 194 |
|
194 |
| -static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) |
| 195 | +static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t) |
195 | 196 | {
|
| 197 | + struct dst_entry *dst = dst_clone(t->dst); |
| 198 | + struct flowi6 *fl6 = &t->fl.u.ip6; |
196 | 199 | struct sock *sk = skb->sk;
|
197 | 200 | struct ipv6_pinfo *np = inet6_sk(sk);
|
198 |
| - struct flowi6 *fl6 = &transport->fl.u.ip6; |
199 | 201 | __u8 tclass = np->tclass;
|
200 |
| - int res; |
| 202 | + __be32 label; |
201 | 203 |
|
202 | 204 | pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb,
|
203 | 205 | skb->len, &fl6->saddr, &fl6->daddr);
|
204 | 206 |
|
205 |
| - if (transport->dscp & SCTP_DSCP_SET_MASK) |
206 |
| - tclass = transport->dscp & SCTP_DSCP_VAL_MASK; |
| 207 | + if (t->dscp & SCTP_DSCP_SET_MASK) |
| 208 | + tclass = t->dscp & SCTP_DSCP_VAL_MASK; |
207 | 209 |
|
208 | 210 | if (INET_ECN_is_capable(tclass))
|
209 | 211 | IP6_ECN_flow_xmit(sk, fl6->flowlabel);
|
210 | 212 |
|
211 |
| - if (!(transport->param_flags & SPP_PMTUD_ENABLE)) |
| 213 | + if (!(t->param_flags & SPP_PMTUD_ENABLE)) |
212 | 214 | skb->ignore_df = 1;
|
213 | 215 |
|
214 | 216 | SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
|
215 | 217 |
|
216 |
| - rcu_read_lock(); |
217 |
| - res = ip6_xmit(sk, skb, fl6, sk->sk_mark, rcu_dereference(np->opt), |
218 |
| - tclass, sk->sk_priority); |
219 |
| - rcu_read_unlock(); |
220 |
| - return res; |
| 218 | + if (!t->encap_port || !sctp_sk(sk)->udp_port) { |
| 219 | + int res; |
| 220 | + |
| 221 | + skb_dst_set(skb, dst); |
| 222 | + rcu_read_lock(); |
| 223 | + res = ip6_xmit(sk, skb, fl6, sk->sk_mark, |
| 224 | + rcu_dereference(np->opt), |
| 225 | + tclass, sk->sk_priority); |
| 226 | + rcu_read_unlock(); |
| 227 | + return res; |
| 228 | + } |
| 229 | + |
| 230 | + if (skb_is_gso(skb)) |
| 231 | + skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM; |
| 232 | + |
| 233 | + skb->encapsulation = 1; |
| 234 | + skb_reset_inner_mac_header(skb); |
| 235 | + skb_reset_inner_transport_header(skb); |
| 236 | + skb_set_inner_ipproto(skb, IPPROTO_SCTP); |
| 237 | + label = ip6_make_flowlabel(sock_net(sk), skb, fl6->flowlabel, true, fl6); |
| 238 | + |
| 239 | + return udp_tunnel6_xmit_skb(dst, sk, skb, NULL, &fl6->saddr, |
| 240 | + &fl6->daddr, tclass, ip6_dst_hoplimit(dst), |
| 241 | + label, sctp_sk(sk)->udp_port, t->encap_port, false); |
221 | 242 | }
|
222 | 243 |
|
223 | 244 | /* Returns the dst cache entry for the given source and destination ip
|
|
0 commit comments