Branch data Line data Source code
1 : : /*
2 : : * INET An implementation of the TCP/IP protocol suite for the LINUX
3 : : * operating system. INET is implemented using the BSD Socket
4 : : * interface as the means of communication with the user level.
5 : : *
6 : : * Support for INET6 connection oriented protocols.
7 : : *
8 : : * Authors: See the TCPv6 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 : : */
15 : :
16 : : #include <linux/module.h>
17 : : #include <linux/in6.h>
18 : : #include <linux/ipv6.h>
19 : : #include <linux/jhash.h>
20 : : #include <linux/slab.h>
21 : :
22 : : #include <net/addrconf.h>
23 : : #include <net/inet_connection_sock.h>
24 : : #include <net/inet_ecn.h>
25 : : #include <net/inet_hashtables.h>
26 : : #include <net/ip6_route.h>
27 : : #include <net/sock.h>
28 : : #include <net/inet6_connection_sock.h>
29 : :
30 : 0 : int inet6_csk_bind_conflict(const struct sock *sk,
31 : : const struct inet_bind_bucket *tb, bool relax)
32 : : {
33 : : const struct sock *sk2;
34 : 0 : int reuse = sk->sk_reuse;
35 : 0 : int reuseport = sk->sk_reuseport;
36 : 0 : kuid_t uid = sock_i_uid((struct sock *)sk);
37 : :
38 : : /* We must walk the whole port owner list in this case. -DaveM */
39 : : /*
40 : : * See comment in inet_csk_bind_conflict about sock lookup
41 : : * vs net namespaces issues.
42 : : */
43 [ # # ][ # # ]: 0 : sk_for_each_bound(sk2, &tb->owners) {
[ # # ]
44 [ # # ][ # # ]: 0 : if (sk != sk2 &&
45 [ # # ]: 0 : (!sk->sk_bound_dev_if ||
46 [ # # ]: 0 : !sk2->sk_bound_dev_if ||
47 : : sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
48 [ # # ][ # # ]: 0 : if ((!reuse || !sk2->sk_reuse ||
[ # # ]
49 [ # # ]: 0 : sk2->sk_state == TCP_LISTEN) &&
50 [ # # ][ # # ]: 0 : (!reuseport || !sk2->sk_reuseport ||
51 [ # # ]: 0 : (sk2->sk_state != TCP_TIME_WAIT &&
52 : 0 : !uid_eq(uid,
53 : : sock_i_uid((struct sock *)sk2))))) {
54 [ # # ]: 0 : if (ipv6_rcv_saddr_equal(sk, sk2))
55 : : break;
56 : : }
57 [ # # ][ # # ]: 0 : if (!relax && reuse && sk2->sk_reuse &&
[ # # ]
58 [ # # ]: 0 : sk2->sk_state != TCP_LISTEN &&
59 : 0 : ipv6_rcv_saddr_equal(sk, sk2))
60 : : break;
61 : : }
62 : : }
63 : :
64 : 0 : return sk2 != NULL;
65 : : }
66 : :
67 : : EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict);
68 : :
69 : 0 : struct dst_entry *inet6_csk_route_req(struct sock *sk,
70 : : struct flowi6 *fl6,
71 : : const struct request_sock *req)
72 : : {
73 : : struct inet_request_sock *ireq = inet_rsk(req);
74 : : struct ipv6_pinfo *np = inet6_sk(sk);
75 : : struct in6_addr *final_p, final;
76 : : struct dst_entry *dst;
77 : :
78 : 0 : memset(fl6, 0, sizeof(*fl6));
79 : 0 : fl6->flowi6_proto = IPPROTO_TCP;
80 : 0 : fl6->daddr = ireq->ir_v6_rmt_addr;
81 : 0 : final_p = fl6_update_dst(fl6, np->opt, &final);
82 : 0 : fl6->saddr = ireq->ir_v6_loc_addr;
83 : 0 : fl6->flowi6_oif = ireq->ir_iif;
84 : 0 : fl6->flowi6_mark = sk->sk_mark;
85 : 0 : fl6->fl6_dport = ireq->ir_rmt_port;
86 [ # # ]: 0 : fl6->fl6_sport = htons(ireq->ir_num);
87 : 0 : security_req_classify_flow(req, flowi6_to_flowi(fl6));
88 : :
89 : 0 : dst = ip6_dst_lookup_flow(sk, fl6, final_p);
90 [ # # ]: 0 : if (IS_ERR(dst))
91 : : return NULL;
92 : :
93 : 0 : return dst;
94 : : }
95 : :
96 : : /*
97 : : * request_sock (formerly open request) hash tables.
98 : : */
99 : 0 : static u32 inet6_synq_hash(const struct in6_addr *raddr, const __be16 rport,
100 : : const u32 rnd, const u32 synq_hsize)
101 : : {
102 : : u32 c;
103 : :
104 : 0 : c = jhash_3words((__force u32)raddr->s6_addr32[0],
105 : : (__force u32)raddr->s6_addr32[1],
106 : : (__force u32)raddr->s6_addr32[2],
107 : : rnd);
108 : :
109 : 0 : c = jhash_2words((__force u32)raddr->s6_addr32[3],
110 : : (__force u32)rport,
111 : : c);
112 : :
113 : 0 : return c & (synq_hsize - 1);
114 : : }
115 : :
116 : 0 : struct request_sock *inet6_csk_search_req(const struct sock *sk,
117 : : struct request_sock ***prevp,
118 : : const __be16 rport,
119 : : const struct in6_addr *raddr,
120 : : const struct in6_addr *laddr,
121 : : const int iif)
122 : : {
123 : : const struct inet_connection_sock *icsk = inet_csk(sk);
124 : 0 : struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
125 : : struct request_sock *req, **prev;
126 : :
127 [ # # ]: 0 : for (prev = &lopt->syn_table[inet6_synq_hash(raddr, rport,
128 : : lopt->hash_rnd,
129 : : lopt->nr_table_entries)];
130 : 0 : (req = *prev) != NULL;
131 : 0 : prev = &req->dl_next) {
132 : : const struct inet_request_sock *ireq = inet_rsk(req);
133 : :
134 [ # # ][ # # ]: 0 : if (ireq->ir_rmt_port == rport &&
135 [ # # ]: 0 : req->rsk_ops->family == AF_INET6 &&
136 [ # # ]: 0 : ipv6_addr_equal(&ireq->ir_v6_rmt_addr, raddr) &&
137 [ # # ]: 0 : ipv6_addr_equal(&ireq->ir_v6_loc_addr, laddr) &&
138 [ # # ]: 0 : (!ireq->ir_iif || ireq->ir_iif == iif)) {
139 [ # # ]: 0 : WARN_ON(req->sk != NULL);
140 : 0 : *prevp = prev;
141 : 0 : return req;
142 : : }
143 : : }
144 : :
145 : : return NULL;
146 : : }
147 : :
148 : : EXPORT_SYMBOL_GPL(inet6_csk_search_req);
149 : :
150 : 0 : void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
151 : : struct request_sock *req,
152 : : const unsigned long timeout)
153 : : {
154 : : struct inet_connection_sock *icsk = inet_csk(sk);
155 : 0 : struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
156 : 0 : const u32 h = inet6_synq_hash(&inet_rsk(req)->ir_v6_rmt_addr,
157 : : inet_rsk(req)->ir_rmt_port,
158 : : lopt->hash_rnd, lopt->nr_table_entries);
159 : :
160 : : reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout);
161 : : inet_csk_reqsk_queue_added(sk, timeout);
162 : 0 : }
163 : :
164 : : EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add);
165 : :
166 : 0 : void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
167 : : {
168 : : struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;
169 : :
170 : 0 : sin6->sin6_family = AF_INET6;
171 : 0 : sin6->sin6_addr = sk->sk_v6_daddr;
172 : 0 : sin6->sin6_port = inet_sk(sk)->inet_dport;
173 : : /* We do not store received flowlabel for TCP */
174 : 0 : sin6->sin6_flowinfo = 0;
175 : 0 : sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
176 : : sk->sk_bound_dev_if);
177 : 0 : }
178 : :
179 : : EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
180 : :
181 : : static inline
182 : : void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst,
183 : : const struct in6_addr *daddr,
184 : : const struct in6_addr *saddr)
185 : : {
186 : : __ip6_dst_store(sk, dst, daddr, saddr);
187 : : }
188 : :
189 : : static inline
190 : : struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
191 : : {
192 : 0 : return __sk_dst_check(sk, cookie);
193 : : }
194 : :
195 : 0 : static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
196 : : struct flowi6 *fl6)
197 : : {
198 : : struct inet_sock *inet = inet_sk(sk);
199 : : struct ipv6_pinfo *np = inet6_sk(sk);
200 : : struct in6_addr *final_p, final;
201 : : struct dst_entry *dst;
202 : :
203 : 0 : memset(fl6, 0, sizeof(*fl6));
204 : 0 : fl6->flowi6_proto = sk->sk_protocol;
205 : 0 : fl6->daddr = sk->sk_v6_daddr;
206 : 0 : fl6->saddr = np->saddr;
207 : 0 : fl6->flowlabel = np->flow_label;
208 [ # # ]: 0 : IP6_ECN_flow_xmit(sk, fl6->flowlabel);
209 : 0 : fl6->flowi6_oif = sk->sk_bound_dev_if;
210 : 0 : fl6->flowi6_mark = sk->sk_mark;
211 : 0 : fl6->fl6_sport = inet->inet_sport;
212 : 0 : fl6->fl6_dport = inet->inet_dport;
213 : 0 : security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
214 : :
215 : 0 : final_p = fl6_update_dst(fl6, np->opt, &final);
216 : :
217 : 0 : dst = __inet6_csk_dst_check(sk, np->dst_cookie);
218 [ # # ]: 0 : if (!dst) {
219 : 0 : dst = ip6_dst_lookup_flow(sk, fl6, final_p);
220 : :
221 [ # # ]: 0 : if (!IS_ERR(dst))
222 : : __inet6_csk_dst_store(sk, dst, NULL, NULL);
223 : : }
224 : 0 : return dst;
225 : : }
226 : :
227 : 0 : int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
228 : : {
229 : 0 : struct sock *sk = skb->sk;
230 : : struct ipv6_pinfo *np = inet6_sk(sk);
231 : : struct flowi6 fl6;
232 : : struct dst_entry *dst;
233 : : int res;
234 : :
235 : 0 : dst = inet6_csk_route_socket(sk, &fl6);
236 [ # # ]: 0 : if (IS_ERR(dst)) {
237 : 0 : sk->sk_err_soft = -PTR_ERR(dst);
238 : 0 : sk->sk_route_caps = 0;
239 : 0 : kfree_skb(skb);
240 : 0 : return PTR_ERR(dst);
241 : : }
242 : :
243 : : rcu_read_lock();
244 : : skb_dst_set_noref(skb, dst);
245 : :
246 : : /* Restore final destination back after routing done */
247 : 0 : fl6.daddr = sk->sk_v6_daddr;
248 : :
249 : 0 : res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
250 : : rcu_read_unlock();
251 : 0 : return res;
252 : : }
253 : : EXPORT_SYMBOL_GPL(inet6_csk_xmit);
254 : :
255 : 0 : struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu)
256 : : {
257 : : struct flowi6 fl6;
258 : 0 : struct dst_entry *dst = inet6_csk_route_socket(sk, &fl6);
259 : :
260 [ # # ]: 0 : if (IS_ERR(dst))
261 : : return NULL;
262 : 0 : dst->ops->update_pmtu(dst, sk, NULL, mtu);
263 : :
264 : 0 : dst = inet6_csk_route_socket(sk, &fl6);
265 [ # # ]: 0 : return IS_ERR(dst) ? NULL : dst;
266 : : }
267 : : EXPORT_SYMBOL_GPL(inet6_csk_update_pmtu);
|