Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  common UDP/RAW code
0004  *  Linux INET implementation
0005  *
0006  * Authors:
0007  *  Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
0008  */
0009 
0010 #include <linux/types.h>
0011 #include <linux/module.h>
0012 #include <linux/in.h>
0013 #include <net/ip.h>
0014 #include <net/sock.h>
0015 #include <net/route.h>
0016 #include <net/tcp_states.h>
0017 #include <net/sock_reuseport.h>
0018 
0019 int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
0020 {
0021     struct inet_sock *inet = inet_sk(sk);
0022     struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
0023     struct flowi4 *fl4;
0024     struct rtable *rt;
0025     __be32 saddr;
0026     int oif;
0027     int err;
0028 
0029 
0030     if (addr_len < sizeof(*usin))
0031         return -EINVAL;
0032 
0033     if (usin->sin_family != AF_INET)
0034         return -EAFNOSUPPORT;
0035 
0036     sk_dst_reset(sk);
0037 
0038     oif = sk->sk_bound_dev_if;
0039     saddr = inet->inet_saddr;
0040     if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
0041         if (!oif || netif_index_is_l3_master(sock_net(sk), oif))
0042             oif = inet->mc_index;
0043         if (!saddr)
0044             saddr = inet->mc_addr;
0045     }
0046     fl4 = &inet->cork.fl.u.ip4;
0047     rt = ip_route_connect(fl4, usin->sin_addr.s_addr, saddr, oif,
0048                   sk->sk_protocol, inet->inet_sport,
0049                   usin->sin_port, sk);
0050     if (IS_ERR(rt)) {
0051         err = PTR_ERR(rt);
0052         if (err == -ENETUNREACH)
0053             IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
0054         goto out;
0055     }
0056 
0057     if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) {
0058         ip_rt_put(rt);
0059         err = -EACCES;
0060         goto out;
0061     }
0062     if (!inet->inet_saddr)
0063         inet->inet_saddr = fl4->saddr;  /* Update source address */
0064     if (!inet->inet_rcv_saddr) {
0065         inet->inet_rcv_saddr = fl4->saddr;
0066         if (sk->sk_prot->rehash)
0067             sk->sk_prot->rehash(sk);
0068     }
0069     inet->inet_daddr = fl4->daddr;
0070     inet->inet_dport = usin->sin_port;
0071     reuseport_has_conns(sk, true);
0072     sk->sk_state = TCP_ESTABLISHED;
0073     sk_set_txhash(sk);
0074     inet->inet_id = prandom_u32();
0075 
0076     sk_dst_set(sk, &rt->dst);
0077     err = 0;
0078 out:
0079     return err;
0080 }
0081 EXPORT_SYMBOL(__ip4_datagram_connect);
0082 
0083 int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
0084 {
0085     int res;
0086 
0087     lock_sock(sk);
0088     res = __ip4_datagram_connect(sk, uaddr, addr_len);
0089     release_sock(sk);
0090     return res;
0091 }
0092 EXPORT_SYMBOL(ip4_datagram_connect);
0093 
0094 /* Because UDP xmit path can manipulate sk_dst_cache without holding
0095  * socket lock, we need to use sk_dst_set() here,
0096  * even if we own the socket lock.
0097  */
0098 void ip4_datagram_release_cb(struct sock *sk)
0099 {
0100     const struct inet_sock *inet = inet_sk(sk);
0101     const struct ip_options_rcu *inet_opt;
0102     __be32 daddr = inet->inet_daddr;
0103     struct dst_entry *dst;
0104     struct flowi4 fl4;
0105     struct rtable *rt;
0106 
0107     rcu_read_lock();
0108 
0109     dst = __sk_dst_get(sk);
0110     if (!dst || !dst->obsolete || dst->ops->check(dst, 0)) {
0111         rcu_read_unlock();
0112         return;
0113     }
0114     inet_opt = rcu_dereference(inet->inet_opt);
0115     if (inet_opt && inet_opt->opt.srr)
0116         daddr = inet_opt->opt.faddr;
0117     rt = ip_route_output_ports(sock_net(sk), &fl4, sk, daddr,
0118                    inet->inet_saddr, inet->inet_dport,
0119                    inet->inet_sport, sk->sk_protocol,
0120                    RT_CONN_FLAGS(sk), sk->sk_bound_dev_if);
0121 
0122     dst = !IS_ERR(rt) ? &rt->dst : NULL;
0123     sk_dst_set(sk, dst);
0124 
0125     rcu_read_unlock();
0126 }
0127 EXPORT_SYMBOL_GPL(ip4_datagram_release_cb);