Instead of on the stack.
Signed-off-by: David S. Miller <davem@davemloft.net>
fl.nl_u.ip4_u.saddr = src_ip;
fl.oif = addr->bound_dev_if;
- ret = ip_route_output_key(&init_net, &rt, &fl);
- if (ret)
+ rt = ip_route_output_key(&init_net, &fl);
+ if (IS_ERR(rt)) {
+ ret = PTR_ERR(rt);
goto out;
-
+ }
src_in->sin_family = AF_INET;
src_in->sin_addr.s_addr = rt->rt_src;
}
};
- if (ip_route_output_flow(&init_net, &rt, &fl, NULL))
+ rt = ip_route_output_flow(&init_net, &fl, NULL);
+ if (IS_ERR(rt))
return NULL;
return rt;
}
}
};
- if (ip_route_output_flow(&init_net, &rt, &fl, NULL))
+ rt = ip_route_output_flow(&init_net, &fl, NULL);
+ if (IS_ERR(rt))
return NULL;
return rt;
}
memset(&fl, 0, sizeof fl);
fl.nl_u.ip4_u.daddr = htonl(dst_ip);
- if (ip_route_output_key(&init_net, &rt, &fl)) {
+ rt = ip_route_output_key(&init_net, &fl);
+ if (IS_ERR(rt)) {
printk(KERN_ERR "%s: ip_route_output_key failed for 0x%08X\n",
__func__, dst_ip);
return rc;
static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
{
- int i, vlan_id, rv;
+ int i, vlan_id;
__be32 *targets = bond->params.arp_targets;
struct vlan_entry *vlan;
struct net_device *vlan_dev;
fl.fl4_dst = targets[i];
fl.fl4_tos = RTO_ONLINK;
- rv = ip_route_output_key(dev_net(bond->dev), &rt, &fl);
- if (rv) {
+ rt = ip_route_output_key(dev_net(bond->dev), &fl);
+ if (IS_ERR(rt)) {
if (net_ratelimit()) {
pr_warning("%s: no route to arp_ip_target %pI4\n",
bond->dev->name, &fl.fl4_dst);
memset(&fl, 0, sizeof(fl));
fl.nl_u.ip4_u.daddr = dst_addr->sin_addr.s_addr;
- err = ip_route_output_key(&init_net, &rt, &fl);
- if (!err)
+ rt = ip_route_output_key(&init_net, &fl);
+ err = 0;
+ if (!IS_ERR(rt))
*dst = &rt->dst;
+ else
+ err = PTR_ERR(rt);
return err;
#else
return -ENETUNREACH;
struct pptp_opt *opt = &po->proto.pptp;
struct pptp_gre_header *hdr;
unsigned int header_len = sizeof(*hdr);
- int err = 0;
int islcp;
int len;
unsigned char *data;
.saddr = opt->src_addr.sin_addr.s_addr,
.tos = RT_TOS(0) } },
.proto = IPPROTO_GRE };
- err = ip_route_output_key(&init_net, &rt, &fl);
- if (err)
+ rt = ip_route_output_key(&init_net, &fl);
+ if (IS_ERR(rt))
goto tx_error;
}
tdev = rt->dst.dev;
.tos = RT_CONN_FLAGS(sk) } },
.proto = IPPROTO_GRE };
security_sk_classify_flow(sk, &fl);
- if (ip_route_output_key(&init_net, &rt, &fl)) {
+ rt = ip_route_output_key(&init_net, &fl);
+ if (IS_ERR(rt)) {
error = -EHOSTUNREACH;
goto end;
}
}
};
- if (ip_route_output_flow(&init_net, &rt, &fl, NULL))
+ rt = ip_route_output_flow(&init_net, &fl, NULL);
+ if (IS_ERR(rt))
return NULL;
return rt;
__be32 src, struct net_device *dev);
extern void rt_cache_flush(struct net *net, int how);
extern void rt_cache_flush_batch(struct net *net);
-extern int __ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp);
-extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
-extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk);
+extern struct rtable *__ip_route_output_key(struct net *, const struct flowi *flp);
+extern struct rtable *ip_route_output_key(struct net *, struct flowi *flp);
+extern struct rtable *ip_route_output_flow(struct net *, struct flowi *flp,
+ struct sock *sk);
extern struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig);
extern int ip_route_input_common(struct sk_buff *skb, __be32 dst, __be32 src,
return ip_tos2prio[IPTOS_TOS(tos)>>1];
}
-static inline int ip_route_connect(struct rtable **rp, __be32 dst,
- __be32 src, u32 tos, int oif, u8 protocol,
- __be16 sport, __be16 dport, struct sock *sk,
- bool can_sleep)
+static inline struct rtable *ip_route_connect(__be32 dst, __be32 src, u32 tos,
+ int oif, u8 protocol,
+ __be16 sport, __be16 dport,
+ struct sock *sk, bool can_sleep)
{
struct flowi fl = { .oif = oif,
.mark = sk->sk_mark,
.proto = protocol,
.fl_ip_sport = sport,
.fl_ip_dport = dport };
- int err;
struct net *net = sock_net(sk);
+ struct rtable *rt;
if (inet_sk(sk)->transparent)
fl.flags |= FLOWI_FLAG_ANYSRC;
fl.flags |= FLOWI_FLAG_CAN_SLEEP;
if (!dst || !src) {
- err = __ip_route_output_key(net, rp, &fl);
- if (err)
- return err;
- fl.fl4_dst = (*rp)->rt_dst;
- fl.fl4_src = (*rp)->rt_src;
- ip_rt_put(*rp);
- *rp = NULL;
+ rt = __ip_route_output_key(net, &fl);
+ if (IS_ERR(rt))
+ return rt;
+ fl.fl4_dst = rt->rt_dst;
+ fl.fl4_src = rt->rt_src;
+ ip_rt_put(rt);
}
security_sk_classify_flow(sk, &fl);
- return ip_route_output_flow(net, rp, &fl, sk);
+ return ip_route_output_flow(net, &fl, sk);
}
-static inline int ip_route_newports(struct rtable **rp, u8 protocol,
- __be16 orig_sport, __be16 orig_dport,
- __be16 sport, __be16 dport, struct sock *sk)
+static inline struct rtable *ip_route_newports(struct rtable *rt,
+ u8 protocol, __be16 orig_sport,
+ __be16 orig_dport, __be16 sport,
+ __be16 dport, struct sock *sk)
{
if (sport != orig_sport || dport != orig_dport) {
- struct flowi fl = { .oif = (*rp)->fl.oif,
- .mark = (*rp)->fl.mark,
- .fl4_dst = (*rp)->fl.fl4_dst,
- .fl4_src = (*rp)->fl.fl4_src,
- .fl4_tos = (*rp)->fl.fl4_tos,
- .proto = (*rp)->fl.proto,
+ struct flowi fl = { .oif = rt->fl.oif,
+ .mark = rt->fl.mark,
+ .fl4_dst = rt->fl.fl4_dst,
+ .fl4_src = rt->fl.fl4_src,
+ .fl4_tos = rt->fl.fl4_tos,
+ .proto = rt->fl.proto,
.fl_ip_sport = sport,
.fl_ip_dport = dport };
fl.flags |= FLOWI_FLAG_ANYSRC;
if (protocol == IPPROTO_TCP)
fl.flags |= FLOWI_FLAG_PRECOW_METRICS;
- ip_rt_put(*rp);
- *rp = NULL;
+ ip_rt_put(rt);
security_sk_classify_flow(sk, &fl);
- return ip_route_output_flow(sock_net(sk), rp, &fl, sk);
+ return ip_route_output_flow(sock_net(sk), &fl, sk);
}
- return 0;
+ return rt;
}
extern void rt_bind_peer(struct rtable *rt, int create);
unlink_clip_vcc(clip_vcc);
return 0;
}
- error = ip_route_output_key(&init_net, &rt, &fl);
- if (error)
- return error;
+ rt = ip_route_output_key(&init_net, &fl);
+ if (IS_ERR(rt))
+ return PTR_ERR(rt);
neigh = __neigh_lookup(&clip_tbl, &ip, rt->dst.dev, 1);
ip_rt_put(rt);
if (!neigh)
if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev))
goto free_skb;
- if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
+ rt = ip_route_output_key(dev_net(dev), &fl);
+ if (!IS_ERR(rt)) {
/* - Bridged-and-DNAT'ed traffic doesn't
* require ip_forwarding. */
- if (((struct dst_entry *)rt)->dev == dev) {
- skb_dst_set(skb, (struct dst_entry *)rt);
+ if (rt->dst.dev == dev) {
+ skb_dst_set(skb, &rt->dst);
goto bridged_dnat;
}
- dst_release((struct dst_entry *)rt);
+ ip_rt_put(rt);
}
free_skb:
kfree_skb(skb);
__be16 orig_sport, orig_dport;
struct rtable *rt;
__be32 daddr, nexthop;
- int tmp;
int err;
dp->dccps_role = DCCP_ROLE_CLIENT;
orig_sport = inet->inet_sport;
orig_dport = usin->sin_port;
- tmp = ip_route_connect(&rt, nexthop, inet->inet_saddr,
- RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
- IPPROTO_DCCP,
- orig_sport, orig_dport, sk, true);
- if (tmp < 0)
- return tmp;
+ rt = ip_route_connect(nexthop, inet->inet_saddr,
+ RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
+ IPPROTO_DCCP,
+ orig_sport, orig_dport, sk, true);
+ if (IS_ERR(rt))
+ return PTR_ERR(rt);
if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
ip_rt_put(rt);
if (err != 0)
goto failure;
- err = ip_route_newports(&rt, IPPROTO_DCCP,
- orig_sport, orig_dport,
- inet->inet_sport, inet->inet_dport, sk);
- if (err != 0)
+ rt = ip_route_newports(rt, IPPROTO_DCCP,
+ orig_sport, orig_dport,
+ inet->inet_sport, inet->inet_dport, sk);
+ if (IS_ERR(rt)) {
+ rt = NULL;
goto failure;
-
+ }
/* OK, now commit destination to socket. */
sk_setup_caps(sk, &rt->dst);
};
security_skb_classify_flow(skb, &fl);
- if (ip_route_output_flow(net, &rt, &fl, sk)) {
+ rt = ip_route_output_flow(net, &fl, sk);
+ if (IS_ERR(rt)) {
IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
return NULL;
}
static int inet_sk_reselect_saddr(struct sock *sk)
{
struct inet_sock *inet = inet_sk(sk);
- int err;
- struct rtable *rt;
__be32 old_saddr = inet->inet_saddr;
- __be32 new_saddr;
__be32 daddr = inet->inet_daddr;
+ struct rtable *rt;
+ __be32 new_saddr;
if (inet->opt && inet->opt->srr)
daddr = inet->opt->faddr;
/* Query new route. */
- err = ip_route_connect(&rt, daddr, 0,
- RT_CONN_FLAGS(sk),
- sk->sk_bound_dev_if,
- sk->sk_protocol,
- inet->inet_sport, inet->inet_dport, sk, false);
- if (err)
- return err;
+ rt = ip_route_connect(daddr, 0, RT_CONN_FLAGS(sk),
+ sk->sk_bound_dev_if, sk->sk_protocol,
+ inet->inet_sport, inet->inet_dport, sk, false);
+ if (IS_ERR(rt))
+ return PTR_ERR(rt);
sk_setup_caps(sk, &rt->dst);
daddr = inet->inet_daddr;
if (inet->opt && inet->opt->srr)
daddr = inet->opt->faddr;
-{
+ {
struct flowi fl = {
.oif = sk->sk_bound_dev_if,
.mark = sk->sk_mark,
};
security_sk_classify_flow(sk, &fl);
- err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk);
-}
- if (!err)
+ rt = ip_route_output_flow(sock_net(sk), &fl, sk);
+ }
+ if (!IS_ERR(rt)) {
+ err = 0;
sk_setup_caps(sk, &rt->dst);
- else {
+ } else {
+ err = PTR_ERR(rt);
+
/* Routing failed... */
sk->sk_route_caps = 0;
/*
/*unsigned long now; */
struct net *net = dev_net(dev);
- if (ip_route_output_key(net, &rt, &fl) < 0)
+ rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt))
return 1;
if (rt->dst.dev != dev) {
NET_INC_STATS_BH(net, LINUX_MIB_ARPFILTER);
if (dev == NULL) {
struct flowi fl = { .fl4_dst = ip,
.fl4_tos = RTO_ONLINK };
- struct rtable *rt;
- err = ip_route_output_key(net, &rt, &fl);
- if (err != 0)
- return err;
+ struct rtable *rt = ip_route_output_key(net, &fl);
+
+ if (IS_ERR(rt))
+ return PTR_ERR(rt);
dev = rt->dst.dev;
ip_rt_put(rt);
if (!dev)
static int arp_req_delete(struct net *net, struct arpreq *r,
struct net_device *dev)
{
- int err;
__be32 ip;
if (r->arp_flags & ATF_PUBL)
if (dev == NULL) {
struct flowi fl = { .fl4_dst = ip,
.fl4_tos = RTO_ONLINK };
- struct rtable *rt;
- err = ip_route_output_key(net, &rt, &fl);
- if (err != 0)
- return err;
+ struct rtable *rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt))
+ return PTR_ERR(rt);
dev = rt->dst.dev;
ip_rt_put(rt);
if (!dev)
if (!saddr)
saddr = inet->mc_addr;
}
- err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr,
- RT_CONN_FLAGS(sk), oif,
- sk->sk_protocol,
- inet->inet_sport, usin->sin_port, sk, true);
- if (err) {
+ rt = ip_route_connect(usin->sin_addr.s_addr, saddr,
+ RT_CONN_FLAGS(sk), oif,
+ sk->sk_protocol,
+ inet->inet_sport, usin->sin_port, sk, true);
+ if (IS_ERR(rt)) {
+ err = PTR_ERR(rt);
if (err == -ENETUNREACH)
IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
return err;
.fl4_tos = RT_TOS(ip_hdr(skb)->tos),
.proto = IPPROTO_ICMP };
security_skb_classify_flow(skb, &fl);
- if (ip_route_output_key(net, &rt, &fl))
+ rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt))
goto out_unlock;
}
if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type,
int err;
security_skb_classify_flow(skb_in, &fl);
- err = __ip_route_output_key(net, &rt, &fl);
- if (err)
- return ERR_PTR(err);
+ rt = __ip_route_output_key(net, &fl);
+ if (IS_ERR(rt))
+ return rt;
/* No need to clone since we're just using its address. */
rt2 = rt;
goto relookup_failed;
if (inet_addr_type(net, fl.fl4_src) == RTN_LOCAL) {
- err = __ip_route_output_key(net, &rt2, &fl);
+ rt2 = __ip_route_output_key(net, &fl);
+ if (IS_ERR(rt2))
+ err = PTR_ERR(rt2);
} else {
struct flowi fl2 = {};
unsigned long orefdst;
fl2.fl4_dst = fl.fl4_src;
- err = ip_route_output_key(net, &rt2, &fl2);
- if (err)
+ rt2 = ip_route_output_key(net, &fl2);
+ if (IS_ERR(rt2)) {
+ err = PTR_ERR(rt2);
goto relookup_failed;
+ }
/* Ugh! */
orefdst = skb_in->_skb_refdst; /* save old refdst */
err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src,
struct flowi fl = { .oif = dev->ifindex,
.fl4_dst = IGMPV3_ALL_MCR,
.proto = IPPROTO_IGMP };
- if (ip_route_output_key(net, &rt, &fl)) {
+ rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt)) {
kfree_skb(skb);
return NULL;
}
struct flowi fl = { .oif = dev->ifindex,
.fl4_dst = dst,
.proto = IPPROTO_IGMP };
- if (ip_route_output_key(net, &rt, &fl))
+ rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt))
return -1;
}
if (rt->rt_src == 0) {
static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
{
struct flowi fl = { .fl4_dst = imr->imr_multiaddr.s_addr };
- struct rtable *rt;
struct net_device *dev = NULL;
struct in_device *idev = NULL;
return NULL;
}
- if (!dev && !ip_route_output_key(net, &rt, &fl)) {
- dev = rt->dst.dev;
- ip_rt_put(rt);
+ if (!dev) {
+ struct rtable *rt = ip_route_output_key(net, &fl);
+ if (!IS_ERR(rt)) {
+ dev = rt->dst.dev;
+ ip_rt_put(rt);
+ }
}
if (dev) {
imr->imr_ifindex = dev->ifindex;
struct net *net = sock_net(sk);
security_req_classify_flow(req, &fl);
- if (ip_route_output_flow(net, &rt, &fl, sk))
+ rt = ip_route_output_flow(net, &fl, sk);
+ if (IS_ERR(rt))
goto no_route;
if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
goto route_err;
.proto = IPPROTO_GRE,
.fl_gre_key = tunnel->parms.o_key
};
- if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
+ rt = ip_route_output_key(dev_net(dev), &fl);
+ if (IS_ERR(rt)) {
dev->stats.tx_carrier_errors++;
goto tx_error;
}
.proto = IPPROTO_GRE,
.fl_gre_key = tunnel->parms.o_key
};
- struct rtable *rt;
+ struct rtable *rt = ip_route_output_key(dev_net(dev), &fl);
- if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
+ if (!IS_ERR(rt)) {
tdev = rt->dst.dev;
ip_rt_put(rt);
}
.proto = IPPROTO_GRE,
.fl_gre_key = t->parms.o_key
};
- struct rtable *rt;
+ struct rtable *rt = ip_route_output_key(dev_net(dev), &fl);
- if (ip_route_output_key(dev_net(dev), &rt, &fl))
+ if (IS_ERR(rt))
return -EADDRNOTAVAIL;
dev = rt->dst.dev;
ip_rt_put(rt);
* itself out.
*/
security_sk_classify_flow(sk, &fl);
- if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk))
+ rt = ip_route_output_flow(sock_net(sk), &fl, sk);
+ if (IS_ERR(rt))
goto no_route;
}
sk_setup_caps(sk, &rt->dst);
.proto = sk->sk_protocol,
.flags = ip_reply_arg_flowi_flags(arg) };
security_skb_classify_flow(skb, &fl);
- if (ip_route_output_key(sock_net(sk), &rt, &fl))
+ rt = ip_route_output_key(sock_net(sk), &fl);
+ if (IS_ERR(rt))
return;
}
.proto = IPPROTO_IPIP
};
- if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
+ rt = ip_route_output_key(dev_net(dev), &fl);
+ if (IS_ERR(rt)) {
dev->stats.tx_carrier_errors++;
goto tx_error_icmp;
}
.fl4_tos = RT_TOS(iph->tos),
.proto = IPPROTO_IPIP
};
- struct rtable *rt;
+ struct rtable *rt = ip_route_output_key(dev_net(dev), &fl);
- if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
+ if (!IS_ERR(rt)) {
tdev = rt->dst.dev;
ip_rt_put(rt);
}
.fl4_tos = RT_TOS(iph->tos),
.proto = IPPROTO_IPIP
};
-
- if (ip_route_output_key(net, &rt, &fl))
+ rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt))
goto out_free;
encap = sizeof(struct iphdr);
} else {
.fl4_tos = RT_TOS(iph->tos),
.proto = IPPROTO_IPIP
};
-
- if (ip_route_output_key(net, &rt, &fl))
+ rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt))
goto out_free;
}
fl.oif = skb->sk ? skb->sk->sk_bound_dev_if : 0;
fl.mark = skb->mark;
fl.flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : 0;
- if (ip_route_output_key(net, &rt, &fl) != 0)
+ rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt))
return -1;
/* Drop old route. */
/* non-local src, find valid iif to satisfy
* rp-filter when calling ip_route_input. */
fl.fl4_dst = iph->saddr;
- if (ip_route_output_key(net, &rt, &fl) != 0)
+ rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt))
return -1;
orefdst = skb->_skb_refdst;
static int nf_ip_route(struct dst_entry **dst, struct flowi *fl)
{
- return ip_route_output_key(&init_net, (struct rtable **)dst, fl);
+ struct rtable *rt = ip_route_output_key(&init_net, fl);
+ if (IS_ERR(rt))
+ return PTR_ERR(rt);
+ *dst = &rt->dst;
+ return 0;
}
static const struct nf_afinfo nf_ip_afinfo = {
}
security_sk_classify_flow(sk, &fl);
- err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk);
+ rt = ip_route_output_flow(sock_net(sk), &fl, sk);
+ if (IS_ERR(rt)) {
+ err = PTR_ERR(rt);
+ goto done;
+ }
}
- if (err)
- goto done;
err = -EACCES;
if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST))
return length >> FRACT_BITS;
}
-static int rt_intern_hash(unsigned hash, struct rtable *rt,
- struct rtable **rp, struct sk_buff *skb, int ifindex)
+static struct rtable *rt_intern_hash(unsigned hash, struct rtable *rt,
+ struct sk_buff *skb, int ifindex)
{
struct rtable *rth, *cand;
struct rtable __rcu **rthp, **candp;
printk(KERN_WARNING
"Neighbour table failure & not caching routes.\n");
ip_rt_put(rt);
- return err;
+ return ERR_PTR(err);
}
}
spin_unlock_bh(rt_hash_lock_addr(hash));
rt_drop(rt);
- if (rp)
- *rp = rth;
- else
+ if (skb)
skb_dst_set(skb, &rth->dst);
- return 0;
+ return rth;
}
if (!atomic_read(&rth->dst.__refcnt)) {
if (err != -ENOBUFS) {
rt_drop(rt);
- return err;
+ return ERR_PTR(err);
}
/* Neighbour tables are full and nothing
if (net_ratelimit())
printk(KERN_WARNING "ipv4: Neighbour table overflow.\n");
rt_drop(rt);
- return -ENOBUFS;
+ return ERR_PTR(-ENOBUFS);
}
}
spin_unlock_bh(rt_hash_lock_addr(hash));
skip_hashing:
- if (rp)
- *rp = rt;
- else
+ if (skb)
skb_dst_set(skb, &rt->dst);
- return 0;
+ return rt;
}
static atomic_t __rt_peer_genid = ATOMIC_INIT(0);
RT_CACHE_STAT_INC(in_slow_mc);
hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev)));
- return rt_intern_hash(hash, rth, NULL, skb, dev->ifindex);
+ rth = rt_intern_hash(hash, rth, skb, dev->ifindex);
+ err = 0;
+ if (IS_ERR(rth))
+ err = PTR_ERR(rth);
e_nobufs:
return -ENOBUFS;
/* put it into the cache */
hash = rt_hash(daddr, saddr, fl->iif,
rt_genid(dev_net(rth->dst.dev)));
- return rt_intern_hash(hash, rth, NULL, skb, fl->iif);
+ rth = rt_intern_hash(hash, rth, skb, fl->iif);
+ if (IS_ERR(rth))
+ return PTR_ERR(rth);
+ return 0;
}
/*
}
rth->rt_type = res.type;
hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net));
- err = rt_intern_hash(hash, rth, NULL, skb, fl.iif);
+ rth = rt_intern_hash(hash, rth, skb, fl.iif);
+ err = 0;
+ if (IS_ERR(rth))
+ err = PTR_ERR(rth);
goto out;
no_route:
* called with rcu_read_lock();
*/
-static int ip_route_output_slow(struct net *net, struct rtable **rp,
- const struct flowi *oldflp)
+static struct rtable *ip_route_output_slow(struct net *net,
+ const struct flowi *oldflp)
{
u32 tos = RT_FL_TOS(oldflp);
struct flowi fl = { .fl4_dst = oldflp->fl4_dst,
unsigned int flags = 0;
struct net_device *dev_out = NULL;
struct rtable *rth;
- int err;
-
res.fi = NULL;
#ifdef CONFIG_IP_MULTIPLE_TABLES
rcu_read_lock();
if (oldflp->fl4_src) {
- err = -EINVAL;
+ rth = ERR_PTR(-EINVAL);
if (ipv4_is_multicast(oldflp->fl4_src) ||
ipv4_is_lbcast(oldflp->fl4_src) ||
ipv4_is_zeronet(oldflp->fl4_src))
if (oldflp->oif) {
dev_out = dev_get_by_index_rcu(net, oldflp->oif);
- err = -ENODEV;
+ rth = ERR_PTR(-ENODEV);
if (dev_out == NULL)
goto out;
/* RACE: Check return value of inet_select_addr instead. */
if (!(dev_out->flags & IFF_UP) || !__in_dev_get_rcu(dev_out)) {
- err = -ENETUNREACH;
+ rth = ERR_PTR(-ENETUNREACH);
goto out;
}
if (ipv4_is_local_multicast(oldflp->fl4_dst) ||
res.type = RTN_UNICAST;
goto make_route;
}
- err = -ENETUNREACH;
+ rth = ERR_PTR(-ENETUNREACH);
goto out;
}
make_route:
rth = __mkroute_output(&res, &fl, oldflp, dev_out, flags);
- if (IS_ERR(rth))
- err = PTR_ERR(rth);
- else {
+ if (!IS_ERR(rth)) {
unsigned int hash;
hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif,
rt_genid(dev_net(dev_out)));
- err = rt_intern_hash(hash, rth, rp, NULL, oldflp->oif);
+ rth = rt_intern_hash(hash, rth, NULL, oldflp->oif);
}
out:
rcu_read_unlock();
- return err;
+ return rth;
}
-int __ip_route_output_key(struct net *net, struct rtable **rp,
- const struct flowi *flp)
+struct rtable *__ip_route_output_key(struct net *net, const struct flowi *flp)
{
struct rtable *rth;
unsigned int hash;
dst_use(&rth->dst, jiffies);
RT_CACHE_STAT_INC(out_hit);
rcu_read_unlock_bh();
- *rp = rth;
- return 0;
+ return rth;
}
RT_CACHE_STAT_INC(out_hlist_search);
}
rcu_read_unlock_bh();
slow_output:
- return ip_route_output_slow(net, rp, flp);
+ return ip_route_output_slow(net, flp);
}
EXPORT_SYMBOL_GPL(__ip_route_output_key);
return rt ? &rt->dst : ERR_PTR(-ENOMEM);
}
-int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
- struct sock *sk)
+struct rtable *ip_route_output_flow(struct net *net, struct flowi *flp,
+ struct sock *sk)
{
- int err;
+ struct rtable *rt = __ip_route_output_key(net, flp);
- if ((err = __ip_route_output_key(net, rp, flp)) != 0)
- return err;
+ if (IS_ERR(rt))
+ return rt;
if (flp->proto) {
if (!flp->fl4_src)
- flp->fl4_src = (*rp)->rt_src;
+ flp->fl4_src = rt->rt_src;
if (!flp->fl4_dst)
- flp->fl4_dst = (*rp)->rt_dst;
- *rp = (struct rtable *) xfrm_lookup(net, &(*rp)->dst, flp, sk, 0);
- if (IS_ERR(*rp)) {
- err = PTR_ERR(*rp);
- *rp = NULL;
- return err;
- }
+ flp->fl4_dst = rt->rt_dst;
+ rt = (struct rtable *) xfrm_lookup(net, &rt->dst, flp, sk, 0);
}
- return 0;
+ return rt;
}
EXPORT_SYMBOL_GPL(ip_route_output_flow);
-int ip_route_output_key(struct net *net, struct rtable **rp, struct flowi *flp)
+struct rtable *ip_route_output_key(struct net *net, struct flowi *flp)
{
- return ip_route_output_flow(net, rp, flp, NULL);
+ return ip_route_output_flow(net, flp, NULL);
}
EXPORT_SYMBOL(ip_route_output_key);
.oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0,
.mark = mark,
};
- err = ip_route_output_key(net, &rt, &fl);
+ rt = ip_route_output_key(net, &fl);
+
+ err = 0;
+ if (IS_ERR(rt))
+ err = PTR_ERR(rt);
}
if (err)
.fl_ip_sport = th->dest,
.fl_ip_dport = th->source };
security_req_classify_flow(req, &fl);
- if (ip_route_output_key(sock_net(sk), &rt, &fl)) {
+ rt = ip_route_output_key(sock_net(sk), &fl);
+ if (IS_ERR(rt)) {
reqsk_free(req);
goto out;
}
__be16 orig_sport, orig_dport;
struct rtable *rt;
__be32 daddr, nexthop;
- int tmp;
int err;
if (addr_len < sizeof(struct sockaddr_in))
orig_sport = inet->inet_sport;
orig_dport = usin->sin_port;
- tmp = ip_route_connect(&rt, nexthop, inet->inet_saddr,
- RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
- IPPROTO_TCP,
- orig_sport, orig_dport, sk, true);
- if (tmp < 0) {
- if (tmp == -ENETUNREACH)
+ rt = ip_route_connect(nexthop, inet->inet_saddr,
+ RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
+ IPPROTO_TCP,
+ orig_sport, orig_dport, sk, true);
+ if (IS_ERR(rt)) {
+ err = PTR_ERR(rt);
+ if (err == -ENETUNREACH)
IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
- return tmp;
+ return err;
}
if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
if (err)
goto failure;
- err = ip_route_newports(&rt, IPPROTO_TCP,
- orig_sport, orig_dport,
- inet->inet_sport, inet->inet_dport, sk);
- if (err)
+ rt = ip_route_newports(rt, IPPROTO_TCP,
+ orig_sport, orig_dport,
+ inet->inet_sport, inet->inet_dport, sk);
+ if (IS_ERR(rt)) {
+ err = PTR_ERR(rt);
+ rt = NULL;
goto failure;
-
+ }
/* OK, now commit destination to socket. */
sk->sk_gso_type = SKB_GSO_TCPV4;
sk_setup_caps(sk, &rt->dst);
struct net *net = sock_net(sk);
security_sk_classify_flow(sk, &fl);
- err = ip_route_output_flow(net, &rt, &fl, sk);
- if (err) {
+ rt = ip_route_output_flow(net, &fl, sk);
+ if (IS_ERR(rt)) {
+ err = PTR_ERR(rt);
if (err == -ENETUNREACH)
IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
goto out;
.fl4_dst = daddr->a4,
.fl4_tos = tos,
};
- struct dst_entry *dst;
struct rtable *rt;
- int err;
if (saddr)
fl.fl4_src = saddr->a4;
- err = __ip_route_output_key(net, &rt, &fl);
- dst = &rt->dst;
- if (err)
- dst = ERR_PTR(err);
- return dst;
+ rt = __ip_route_output_key(net, &fl);
+ if (!IS_ERR(rt))
+ return &rt->dst;
+
+ return ERR_CAST(rt);
}
static int xfrm4_get_saddr(struct net *net,
fl.fl4_dst = eiph->saddr;
fl.fl4_tos = RT_TOS(eiph->tos);
fl.proto = IPPROTO_IPIP;
- if (ip_route_output_key(dev_net(skb->dev), &rt, &fl))
+ rt = ip_route_output_key(dev_net(skb->dev), &fl);
+ if (IS_ERR(rt))
goto out;
skb2->dev = rt->dst.dev;
fl.fl4_dst = eiph->daddr;
fl.fl4_src = eiph->saddr;
fl.fl4_tos = eiph->tos;
- if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) ||
+ rt = ip_route_output_key(dev_net(skb->dev), &fl);
+ if (IS_ERR(rt) ||
rt->dst.dev->type != ARPHRD_TUNNEL) {
- ip_rt_put(rt);
+ if (!IS_ERR(rt))
+ ip_rt_put(rt);
goto out;
}
- skb_dst_set(skb2, (struct dst_entry *)rt);
+ skb_dst_set(skb2, &rt->dst);
} else {
ip_rt_put(rt);
if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos,
.fl4_tos = RT_TOS(tos),
.oif = tunnel->parms.link,
.proto = IPPROTO_IPV6 };
- if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
+ rt = ip_route_output_key(dev_net(dev), &fl);
+ if (IS_ERR(rt)) {
dev->stats.tx_carrier_errors++;
goto tx_error_icmp;
}
.fl4_tos = RT_TOS(iph->tos),
.oif = tunnel->parms.link,
.proto = IPPROTO_IPV6 };
- struct rtable *rt;
- if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
+ struct rtable *rt = ip_route_output_key(dev_net(dev), &fl);
+
+ if (!IS_ERR(rt)) {
tdev = rt->dst.dev;
ip_rt_put(rt);
}
if (ipv4_is_multicast(lsa->l2tp_addr.s_addr))
goto out;
- rc = ip_route_connect(&rt, lsa->l2tp_addr.s_addr, saddr,
+ rt = ip_route_connect(lsa->l2tp_addr.s_addr, saddr,
RT_CONN_FLAGS(sk), oif,
IPPROTO_L2TP,
0, 0, sk, true);
- if (rc) {
+ if (IS_ERR(rt)) {
+ rc = PTR_ERR(rt);
if (rc == -ENETUNREACH)
IP_INC_STATS_BH(&init_net, IPSTATS_MIB_OUTNOROUTES);
goto out;
* itself out.
*/
security_sk_classify_flow(sk, &fl);
- if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk))
+ rt = ip_route_output_flow(sock_net(sk), &fl, sk);
+ if (IS_ERR(rt))
goto no_route;
}
sk_setup_caps(sk, &rt->dst);
.fl4_tos = rtos,
};
- if (ip_route_output_key(net, &rt, &fl)) {
+ rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt)) {
spin_unlock(&dest->dst_lock);
IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n",
&dest->addr.ip);
.fl4_tos = rtos,
};
- if (ip_route_output_key(net, &rt, &fl)) {
+ rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt)) {
IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n",
&daddr);
return NULL;
.mark = skb->mark,
};
- if (ip_route_output_key(net, &rt, &fl))
+ rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt))
return 0;
if (!(rt->rt_flags & RTCF_LOCAL)) {
ip_rt_put(rt);
fl.fl4_dst = info->gw.ip;
fl.fl4_tos = RT_TOS(iph->tos);
fl.fl4_scope = RT_SCOPE_UNIVERSE;
- if (ip_route_output_key(net, &rt, &fl) != 0)
+ rt = ip_route_output_key(net, &fl);
+ if (IS_ERR(rt))
return false;
skb_dst_drop(skb);
{
struct rtable *rt;
struct flowi fl;
- int ret;
peer->if_mtu = 1500;
BUG();
}
- ret = ip_route_output_key(&init_net, &rt, &fl);
- if (ret < 0) {
- _leave(" [route err %d]", ret);
+ rt = ip_route_output_key(&init_net, &fl);
+ if (IS_ERR(rt)) {
+ _leave(" [route err %ld]", PTR_ERR(rt));
return;
}
SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ",
__func__, &fl.fl4_dst, &fl.fl4_src);
- if (!ip_route_output_key(&init_net, &rt, &fl)) {
+ rt = ip_route_output_key(&init_net, &fl);
+ if (!IS_ERR(rt))
dst = &rt->dst;
- }
/* If there is no association or if a source address is passed, no
* more validation is required.
(AF_INET == laddr->a.sa.sa_family)) {
fl.fl4_src = laddr->a.v4.sin_addr.s_addr;
fl.fl_ip_sport = laddr->a.v4.sin_port;
- if (!ip_route_output_key(&init_net, &rt, &fl)) {
+ rt = ip_route_output_key(&init_net, &fl);
+ if (!IS_ERR(rt)) {
dst = &rt->dst;
goto out_unlock;
}