diff options
Diffstat (limited to 'net/sctp/ipv6.c')
-rw-r--r-- | net/sctp/ipv6.c | 44 |
1 files changed, 14 insertions, 30 deletions
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index da613ceae28c..e7b2d4fe2b6a 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -183,7 +183,7 @@ static void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
183 | break; | 183 | break; |
184 | case NDISC_REDIRECT: | 184 | case NDISC_REDIRECT: |
185 | sctp_icmp_redirect(sk, transport, skb); | 185 | sctp_icmp_redirect(sk, transport, skb); |
186 | break; | 186 | goto out_unlock; |
187 | default: | 187 | default: |
188 | break; | 188 | break; |
189 | } | 189 | } |
@@ -204,44 +204,23 @@ out: | |||
204 | in6_dev_put(idev); | 204 | in6_dev_put(idev); |
205 | } | 205 | } |
206 | 206 | ||
207 | /* Based on tcp_v6_xmit() in tcp_ipv6.c. */ | ||
208 | static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) | 207 | static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) |
209 | { | 208 | { |
210 | struct sock *sk = skb->sk; | 209 | struct sock *sk = skb->sk; |
211 | struct ipv6_pinfo *np = inet6_sk(sk); | 210 | struct ipv6_pinfo *np = inet6_sk(sk); |
212 | struct flowi6 fl6; | 211 | struct flowi6 *fl6 = &transport->fl.u.ip6; |
213 | |||
214 | memset(&fl6, 0, sizeof(fl6)); | ||
215 | |||
216 | fl6.flowi6_proto = sk->sk_protocol; | ||
217 | |||
218 | /* Fill in the dest address from the route entry passed with the skb | ||
219 | * and the source address from the transport. | ||
220 | */ | ||
221 | fl6.daddr = transport->ipaddr.v6.sin6_addr; | ||
222 | fl6.saddr = transport->saddr.v6.sin6_addr; | ||
223 | |||
224 | fl6.flowlabel = np->flow_label; | ||
225 | IP6_ECN_flow_xmit(sk, fl6.flowlabel); | ||
226 | if (ipv6_addr_type(&fl6.saddr) & IPV6_ADDR_LINKLOCAL) | ||
227 | fl6.flowi6_oif = transport->saddr.v6.sin6_scope_id; | ||
228 | else | ||
229 | fl6.flowi6_oif = sk->sk_bound_dev_if; | ||
230 | |||
231 | if (np->opt && np->opt->srcrt) { | ||
232 | struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; | ||
233 | fl6.daddr = *rt0->addr; | ||
234 | } | ||
235 | 212 | ||
236 | pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb, | 213 | pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb, |
237 | skb->len, &fl6.saddr, &fl6.daddr); | 214 | skb->len, &fl6->saddr, &fl6->daddr); |
238 | 215 | ||
239 | SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS); | 216 | IP6_ECN_flow_xmit(sk, fl6->flowlabel); |
240 | 217 | ||
241 | if (!(transport->param_flags & SPP_PMTUD_ENABLE)) | 218 | if (!(transport->param_flags & SPP_PMTUD_ENABLE)) |
242 | skb->local_df = 1; | 219 | skb->local_df = 1; |
243 | 220 | ||
244 | return ip6_xmit(sk, skb, &fl6, np->opt, np->tclass); | 221 | SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS); |
222 | |||
223 | return ip6_xmit(sk, skb, fl6, np->opt, np->tclass); | ||
245 | } | 224 | } |
246 | 225 | ||
247 | /* Returns the dst cache entry for the given source and destination ip | 226 | /* Returns the dst cache entry for the given source and destination ip |
@@ -254,10 +233,12 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
254 | struct dst_entry *dst = NULL; | 233 | struct dst_entry *dst = NULL; |
255 | struct flowi6 *fl6 = &fl->u.ip6; | 234 | struct flowi6 *fl6 = &fl->u.ip6; |
256 | struct sctp_bind_addr *bp; | 235 | struct sctp_bind_addr *bp; |
236 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
257 | struct sctp_sockaddr_entry *laddr; | 237 | struct sctp_sockaddr_entry *laddr; |
258 | union sctp_addr *baddr = NULL; | 238 | union sctp_addr *baddr = NULL; |
259 | union sctp_addr *daddr = &t->ipaddr; | 239 | union sctp_addr *daddr = &t->ipaddr; |
260 | union sctp_addr dst_saddr; | 240 | union sctp_addr dst_saddr; |
241 | struct in6_addr *final_p, final; | ||
261 | __u8 matchlen = 0; | 242 | __u8 matchlen = 0; |
262 | __u8 bmatchlen; | 243 | __u8 bmatchlen; |
263 | sctp_scope_t scope; | 244 | sctp_scope_t scope; |
@@ -281,7 +262,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
281 | pr_debug("src=%pI6 - ", &fl6->saddr); | 262 | pr_debug("src=%pI6 - ", &fl6->saddr); |
282 | } | 263 | } |
283 | 264 | ||
284 | dst = ip6_dst_lookup_flow(sk, fl6, NULL, false); | 265 | final_p = fl6_update_dst(fl6, np->opt, &final); |
266 | dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); | ||
285 | if (!asoc || saddr) | 267 | if (!asoc || saddr) |
286 | goto out; | 268 | goto out; |
287 | 269 | ||
@@ -333,10 +315,12 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
333 | } | 315 | } |
334 | } | 316 | } |
335 | rcu_read_unlock(); | 317 | rcu_read_unlock(); |
318 | |||
336 | if (baddr) { | 319 | if (baddr) { |
337 | fl6->saddr = baddr->v6.sin6_addr; | 320 | fl6->saddr = baddr->v6.sin6_addr; |
338 | fl6->fl6_sport = baddr->v6.sin6_port; | 321 | fl6->fl6_sport = baddr->v6.sin6_port; |
339 | dst = ip6_dst_lookup_flow(sk, fl6, NULL, false); | 322 | final_p = fl6_update_dst(fl6, np->opt, &final); |
323 | dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); | ||
340 | } | 324 | } |
341 | 325 | ||
342 | out: | 326 | out: |