.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * INET An implementation of the TCP/IP protocol suite for the LINUX |
---|
3 | 4 | * operating system. INET is implemented using the BSD Socket |
---|
.. | .. |
---|
6 | 7 | * Support for INET connection oriented protocols. |
---|
7 | 8 | * |
---|
8 | 9 | * Authors: See the TCP sources |
---|
9 | | - * |
---|
10 | | - * This program is free software; you can redistribute it and/or |
---|
11 | | - * modify it under the terms of the GNU General Public License |
---|
12 | | - * as published by the Free Software Foundation; either version |
---|
13 | | - * 2 of the License, or(at your option) any later version. |
---|
14 | 10 | */ |
---|
15 | 11 | |
---|
16 | 12 | #include <linux/module.h> |
---|
.. | .. |
---|
140 | 136 | { |
---|
141 | 137 | struct sock *sk2; |
---|
142 | 138 | bool reuse = sk->sk_reuse; |
---|
143 | | - bool reuseport = !!sk->sk_reuseport && reuseport_ok; |
---|
| 139 | + bool reuseport = !!sk->sk_reuseport; |
---|
144 | 140 | kuid_t uid = sock_i_uid((struct sock *)sk); |
---|
145 | 141 | |
---|
146 | 142 | /* |
---|
.. | .. |
---|
151 | 147 | */ |
---|
152 | 148 | |
---|
153 | 149 | sk_for_each_bound(sk2, &tb->owners) { |
---|
154 | | - if (sk != sk2 && |
---|
155 | | - (!sk->sk_bound_dev_if || |
---|
156 | | - !sk2->sk_bound_dev_if || |
---|
157 | | - sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { |
---|
158 | | - if ((!reuse || !sk2->sk_reuse || |
---|
159 | | - sk2->sk_state == TCP_LISTEN) && |
---|
160 | | - (!reuseport || !sk2->sk_reuseport || |
---|
161 | | - rcu_access_pointer(sk->sk_reuseport_cb) || |
---|
162 | | - (sk2->sk_state != TCP_TIME_WAIT && |
---|
163 | | - !uid_eq(uid, sock_i_uid(sk2))))) { |
---|
164 | | - if (inet_rcv_saddr_equal(sk, sk2, true)) |
---|
165 | | - break; |
---|
166 | | - } |
---|
167 | | - if (!relax && reuse && sk2->sk_reuse && |
---|
| 150 | + int bound_dev_if2; |
---|
| 151 | + |
---|
| 152 | + if (sk == sk2) |
---|
| 153 | + continue; |
---|
| 154 | + bound_dev_if2 = READ_ONCE(sk2->sk_bound_dev_if); |
---|
| 155 | + if ((!sk->sk_bound_dev_if || |
---|
| 156 | + !bound_dev_if2 || |
---|
| 157 | + sk->sk_bound_dev_if == bound_dev_if2)) { |
---|
| 158 | + if (reuse && sk2->sk_reuse && |
---|
168 | 159 | sk2->sk_state != TCP_LISTEN) { |
---|
| 160 | + if ((!relax || |
---|
| 161 | + (!reuseport_ok && |
---|
| 162 | + reuseport && sk2->sk_reuseport && |
---|
| 163 | + !rcu_access_pointer(sk->sk_reuseport_cb) && |
---|
| 164 | + (sk2->sk_state == TCP_TIME_WAIT || |
---|
| 165 | + uid_eq(uid, sock_i_uid(sk2))))) && |
---|
| 166 | + inet_rcv_saddr_equal(sk, sk2, true)) |
---|
| 167 | + break; |
---|
| 168 | + } else if (!reuseport_ok || |
---|
| 169 | + !reuseport || !sk2->sk_reuseport || |
---|
| 170 | + rcu_access_pointer(sk->sk_reuseport_cb) || |
---|
| 171 | + (sk2->sk_state != TCP_TIME_WAIT && |
---|
| 172 | + !uid_eq(uid, sock_i_uid(sk2)))) { |
---|
169 | 173 | if (inet_rcv_saddr_equal(sk, sk2, true)) |
---|
170 | 174 | break; |
---|
171 | 175 | } |
---|
.. | .. |
---|
185 | 189 | int port = 0; |
---|
186 | 190 | struct inet_bind_hashbucket *head; |
---|
187 | 191 | struct net *net = sock_net(sk); |
---|
| 192 | + bool relax = false; |
---|
188 | 193 | int i, low, high, attempt_half; |
---|
189 | 194 | struct inet_bind_bucket *tb; |
---|
190 | 195 | u32 remaining, offset; |
---|
| 196 | + int l3mdev; |
---|
191 | 197 | |
---|
| 198 | + l3mdev = inet_sk_bound_l3mdev(sk); |
---|
| 199 | +ports_exhausted: |
---|
192 | 200 | attempt_half = (sk->sk_reuse == SK_CAN_REUSE) ? 1 : 0; |
---|
193 | 201 | other_half_scan: |
---|
194 | 202 | inet_get_local_port_range(net, &low, &high); |
---|
.. | .. |
---|
224 | 232 | hinfo->bhash_size)]; |
---|
225 | 233 | spin_lock_bh(&head->lock); |
---|
226 | 234 | inet_bind_bucket_for_each(tb, &head->chain) |
---|
227 | | - if (net_eq(ib_net(tb), net) && tb->port == port) { |
---|
228 | | - if (!inet_csk_bind_conflict(sk, tb, false, false)) |
---|
| 235 | + if (net_eq(ib_net(tb), net) && tb->l3mdev == l3mdev && |
---|
| 236 | + tb->port == port) { |
---|
| 237 | + if (!inet_csk_bind_conflict(sk, tb, relax, false)) |
---|
229 | 238 | goto success; |
---|
230 | 239 | goto next_port; |
---|
231 | 240 | } |
---|
.. | .. |
---|
244 | 253 | /* OK we now try the upper half of the range */ |
---|
245 | 254 | attempt_half = 2; |
---|
246 | 255 | goto other_half_scan; |
---|
| 256 | + } |
---|
| 257 | + |
---|
| 258 | + if (READ_ONCE(net->ipv4.sysctl_ip_autobind_reuse) && !relax) { |
---|
| 259 | + /* We still have a chance to connect to different destinations */ |
---|
| 260 | + relax = true; |
---|
| 261 | + goto ports_exhausted; |
---|
247 | 262 | } |
---|
248 | 263 | return NULL; |
---|
249 | 264 | success: |
---|
.. | .. |
---|
348 | 363 | struct inet_bind_hashbucket *head; |
---|
349 | 364 | struct net *net = sock_net(sk); |
---|
350 | 365 | struct inet_bind_bucket *tb = NULL; |
---|
| 366 | + int l3mdev; |
---|
| 367 | + |
---|
| 368 | + l3mdev = inet_sk_bound_l3mdev(sk); |
---|
351 | 369 | |
---|
352 | 370 | if (!port) { |
---|
353 | 371 | head = inet_csk_find_open_port(sk, &tb, &port); |
---|
.. | .. |
---|
361 | 379 | hinfo->bhash_size)]; |
---|
362 | 380 | spin_lock_bh(&head->lock); |
---|
363 | 381 | inet_bind_bucket_for_each(tb, &head->chain) |
---|
364 | | - if (net_eq(ib_net(tb), net) && tb->port == port) |
---|
| 382 | + if (net_eq(ib_net(tb), net) && tb->l3mdev == l3mdev && |
---|
| 383 | + tb->port == port) |
---|
365 | 384 | goto tb_found; |
---|
366 | 385 | tb_not_found: |
---|
367 | 386 | tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, |
---|
368 | | - net, head, port); |
---|
| 387 | + net, head, port, l3mdev); |
---|
369 | 388 | if (!tb) |
---|
370 | 389 | goto fail_unlock; |
---|
371 | 390 | tb_found: |
---|
.. | .. |
---|
549 | 568 | { |
---|
550 | 569 | struct inet_connection_sock *icsk = inet_csk(sk); |
---|
551 | 570 | |
---|
552 | | - icsk->icsk_pending = icsk->icsk_ack.pending = icsk->icsk_ack.blocked = 0; |
---|
| 571 | + icsk->icsk_pending = icsk->icsk_ack.pending = 0; |
---|
553 | 572 | |
---|
554 | 573 | sk_stop_timer(sk, &icsk->icsk_retransmit_timer); |
---|
555 | 574 | sk_stop_timer(sk, &icsk->icsk_delack_timer); |
---|
.. | .. |
---|
587 | 606 | (opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr, |
---|
588 | 607 | ireq->ir_loc_addr, ireq->ir_rmt_port, |
---|
589 | 608 | htons(ireq->ir_num), sk->sk_uid); |
---|
590 | | - security_req_classify_flow(req, flowi4_to_flowi(fl4)); |
---|
| 609 | + security_req_classify_flow(req, flowi4_to_flowi_common(fl4)); |
---|
591 | 610 | rt = ip_route_output_flow(net, fl4, sk); |
---|
592 | 611 | if (IS_ERR(rt)) |
---|
593 | 612 | goto no_route; |
---|
.. | .. |
---|
625 | 644 | (opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr, |
---|
626 | 645 | ireq->ir_loc_addr, ireq->ir_rmt_port, |
---|
627 | 646 | htons(ireq->ir_num), sk->sk_uid); |
---|
628 | | - security_req_classify_flow(req, flowi4_to_flowi(fl4)); |
---|
| 647 | + security_req_classify_flow(req, flowi4_to_flowi_common(fl4)); |
---|
629 | 648 | rt = ip_route_output_flow(net, fl4, sk); |
---|
630 | 649 | if (IS_ERR(rt)) |
---|
631 | 650 | goto no_route; |
---|
.. | .. |
---|
641 | 660 | } |
---|
642 | 661 | EXPORT_SYMBOL_GPL(inet_csk_route_child_sock); |
---|
643 | 662 | |
---|
644 | | -#if IS_ENABLED(CONFIG_IPV6) |
---|
645 | | -#define AF_INET_FAMILY(fam) ((fam) == AF_INET) |
---|
646 | | -#else |
---|
647 | | -#define AF_INET_FAMILY(fam) true |
---|
648 | | -#endif |
---|
649 | | - |
---|
650 | 663 | /* Decide when to expire the request and when to resend SYN-ACK */ |
---|
651 | | -static inline void syn_ack_recalc(struct request_sock *req, const int thresh, |
---|
652 | | - const int max_retries, |
---|
653 | | - const u8 rskq_defer_accept, |
---|
654 | | - int *expire, int *resend) |
---|
| 664 | +static void syn_ack_recalc(struct request_sock *req, |
---|
| 665 | + const int max_syn_ack_retries, |
---|
| 666 | + const u8 rskq_defer_accept, |
---|
| 667 | + int *expire, int *resend) |
---|
655 | 668 | { |
---|
656 | 669 | if (!rskq_defer_accept) { |
---|
657 | | - *expire = req->num_timeout >= thresh; |
---|
| 670 | + *expire = req->num_timeout >= max_syn_ack_retries; |
---|
658 | 671 | *resend = 1; |
---|
659 | 672 | return; |
---|
660 | 673 | } |
---|
661 | | - *expire = req->num_timeout >= thresh && |
---|
662 | | - (!inet_rsk(req)->acked || req->num_timeout >= max_retries); |
---|
663 | | - /* |
---|
664 | | - * Do not resend while waiting for data after ACK, |
---|
| 674 | + *expire = req->num_timeout >= max_syn_ack_retries && |
---|
| 675 | + (!inet_rsk(req)->acked || req->num_timeout >= rskq_defer_accept); |
---|
| 676 | + /* Do not resend while waiting for data after ACK, |
---|
665 | 677 | * start to resend on end of deferring period to give |
---|
666 | 678 | * last chance for data or ACK to create established socket. |
---|
667 | 679 | */ |
---|
.. | .. |
---|
680 | 692 | EXPORT_SYMBOL(inet_rtx_syn_ack); |
---|
681 | 693 | |
---|
682 | 694 | /* return true if req was found in the ehash table */ |
---|
683 | | -static bool reqsk_queue_unlink(struct request_sock_queue *queue, |
---|
684 | | - struct request_sock *req) |
---|
| 695 | +static bool reqsk_queue_unlink(struct request_sock *req) |
---|
685 | 696 | { |
---|
686 | 697 | struct inet_hashinfo *hashinfo = req_to_sk(req)->sk_prot->h.hashinfo; |
---|
687 | 698 | bool found = false; |
---|
.. | .. |
---|
700 | 711 | |
---|
701 | 712 | bool inet_csk_reqsk_queue_drop(struct sock *sk, struct request_sock *req) |
---|
702 | 713 | { |
---|
703 | | - bool unlinked = reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req); |
---|
| 714 | + bool unlinked = reqsk_queue_unlink(req); |
---|
704 | 715 | |
---|
705 | 716 | if (unlinked) { |
---|
706 | 717 | reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req); |
---|
.. | .. |
---|
724 | 735 | struct net *net = sock_net(sk_listener); |
---|
725 | 736 | struct inet_connection_sock *icsk = inet_csk(sk_listener); |
---|
726 | 737 | struct request_sock_queue *queue = &icsk->icsk_accept_queue; |
---|
727 | | - int qlen, expire = 0, resend = 0; |
---|
728 | | - int max_retries, thresh; |
---|
729 | | - u8 defer_accept; |
---|
| 738 | + int max_syn_ack_retries, qlen, expire = 0, resend = 0; |
---|
730 | 739 | |
---|
731 | 740 | if (inet_sk_state_load(sk_listener) != TCP_LISTEN) |
---|
732 | 741 | goto drop; |
---|
733 | 742 | |
---|
734 | | - max_retries = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_synack_retries; |
---|
735 | | - thresh = max_retries; |
---|
| 743 | + max_syn_ack_retries = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_synack_retries; |
---|
736 | 744 | /* Normally all the openreqs are young and become mature |
---|
737 | 745 | * (i.e. converted to established socket) for first timeout. |
---|
738 | 746 | * If synack was not acknowledged for 1 second, it means |
---|
.. | .. |
---|
751 | 759 | * ones are about to clog our table. |
---|
752 | 760 | */ |
---|
753 | 761 | qlen = reqsk_queue_len(queue); |
---|
754 | | - if ((qlen << 1) > max(8U, sk_listener->sk_max_ack_backlog)) { |
---|
| 762 | + if ((qlen << 1) > max(8U, READ_ONCE(sk_listener->sk_max_ack_backlog))) { |
---|
755 | 763 | int young = reqsk_queue_len_young(queue) << 1; |
---|
756 | 764 | |
---|
757 | | - while (thresh > 2) { |
---|
| 765 | + while (max_syn_ack_retries > 2) { |
---|
758 | 766 | if (qlen < young) |
---|
759 | 767 | break; |
---|
760 | | - thresh--; |
---|
| 768 | + max_syn_ack_retries--; |
---|
761 | 769 | young <<= 1; |
---|
762 | 770 | } |
---|
763 | 771 | } |
---|
764 | | - defer_accept = READ_ONCE(queue->rskq_defer_accept); |
---|
765 | | - if (defer_accept) |
---|
766 | | - max_retries = defer_accept; |
---|
767 | | - syn_ack_recalc(req, thresh, max_retries, defer_accept, |
---|
| 772 | + syn_ack_recalc(req, max_syn_ack_retries, READ_ONCE(queue->rskq_defer_accept), |
---|
768 | 773 | &expire, &resend); |
---|
769 | 774 | req->rsk_ops->syn_ack_timeout(req); |
---|
770 | 775 | if (!expire && |
---|
.. | .. |
---|
786 | 791 | static void reqsk_queue_hash_req(struct request_sock *req, |
---|
787 | 792 | unsigned long timeout) |
---|
788 | 793 | { |
---|
789 | | - req->num_retrans = 0; |
---|
790 | | - req->num_timeout = 0; |
---|
791 | | - req->sk = NULL; |
---|
792 | | - |
---|
793 | 794 | timer_setup(&req->rsk_timer, reqsk_timer_handler, TIMER_PINNED); |
---|
794 | 795 | mod_timer(&req->rsk_timer, jiffies + timeout); |
---|
795 | 796 | |
---|
796 | | - inet_ehash_insert(req_to_sk(req), NULL); |
---|
| 797 | + inet_ehash_insert(req_to_sk(req), NULL, NULL); |
---|
797 | 798 | /* before letting lookups find us, make sure all req fields |
---|
798 | 799 | * are committed to memory and refcnt initialized. |
---|
799 | 800 | */ |
---|
.. | .. |
---|
808 | 809 | inet_csk_reqsk_queue_added(sk); |
---|
809 | 810 | } |
---|
810 | 811 | EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_hash_add); |
---|
| 812 | + |
---|
| 813 | +static void inet_clone_ulp(const struct request_sock *req, struct sock *newsk, |
---|
| 814 | + const gfp_t priority) |
---|
| 815 | +{ |
---|
| 816 | + struct inet_connection_sock *icsk = inet_csk(newsk); |
---|
| 817 | + |
---|
| 818 | + if (!icsk->icsk_ulp_ops) |
---|
| 819 | + return; |
---|
| 820 | + |
---|
| 821 | + if (icsk->icsk_ulp_ops->clone) |
---|
| 822 | + icsk->icsk_ulp_ops->clone(req, newsk, priority); |
---|
| 823 | +} |
---|
811 | 824 | |
---|
812 | 825 | /** |
---|
813 | 826 | * inet_csk_clone_lock - clone an inet socket, and lock its clone |
---|
.. | .. |
---|
845 | 858 | newicsk->icsk_retransmits = 0; |
---|
846 | 859 | newicsk->icsk_backoff = 0; |
---|
847 | 860 | newicsk->icsk_probes_out = 0; |
---|
| 861 | + newicsk->icsk_probes_tstamp = 0; |
---|
848 | 862 | |
---|
849 | 863 | /* Deinitialize accept_queue to trap illegal accesses. */ |
---|
850 | 864 | memset(&newicsk->icsk_accept_queue, 0, sizeof(newicsk->icsk_accept_queue)); |
---|
| 865 | + |
---|
| 866 | + inet_clone_ulp(req, newsk, priority); |
---|
851 | 867 | |
---|
852 | 868 | security_inet_csk_clone(newsk, req); |
---|
853 | 869 | } |
---|
.. | .. |
---|
895 | 911 | /* sk_clone_lock locked the socket and set refcnt to 2 */ |
---|
896 | 912 | bh_unlock_sock(sk); |
---|
897 | 913 | sock_put(sk); |
---|
898 | | - |
---|
899 | | - /* The below has to be done to allow calling inet_csk_destroy_sock */ |
---|
900 | | - sock_set_flag(sk, SOCK_DEAD); |
---|
901 | | - percpu_counter_inc(sk->sk_prot->orphan_count); |
---|
| 914 | + inet_csk_prepare_for_destroy_sock(sk); |
---|
902 | 915 | inet_sk(sk)->inet_num = 0; |
---|
903 | 916 | } |
---|
904 | 917 | EXPORT_SYMBOL(inet_csk_prepare_forced_close); |
---|
| 918 | + |
---|
| 919 | +static int inet_ulp_can_listen(const struct sock *sk) |
---|
| 920 | +{ |
---|
| 921 | + const struct inet_connection_sock *icsk = inet_csk(sk); |
---|
| 922 | + |
---|
| 923 | + if (icsk->icsk_ulp_ops && !icsk->icsk_ulp_ops->clone) |
---|
| 924 | + return -EINVAL; |
---|
| 925 | + |
---|
| 926 | + return 0; |
---|
| 927 | +} |
---|
905 | 928 | |
---|
906 | 929 | int inet_csk_listen_start(struct sock *sk, int backlog) |
---|
907 | 930 | { |
---|
908 | 931 | struct inet_connection_sock *icsk = inet_csk(sk); |
---|
909 | 932 | struct inet_sock *inet = inet_sk(sk); |
---|
910 | | - int err = -EADDRINUSE; |
---|
| 933 | + int err; |
---|
| 934 | + |
---|
| 935 | + err = inet_ulp_can_listen(sk); |
---|
| 936 | + if (unlikely(err)) |
---|
| 937 | + return err; |
---|
911 | 938 | |
---|
912 | 939 | reqsk_queue_alloc(&icsk->icsk_accept_queue); |
---|
913 | 940 | |
---|
914 | | - sk->sk_max_ack_backlog = backlog; |
---|
915 | 941 | sk->sk_ack_backlog = 0; |
---|
916 | 942 | inet_csk_delack_init(sk); |
---|
917 | 943 | |
---|
.. | .. |
---|
920 | 946 | * It is OK, because this socket enters to hash table only |
---|
921 | 947 | * after validation is complete. |
---|
922 | 948 | */ |
---|
| 949 | + err = -EADDRINUSE; |
---|
923 | 950 | inet_sk_state_store(sk, TCP_LISTEN); |
---|
924 | 951 | if (!sk->sk_prot->get_port(sk, inet->inet_num)) { |
---|
925 | 952 | inet->inet_sport = htons(inet->inet_num); |
---|
.. | .. |
---|
946 | 973 | percpu_counter_inc(sk->sk_prot->orphan_count); |
---|
947 | 974 | |
---|
948 | 975 | if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(req)->tfo_listener) { |
---|
949 | | - BUG_ON(tcp_sk(child)->fastopen_rsk != req); |
---|
| 976 | + BUG_ON(rcu_access_pointer(tcp_sk(child)->fastopen_rsk) != req); |
---|
950 | 977 | BUG_ON(sk != req->rsk_listener); |
---|
951 | 978 | |
---|
952 | 979 | /* Paranoid, to prevent race condition if |
---|
.. | .. |
---|
955 | 982 | * Also to satisfy an assertion in |
---|
956 | 983 | * tcp_v4_destroy_sock(). |
---|
957 | 984 | */ |
---|
958 | | - tcp_sk(child)->fastopen_rsk = NULL; |
---|
| 985 | + RCU_INIT_POINTER(tcp_sk(child)->fastopen_rsk, NULL); |
---|
959 | 986 | } |
---|
960 | 987 | inet_csk_destroy_sock(child); |
---|
961 | 988 | } |
---|
.. | .. |
---|
1061 | 1088 | sin->sin_port = inet->inet_dport; |
---|
1062 | 1089 | } |
---|
1063 | 1090 | EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr); |
---|
1064 | | - |
---|
1065 | | -#ifdef CONFIG_COMPAT |
---|
1066 | | -int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname, |
---|
1067 | | - char __user *optval, int __user *optlen) |
---|
1068 | | -{ |
---|
1069 | | - const struct inet_connection_sock *icsk = inet_csk(sk); |
---|
1070 | | - |
---|
1071 | | - if (icsk->icsk_af_ops->compat_getsockopt) |
---|
1072 | | - return icsk->icsk_af_ops->compat_getsockopt(sk, level, optname, |
---|
1073 | | - optval, optlen); |
---|
1074 | | - return icsk->icsk_af_ops->getsockopt(sk, level, optname, |
---|
1075 | | - optval, optlen); |
---|
1076 | | -} |
---|
1077 | | -EXPORT_SYMBOL_GPL(inet_csk_compat_getsockopt); |
---|
1078 | | - |
---|
1079 | | -int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname, |
---|
1080 | | - char __user *optval, unsigned int optlen) |
---|
1081 | | -{ |
---|
1082 | | - const struct inet_connection_sock *icsk = inet_csk(sk); |
---|
1083 | | - |
---|
1084 | | - if (icsk->icsk_af_ops->compat_setsockopt) |
---|
1085 | | - return icsk->icsk_af_ops->compat_setsockopt(sk, level, optname, |
---|
1086 | | - optval, optlen); |
---|
1087 | | - return icsk->icsk_af_ops->setsockopt(sk, level, optname, |
---|
1088 | | - optval, optlen); |
---|
1089 | | -} |
---|
1090 | | -EXPORT_SYMBOL_GPL(inet_csk_compat_setsockopt); |
---|
1091 | | -#endif |
---|
1092 | 1091 | |
---|
1093 | 1092 | static struct dst_entry *inet_csk_rebuild_route(struct sock *sk, struct flowi *fl) |
---|
1094 | 1093 | { |
---|