diff options
Diffstat (limited to 'net/ipv4/inet_connection_sock.c')
-rw-r--r-- | net/ipv4/inet_connection_sock.c | 70 |
1 files changed, 48 insertions, 22 deletions
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 7174370b1195..c14d88ad348d 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
@@ -33,7 +33,7 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg); | |||
33 | * This struct holds the first and last local port number. | 33 | * This struct holds the first and last local port number. |
34 | */ | 34 | */ |
35 | struct local_ports sysctl_local_ports __read_mostly = { | 35 | struct local_ports sysctl_local_ports __read_mostly = { |
36 | .lock = SEQLOCK_UNLOCKED, | 36 | .lock = __SEQLOCK_UNLOCKED(sysctl_local_ports.lock), |
37 | .range = { 32768, 61000 }, | 37 | .range = { 32768, 61000 }, |
38 | }; | 38 | }; |
39 | 39 | ||
@@ -55,7 +55,6 @@ EXPORT_SYMBOL(inet_get_local_port_range); | |||
55 | int inet_csk_bind_conflict(const struct sock *sk, | 55 | int inet_csk_bind_conflict(const struct sock *sk, |
56 | const struct inet_bind_bucket *tb) | 56 | const struct inet_bind_bucket *tb) |
57 | { | 57 | { |
58 | const __be32 sk_rcv_saddr = inet_rcv_saddr(sk); | ||
59 | struct sock *sk2; | 58 | struct sock *sk2; |
60 | struct hlist_node *node; | 59 | struct hlist_node *node; |
61 | int reuse = sk->sk_reuse; | 60 | int reuse = sk->sk_reuse; |
@@ -75,9 +74,9 @@ int inet_csk_bind_conflict(const struct sock *sk, | |||
75 | sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { | 74 | sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { |
76 | if (!reuse || !sk2->sk_reuse || | 75 | if (!reuse || !sk2->sk_reuse || |
77 | sk2->sk_state == TCP_LISTEN) { | 76 | sk2->sk_state == TCP_LISTEN) { |
78 | const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); | 77 | const __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2); |
79 | if (!sk2_rcv_saddr || !sk_rcv_saddr || | 78 | if (!sk2_rcv_saddr || !sk_rcv_saddr(sk) || |
80 | sk2_rcv_saddr == sk_rcv_saddr) | 79 | sk2_rcv_saddr == sk_rcv_saddr(sk)) |
81 | break; | 80 | break; |
82 | } | 81 | } |
83 | } | 82 | } |
@@ -351,30 +350,24 @@ void inet_csk_reset_keepalive_timer(struct sock *sk, unsigned long len) | |||
351 | EXPORT_SYMBOL(inet_csk_reset_keepalive_timer); | 350 | EXPORT_SYMBOL(inet_csk_reset_keepalive_timer); |
352 | 351 | ||
353 | struct dst_entry *inet_csk_route_req(struct sock *sk, | 352 | struct dst_entry *inet_csk_route_req(struct sock *sk, |
353 | struct flowi4 *fl4, | ||
354 | const struct request_sock *req) | 354 | const struct request_sock *req) |
355 | { | 355 | { |
356 | struct rtable *rt; | 356 | struct rtable *rt; |
357 | const struct inet_request_sock *ireq = inet_rsk(req); | 357 | const struct inet_request_sock *ireq = inet_rsk(req); |
358 | struct ip_options *opt = inet_rsk(req)->opt; | 358 | struct ip_options_rcu *opt = inet_rsk(req)->opt; |
359 | struct flowi fl = { .oif = sk->sk_bound_dev_if, | ||
360 | .mark = sk->sk_mark, | ||
361 | .nl_u = { .ip4_u = | ||
362 | { .daddr = ((opt && opt->srr) ? | ||
363 | opt->faddr : | ||
364 | ireq->rmt_addr), | ||
365 | .saddr = ireq->loc_addr, | ||
366 | .tos = RT_CONN_FLAGS(sk) } }, | ||
367 | .proto = sk->sk_protocol, | ||
368 | .flags = inet_sk_flowi_flags(sk), | ||
369 | .uli_u = { .ports = | ||
370 | { .sport = inet_sk(sk)->inet_sport, | ||
371 | .dport = ireq->rmt_port } } }; | ||
372 | struct net *net = sock_net(sk); | 359 | struct net *net = sock_net(sk); |
373 | 360 | ||
374 | security_req_classify_flow(req, &fl); | 361 | flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark, |
375 | if (ip_route_output_flow(net, &rt, &fl, sk, 0)) | 362 | RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, |
363 | sk->sk_protocol, inet_sk_flowi_flags(sk), | ||
364 | (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr, | ||
365 | ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport); | ||
366 | security_req_classify_flow(req, flowi4_to_flowi(fl4)); | ||
367 | rt = ip_route_output_flow(net, fl4, sk); | ||
368 | if (IS_ERR(rt)) | ||
376 | goto no_route; | 369 | goto no_route; |
377 | if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) | 370 | if (opt && opt->opt.is_strictroute && fl4->daddr != rt->rt_gateway) |
378 | goto route_err; | 371 | goto route_err; |
379 | return &rt->dst; | 372 | return &rt->dst; |
380 | 373 | ||
@@ -386,6 +379,39 @@ no_route: | |||
386 | } | 379 | } |
387 | EXPORT_SYMBOL_GPL(inet_csk_route_req); | 380 | EXPORT_SYMBOL_GPL(inet_csk_route_req); |
388 | 381 | ||
382 | struct dst_entry *inet_csk_route_child_sock(struct sock *sk, | ||
383 | struct sock *newsk, | ||
384 | const struct request_sock *req) | ||
385 | { | ||
386 | const struct inet_request_sock *ireq = inet_rsk(req); | ||
387 | struct inet_sock *newinet = inet_sk(newsk); | ||
388 | struct ip_options_rcu *opt = ireq->opt; | ||
389 | struct net *net = sock_net(sk); | ||
390 | struct flowi4 *fl4; | ||
391 | struct rtable *rt; | ||
392 | |||
393 | fl4 = &newinet->cork.fl.u.ip4; | ||
394 | flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark, | ||
395 | RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, | ||
396 | sk->sk_protocol, inet_sk_flowi_flags(sk), | ||
397 | (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr, | ||
398 | ireq->loc_addr, ireq->rmt_port, inet_sk(sk)->inet_sport); | ||
399 | security_req_classify_flow(req, flowi4_to_flowi(fl4)); | ||
400 | rt = ip_route_output_flow(net, fl4, sk); | ||
401 | if (IS_ERR(rt)) | ||
402 | goto no_route; | ||
403 | if (opt && opt->opt.is_strictroute && fl4->daddr != rt->rt_gateway) | ||
404 | goto route_err; | ||
405 | return &rt->dst; | ||
406 | |||
407 | route_err: | ||
408 | ip_rt_put(rt); | ||
409 | no_route: | ||
410 | IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); | ||
411 | return NULL; | ||
412 | } | ||
413 | EXPORT_SYMBOL_GPL(inet_csk_route_child_sock); | ||
414 | |||
389 | static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport, | 415 | static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport, |
390 | const u32 rnd, const u32 synq_hsize) | 416 | const u32 rnd, const u32 synq_hsize) |
391 | { | 417 | { |