162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * INET		An implementation of the TCP/IP protocol suite for the LINUX
462306a36Sopenharmony_ci *		operating system.  INET  is implemented using the  BSD Socket
562306a36Sopenharmony_ci *		interface as the means of communication with the user level.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *		Definitions for the IP router.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Version:	@(#)route.h	1.0.4	05/27/93
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Authors:	Ross Biro
1262306a36Sopenharmony_ci *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
1362306a36Sopenharmony_ci * Fixes:
1462306a36Sopenharmony_ci *		Alan Cox	:	Reformatted. Added ip_rt_local()
1562306a36Sopenharmony_ci *		Alan Cox	:	Support for TCP parameters.
1662306a36Sopenharmony_ci *		Alexey Kuznetsov:	Major changes for new routing code.
1762306a36Sopenharmony_ci *		Mike McLagan    :	Routing by source
1862306a36Sopenharmony_ci *		Robert Olsson   :	Added rt_cache statistics
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci#ifndef _ROUTE_H
2162306a36Sopenharmony_ci#define _ROUTE_H
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <net/dst.h>
2462306a36Sopenharmony_ci#include <net/inetpeer.h>
2562306a36Sopenharmony_ci#include <net/flow.h>
2662306a36Sopenharmony_ci#include <net/inet_sock.h>
2762306a36Sopenharmony_ci#include <net/ip_fib.h>
2862306a36Sopenharmony_ci#include <net/arp.h>
2962306a36Sopenharmony_ci#include <net/ndisc.h>
3062306a36Sopenharmony_ci#include <linux/in_route.h>
3162306a36Sopenharmony_ci#include <linux/rtnetlink.h>
3262306a36Sopenharmony_ci#include <linux/rcupdate.h>
3362306a36Sopenharmony_ci#include <linux/route.h>
3462306a36Sopenharmony_ci#include <linux/ip.h>
3562306a36Sopenharmony_ci#include <linux/cache.h>
3662306a36Sopenharmony_ci#include <linux/security.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define RTO_ONLINK	0x01
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define RT_CONN_FLAGS(sk)   (RT_TOS(inet_sk(sk)->tos) | sock_flag(sk, SOCK_LOCALROUTE))
4162306a36Sopenharmony_ci#define RT_CONN_FLAGS_TOS(sk,tos)   (RT_TOS(tos) | sock_flag(sk, SOCK_LOCALROUTE))
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic inline __u8 ip_sock_rt_scope(const struct sock *sk)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	if (sock_flag(sk, SOCK_LOCALROUTE))
4662306a36Sopenharmony_ci		return RT_SCOPE_LINK;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	return RT_SCOPE_UNIVERSE;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic inline __u8 ip_sock_rt_tos(const struct sock *sk)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	return RT_TOS(inet_sk(sk)->tos);
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistruct ip_tunnel_info;
5762306a36Sopenharmony_cistruct fib_nh;
5862306a36Sopenharmony_cistruct fib_info;
5962306a36Sopenharmony_cistruct uncached_list;
6062306a36Sopenharmony_cistruct rtable {
6162306a36Sopenharmony_ci	struct dst_entry	dst;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	int			rt_genid;
6462306a36Sopenharmony_ci	unsigned int		rt_flags;
6562306a36Sopenharmony_ci	__u16			rt_type;
6662306a36Sopenharmony_ci	__u8			rt_is_input;
6762306a36Sopenharmony_ci	__u8			rt_uses_gateway;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	int			rt_iif;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	u8			rt_gw_family;
7262306a36Sopenharmony_ci	/* Info on neighbour */
7362306a36Sopenharmony_ci	union {
7462306a36Sopenharmony_ci		__be32		rt_gw4;
7562306a36Sopenharmony_ci		struct in6_addr	rt_gw6;
7662306a36Sopenharmony_ci	};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/* Miscellaneous cached information */
7962306a36Sopenharmony_ci	u32			rt_mtu_locked:1,
8062306a36Sopenharmony_ci				rt_pmtu:31;
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic inline bool rt_is_input_route(const struct rtable *rt)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	return rt->rt_is_input != 0;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic inline bool rt_is_output_route(const struct rtable *rt)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	return rt->rt_is_input == 0;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic inline __be32 rt_nexthop(const struct rtable *rt, __be32 daddr)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	if (rt->rt_gw_family == AF_INET)
9662306a36Sopenharmony_ci		return rt->rt_gw4;
9762306a36Sopenharmony_ci	return daddr;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistruct ip_rt_acct {
10162306a36Sopenharmony_ci	__u32 	o_bytes;
10262306a36Sopenharmony_ci	__u32 	o_packets;
10362306a36Sopenharmony_ci	__u32 	i_bytes;
10462306a36Sopenharmony_ci	__u32 	i_packets;
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistruct rt_cache_stat {
10862306a36Sopenharmony_ci        unsigned int in_slow_tot;
10962306a36Sopenharmony_ci        unsigned int in_slow_mc;
11062306a36Sopenharmony_ci        unsigned int in_no_route;
11162306a36Sopenharmony_ci        unsigned int in_brd;
11262306a36Sopenharmony_ci        unsigned int in_martian_dst;
11362306a36Sopenharmony_ci        unsigned int in_martian_src;
11462306a36Sopenharmony_ci        unsigned int out_slow_tot;
11562306a36Sopenharmony_ci        unsigned int out_slow_mc;
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ciextern struct ip_rt_acct __percpu *ip_rt_acct;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistruct in_device;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ciint ip_rt_init(void);
12362306a36Sopenharmony_civoid rt_cache_flush(struct net *net);
12462306a36Sopenharmony_civoid rt_flush_dev(struct net_device *dev);
12562306a36Sopenharmony_cistruct rtable *ip_route_output_key_hash(struct net *net, struct flowi4 *flp,
12662306a36Sopenharmony_ci					const struct sk_buff *skb);
12762306a36Sopenharmony_cistruct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *flp,
12862306a36Sopenharmony_ci					    struct fib_result *res,
12962306a36Sopenharmony_ci					    const struct sk_buff *skb);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic inline struct rtable *__ip_route_output_key(struct net *net,
13262306a36Sopenharmony_ci						   struct flowi4 *flp)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	return ip_route_output_key_hash(net, flp, NULL);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistruct rtable *ip_route_output_flow(struct net *, struct flowi4 *flp,
13862306a36Sopenharmony_ci				    const struct sock *sk);
13962306a36Sopenharmony_cistruct rtable *ip_route_output_tunnel(struct sk_buff *skb,
14062306a36Sopenharmony_ci				      struct net_device *dev,
14162306a36Sopenharmony_ci				      struct net *net, __be32 *saddr,
14262306a36Sopenharmony_ci				      const struct ip_tunnel_info *info,
14362306a36Sopenharmony_ci				      u8 protocol, bool use_cache);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistruct dst_entry *ipv4_blackhole_route(struct net *net,
14662306a36Sopenharmony_ci				       struct dst_entry *dst_orig);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic inline struct rtable *ip_route_output_key(struct net *net, struct flowi4 *flp)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	return ip_route_output_flow(net, flp, NULL);
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic inline struct rtable *ip_route_output(struct net *net, __be32 daddr,
15462306a36Sopenharmony_ci					     __be32 saddr, u8 tos, int oif)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct flowi4 fl4 = {
15762306a36Sopenharmony_ci		.flowi4_oif = oif,
15862306a36Sopenharmony_ci		.flowi4_tos = tos,
15962306a36Sopenharmony_ci		.daddr = daddr,
16062306a36Sopenharmony_ci		.saddr = saddr,
16162306a36Sopenharmony_ci	};
16262306a36Sopenharmony_ci	return ip_route_output_key(net, &fl4);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic inline struct rtable *ip_route_output_ports(struct net *net, struct flowi4 *fl4,
16662306a36Sopenharmony_ci						   const struct sock *sk,
16762306a36Sopenharmony_ci						   __be32 daddr, __be32 saddr,
16862306a36Sopenharmony_ci						   __be16 dport, __be16 sport,
16962306a36Sopenharmony_ci						   __u8 proto, __u8 tos, int oif)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	flowi4_init_output(fl4, oif, sk ? READ_ONCE(sk->sk_mark) : 0, tos,
17262306a36Sopenharmony_ci			   RT_SCOPE_UNIVERSE, proto,
17362306a36Sopenharmony_ci			   sk ? inet_sk_flowi_flags(sk) : 0,
17462306a36Sopenharmony_ci			   daddr, saddr, dport, sport, sock_net_uid(net, sk));
17562306a36Sopenharmony_ci	if (sk)
17662306a36Sopenharmony_ci		security_sk_classify_flow(sk, flowi4_to_flowi_common(fl4));
17762306a36Sopenharmony_ci	return ip_route_output_flow(net, fl4, sk);
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic inline struct rtable *ip_route_output_gre(struct net *net, struct flowi4 *fl4,
18162306a36Sopenharmony_ci						 __be32 daddr, __be32 saddr,
18262306a36Sopenharmony_ci						 __be32 gre_key, __u8 tos, int oif)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	memset(fl4, 0, sizeof(*fl4));
18562306a36Sopenharmony_ci	fl4->flowi4_oif = oif;
18662306a36Sopenharmony_ci	fl4->daddr = daddr;
18762306a36Sopenharmony_ci	fl4->saddr = saddr;
18862306a36Sopenharmony_ci	fl4->flowi4_tos = tos;
18962306a36Sopenharmony_ci	fl4->flowi4_proto = IPPROTO_GRE;
19062306a36Sopenharmony_ci	fl4->fl4_gre_key = gre_key;
19162306a36Sopenharmony_ci	return ip_route_output_key(net, fl4);
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ciint ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr,
19462306a36Sopenharmony_ci			  u8 tos, struct net_device *dev,
19562306a36Sopenharmony_ci			  struct in_device *in_dev, u32 *itag);
19662306a36Sopenharmony_ciint ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 src,
19762306a36Sopenharmony_ci			 u8 tos, struct net_device *devin);
19862306a36Sopenharmony_ciint ip_route_use_hint(struct sk_buff *skb, __be32 dst, __be32 src,
19962306a36Sopenharmony_ci		      u8 tos, struct net_device *devin,
20062306a36Sopenharmony_ci		      const struct sk_buff *hint);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src,
20362306a36Sopenharmony_ci				 u8 tos, struct net_device *devin)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	int err;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	rcu_read_lock();
20862306a36Sopenharmony_ci	err = ip_route_input_noref(skb, dst, src, tos, devin);
20962306a36Sopenharmony_ci	if (!err) {
21062306a36Sopenharmony_ci		skb_dst_force(skb);
21162306a36Sopenharmony_ci		if (!skb_dst(skb))
21262306a36Sopenharmony_ci			err = -EINVAL;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci	rcu_read_unlock();
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	return err;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_civoid ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, int oif,
22062306a36Sopenharmony_ci		      u8 protocol);
22162306a36Sopenharmony_civoid ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu);
22262306a36Sopenharmony_civoid ipv4_redirect(struct sk_buff *skb, struct net *net, int oif, u8 protocol);
22362306a36Sopenharmony_civoid ipv4_sk_redirect(struct sk_buff *skb, struct sock *sk);
22462306a36Sopenharmony_civoid ip_rt_send_redirect(struct sk_buff *skb);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ciunsigned int inet_addr_type(struct net *net, __be32 addr);
22762306a36Sopenharmony_ciunsigned int inet_addr_type_table(struct net *net, __be32 addr, u32 tb_id);
22862306a36Sopenharmony_ciunsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
22962306a36Sopenharmony_ci				__be32 addr);
23062306a36Sopenharmony_ciunsigned int inet_addr_type_dev_table(struct net *net,
23162306a36Sopenharmony_ci				      const struct net_device *dev,
23262306a36Sopenharmony_ci				      __be32 addr);
23362306a36Sopenharmony_civoid ip_rt_multicast_event(struct in_device *);
23462306a36Sopenharmony_ciint ip_rt_ioctl(struct net *, unsigned int cmd, struct rtentry *rt);
23562306a36Sopenharmony_civoid ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
23662306a36Sopenharmony_cistruct rtable *rt_dst_alloc(struct net_device *dev,
23762306a36Sopenharmony_ci			    unsigned int flags, u16 type, bool noxfrm);
23862306a36Sopenharmony_cistruct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistruct in_ifaddr;
24162306a36Sopenharmony_civoid fib_add_ifaddr(struct in_ifaddr *);
24262306a36Sopenharmony_civoid fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *);
24362306a36Sopenharmony_civoid fib_modify_prefix_metric(struct in_ifaddr *ifa, u32 new_metric);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_civoid rt_add_uncached_list(struct rtable *rt);
24662306a36Sopenharmony_civoid rt_del_uncached_list(struct rtable *rt);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ciint fib_dump_info_fnhe(struct sk_buff *skb, struct netlink_callback *cb,
24962306a36Sopenharmony_ci		       u32 table_id, struct fib_info *fi,
25062306a36Sopenharmony_ci		       int *fa_index, int fa_start, unsigned int flags);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic inline void ip_rt_put(struct rtable *rt)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	/* dst_release() accepts a NULL parameter.
25562306a36Sopenharmony_ci	 * We rely on dst being first structure in struct rtable
25662306a36Sopenharmony_ci	 */
25762306a36Sopenharmony_ci	BUILD_BUG_ON(offsetof(struct rtable, dst) != 0);
25862306a36Sopenharmony_ci	dst_release(&rt->dst);
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci#define IPTOS_RT_MASK	(IPTOS_TOS_MASK & ~3)
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ciextern const __u8 ip_tos2prio[16];
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic inline char rt_tos2priority(u8 tos)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	return ip_tos2prio[IPTOS_TOS(tos)>>1];
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/* ip_route_connect() and ip_route_newports() work in tandem whilst
27162306a36Sopenharmony_ci * binding a socket for a new outgoing connection.
27262306a36Sopenharmony_ci *
27362306a36Sopenharmony_ci * In order to use IPSEC properly, we must, in the end, have a
27462306a36Sopenharmony_ci * route that was looked up using all available keys including source
27562306a36Sopenharmony_ci * and destination ports.
27662306a36Sopenharmony_ci *
27762306a36Sopenharmony_ci * However, if a source port needs to be allocated (the user specified
27862306a36Sopenharmony_ci * a wildcard source port) we need to obtain addressing information
27962306a36Sopenharmony_ci * in order to perform that allocation.
28062306a36Sopenharmony_ci *
28162306a36Sopenharmony_ci * So ip_route_connect() looks up a route using wildcarded source and
28262306a36Sopenharmony_ci * destination ports in the key, simply so that we can get a pair of
28362306a36Sopenharmony_ci * addresses to use for port allocation.
28462306a36Sopenharmony_ci *
28562306a36Sopenharmony_ci * Later, once the ports are allocated, ip_route_newports() will make
28662306a36Sopenharmony_ci * another route lookup if needed to make sure we catch any IPSEC
28762306a36Sopenharmony_ci * rules keyed on the port information.
28862306a36Sopenharmony_ci *
28962306a36Sopenharmony_ci * The callers allocate the flow key on their stack, and must pass in
29062306a36Sopenharmony_ci * the same flowi4 object to both the ip_route_connect() and the
29162306a36Sopenharmony_ci * ip_route_newports() calls.
29262306a36Sopenharmony_ci */
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst,
29562306a36Sopenharmony_ci					 __be32 src, int oif, u8 protocol,
29662306a36Sopenharmony_ci					 __be16 sport, __be16 dport,
29762306a36Sopenharmony_ci					 const struct sock *sk)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	__u8 flow_flags = 0;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (inet_test_bit(TRANSPARENT, sk))
30262306a36Sopenharmony_ci		flow_flags |= FLOWI_FLAG_ANYSRC;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	flowi4_init_output(fl4, oif, READ_ONCE(sk->sk_mark), ip_sock_rt_tos(sk),
30562306a36Sopenharmony_ci			   ip_sock_rt_scope(sk), protocol, flow_flags, dst,
30662306a36Sopenharmony_ci			   src, dport, sport, sk->sk_uid);
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic inline struct rtable *ip_route_connect(struct flowi4 *fl4, __be32 dst,
31062306a36Sopenharmony_ci					      __be32 src, int oif, u8 protocol,
31162306a36Sopenharmony_ci					      __be16 sport, __be16 dport,
31262306a36Sopenharmony_ci					      const struct sock *sk)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	struct net *net = sock_net(sk);
31562306a36Sopenharmony_ci	struct rtable *rt;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	ip_route_connect_init(fl4, dst, src, oif, protocol, sport, dport, sk);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (!dst || !src) {
32062306a36Sopenharmony_ci		rt = __ip_route_output_key(net, fl4);
32162306a36Sopenharmony_ci		if (IS_ERR(rt))
32262306a36Sopenharmony_ci			return rt;
32362306a36Sopenharmony_ci		ip_rt_put(rt);
32462306a36Sopenharmony_ci		flowi4_update_output(fl4, oif, fl4->daddr, fl4->saddr);
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci	security_sk_classify_flow(sk, flowi4_to_flowi_common(fl4));
32762306a36Sopenharmony_ci	return ip_route_output_flow(net, fl4, sk);
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic inline struct rtable *ip_route_newports(struct flowi4 *fl4, struct rtable *rt,
33162306a36Sopenharmony_ci					       __be16 orig_sport, __be16 orig_dport,
33262306a36Sopenharmony_ci					       __be16 sport, __be16 dport,
33362306a36Sopenharmony_ci					       const struct sock *sk)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	if (sport != orig_sport || dport != orig_dport) {
33662306a36Sopenharmony_ci		fl4->fl4_dport = dport;
33762306a36Sopenharmony_ci		fl4->fl4_sport = sport;
33862306a36Sopenharmony_ci		ip_rt_put(rt);
33962306a36Sopenharmony_ci		flowi4_update_output(fl4, sk->sk_bound_dev_if, fl4->daddr,
34062306a36Sopenharmony_ci				     fl4->saddr);
34162306a36Sopenharmony_ci		security_sk_classify_flow(sk, flowi4_to_flowi_common(fl4));
34262306a36Sopenharmony_ci		return ip_route_output_flow(sock_net(sk), fl4, sk);
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	return rt;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic inline int inet_iif(const struct sk_buff *skb)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct rtable *rt = skb_rtable(skb);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (rt && rt->rt_iif)
35262306a36Sopenharmony_ci		return rt->rt_iif;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	return skb->skb_iif;
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic inline int ip4_dst_hoplimit(const struct dst_entry *dst)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
36062306a36Sopenharmony_ci	struct net *net = dev_net(dst->dev);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (hoplimit == 0)
36362306a36Sopenharmony_ci		hoplimit = READ_ONCE(net->ipv4.sysctl_ip_default_ttl);
36462306a36Sopenharmony_ci	return hoplimit;
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic inline struct neighbour *ip_neigh_gw4(struct net_device *dev,
36862306a36Sopenharmony_ci					     __be32 daddr)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct neighbour *neigh;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	neigh = __ipv4_neigh_lookup_noref(dev, (__force u32)daddr);
37362306a36Sopenharmony_ci	if (unlikely(!neigh))
37462306a36Sopenharmony_ci		neigh = __neigh_create(&arp_tbl, &daddr, dev, false);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	return neigh;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic inline struct neighbour *ip_neigh_for_gw(struct rtable *rt,
38062306a36Sopenharmony_ci						struct sk_buff *skb,
38162306a36Sopenharmony_ci						bool *is_v6gw)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct net_device *dev = rt->dst.dev;
38462306a36Sopenharmony_ci	struct neighbour *neigh;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (likely(rt->rt_gw_family == AF_INET)) {
38762306a36Sopenharmony_ci		neigh = ip_neigh_gw4(dev, rt->rt_gw4);
38862306a36Sopenharmony_ci	} else if (rt->rt_gw_family == AF_INET6) {
38962306a36Sopenharmony_ci		neigh = ip_neigh_gw6(dev, &rt->rt_gw6);
39062306a36Sopenharmony_ci		*is_v6gw = true;
39162306a36Sopenharmony_ci	} else {
39262306a36Sopenharmony_ci		neigh = ip_neigh_gw4(dev, ip_hdr(skb)->daddr);
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci	return neigh;
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci#endif	/* _ROUTE_H */
398