~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/inet6_connection_sock.c

Version: ~ [ linux-5.3 ] ~ [ linux-5.2.14 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.72 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.143 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.192 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.192 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.73 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 #include <net/sock_reuseport.h>
 30 
 31 int inet6_csk_bind_conflict(const struct sock *sk,
 32                             const struct inet_bind_bucket *tb, bool relax,
 33                             bool reuseport_ok)
 34 {
 35         const struct sock *sk2;
 36         bool reuse = !!sk->sk_reuse;
 37         bool reuseport = !!sk->sk_reuseport && reuseport_ok;
 38         kuid_t uid = sock_i_uid((struct sock *)sk);
 39 
 40         /* We must walk the whole port owner list in this case. -DaveM */
 41         /*
 42          * See comment in inet_csk_bind_conflict about sock lookup
 43          * vs net namespaces issues.
 44          */
 45         sk_for_each_bound(sk2, &tb->owners) {
 46                 if (sk != sk2 &&
 47                     (!sk->sk_bound_dev_if ||
 48                      !sk2->sk_bound_dev_if ||
 49                      sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
 50                         if ((!reuse || !sk2->sk_reuse ||
 51                              sk2->sk_state == TCP_LISTEN) &&
 52                             (!reuseport || !sk2->sk_reuseport ||
 53                              rcu_access_pointer(sk->sk_reuseport_cb) ||
 54                              (sk2->sk_state != TCP_TIME_WAIT &&
 55                               !uid_eq(uid,
 56                                       sock_i_uid((struct sock *)sk2))))) {
 57                                 if (ipv6_rcv_saddr_equal(sk, sk2, true))
 58                                         break;
 59                         }
 60                         if (!relax && reuse && sk2->sk_reuse &&
 61                             sk2->sk_state != TCP_LISTEN &&
 62                             ipv6_rcv_saddr_equal(sk, sk2, true))
 63                                 break;
 64                 }
 65         }
 66 
 67         return sk2 != NULL;
 68 }
 69 EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict);
 70 
 71 struct dst_entry *inet6_csk_route_req(const struct sock *sk,
 72                                       struct flowi6 *fl6,
 73                                       const struct request_sock *req,
 74                                       u8 proto)
 75 {
 76         struct inet_request_sock *ireq = inet_rsk(req);
 77         const struct ipv6_pinfo *np = inet6_sk(sk);
 78         struct in6_addr *final_p, final;
 79         struct dst_entry *dst;
 80 
 81         memset(fl6, 0, sizeof(*fl6));
 82         fl6->flowi6_proto = proto;
 83         fl6->daddr = ireq->ir_v6_rmt_addr;
 84         rcu_read_lock();
 85         final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
 86         rcu_read_unlock();
 87         fl6->saddr = ireq->ir_v6_loc_addr;
 88         fl6->flowi6_oif = ireq->ir_iif;
 89         fl6->flowi6_mark = ireq->ir_mark;
 90         fl6->fl6_dport = ireq->ir_rmt_port;
 91         fl6->fl6_sport = htons(ireq->ir_num);
 92         fl6->flowi6_uid = sk->sk_uid;
 93         security_req_classify_flow(req, flowi6_to_flowi(fl6));
 94 
 95         dst = ip6_dst_lookup_flow(sk, fl6, final_p);
 96         if (IS_ERR(dst))
 97                 return NULL;
 98 
 99         return dst;
100 }
101 EXPORT_SYMBOL(inet6_csk_route_req);
102 
103 void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr)
104 {
105         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;
106 
107         sin6->sin6_family = AF_INET6;
108         sin6->sin6_addr = sk->sk_v6_daddr;
109         sin6->sin6_port = inet_sk(sk)->inet_dport;
110         /* We do not store received flowlabel for TCP */
111         sin6->sin6_flowinfo = 0;
112         sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
113                                                   sk->sk_bound_dev_if);
114 }
115 EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
116 
117 static inline
118 struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
119 {
120         return __sk_dst_check(sk, cookie);
121 }
122 
123 static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
124                                                 struct flowi6 *fl6)
125 {
126         struct inet_sock *inet = inet_sk(sk);
127         struct ipv6_pinfo *np = inet6_sk(sk);
128         struct in6_addr *final_p, final;
129         struct dst_entry *dst;
130 
131         memset(fl6, 0, sizeof(*fl6));
132         fl6->flowi6_proto = sk->sk_protocol;
133         fl6->daddr = sk->sk_v6_daddr;
134         fl6->saddr = np->saddr;
135         fl6->flowlabel = np->flow_label;
136         IP6_ECN_flow_xmit(sk, fl6->flowlabel);
137         fl6->flowi6_oif = sk->sk_bound_dev_if;
138         fl6->flowi6_mark = sk->sk_mark;
139         fl6->fl6_sport = inet->inet_sport;
140         fl6->fl6_dport = inet->inet_dport;
141         fl6->flowi6_uid = sk->sk_uid;
142         security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
143 
144         rcu_read_lock();
145         final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
146         rcu_read_unlock();
147 
148         dst = __inet6_csk_dst_check(sk, np->dst_cookie);
149         if (!dst) {
150                 dst = ip6_dst_lookup_flow(sk, fl6, final_p);
151 
152                 if (!IS_ERR(dst))
153                         ip6_dst_store(sk, dst, NULL, NULL);
154         }
155         return dst;
156 }
157 
158 int inet6_csk_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl_unused)
159 {
160         struct ipv6_pinfo *np = inet6_sk(sk);
161         struct flowi6 fl6;
162         struct dst_entry *dst;
163         int res;
164 
165         dst = inet6_csk_route_socket(sk, &fl6);
166         if (IS_ERR(dst)) {
167                 sk->sk_err_soft = -PTR_ERR(dst);
168                 sk->sk_route_caps = 0;
169                 kfree_skb(skb);
170                 return PTR_ERR(dst);
171         }
172 
173         rcu_read_lock();
174         skb_dst_set_noref(skb, dst);
175 
176         /* Restore final destination back after routing done */
177         fl6.daddr = sk->sk_v6_daddr;
178 
179         res = ip6_xmit(sk, skb, &fl6, sk->sk_mark, rcu_dereference(np->opt),
180                        np->tclass);
181         rcu_read_unlock();
182         return res;
183 }
184 EXPORT_SYMBOL_GPL(inet6_csk_xmit);
185 
186 struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu)
187 {
188         struct flowi6 fl6;
189         struct dst_entry *dst = inet6_csk_route_socket(sk, &fl6);
190 
191         if (IS_ERR(dst))
192                 return NULL;
193         dst->ops->update_pmtu(dst, sk, NULL, mtu);
194 
195         dst = inet6_csk_route_socket(sk, &fl6);
196         return IS_ERR(dst) ? NULL : dst;
197 }
198 EXPORT_SYMBOL_GPL(inet6_csk_update_pmtu);
199 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp