static int ip6_dst_gc(void);
static int ip6_pkt_discard(struct sk_buff *skb);
-static int ip6_pkt_discard_out(struct sk_buff *skb);
+static int ip6_pkt_discard_out(struct sk_buff **pskb);
static void ip6_link_failure(struct sk_buff *skb);
static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
BACKTRACK();
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
- struct rt6_info *nrt;
- dst_hold(&rt->u.dst);
read_unlock_bh(&rt6_lock);
- nrt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
- &skb->nh.ipv6h->saddr);
-
- dst_release(&rt->u.dst);
- rt = nrt;
-
+ rt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
+ &skb->nh.ipv6h->saddr);
+
if (rt->u.dst.error != -EEXIST || --attempts <= 0)
goto out2;
-
/* Race condition! In the gap, when rt6_lock was
released someone could insert this route. Relookup.
*/
}
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
- struct rt6_info *nrt;
- dst_hold(&rt->u.dst);
read_unlock_bh(&rt6_lock);
- nrt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src);
-
- dst_release(&rt->u.dst);
- rt = nrt;
+ rt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src);
if (rt->u.dst.error != -EEXIST || --attempts <= 0)
goto out2;
struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
struct neighbour *neigh,
struct in6_addr *addr,
- int (*output)(struct sk_buff *))
+ int (*output)(struct sk_buff **))
{
struct rt6_info *rt;
struct inet6_dev *idev = in6_dev_get(dev);
return NULL;
rt = ip6_dst_alloc();
- if (unlikely(rt == NULL)) {
- in6_dev_put(idev);
+ if (unlikely(rt == NULL))
goto out;
- }
dev_hold(dev);
if (neigh)
rt = ip6_dst_alloc();
- if (rt == NULL) {
- err = -ENOMEM;
- goto out;
- }
+ if (rt == NULL)
+ return -ENOMEM;
rt->u.dst.obsolete = -1;
rt->rt6i_expires = clock_t_to_jiffies(rtmsg->rtmsg_info);
out:
if (dev)
dev_put(dev);
- if (idev)
- in6_dev_put(idev);
- if (rt)
- dst_free((struct dst_entry *) rt);
+ dst_free((struct dst_entry *) rt);
return err;
}
rt6_reset_dflt_pointer(NULL);
- err = fib6_del(rt, nlh, _rtattr);
dst_release(&rt->u.dst);
+ err = fib6_del(rt, nlh, _rtattr);
write_unlock_bh(&rt6_lock);
return err;
rt->rt6i_dev->ifindex != rtmsg->rtmsg_ifindex))
continue;
if (rtmsg->rtmsg_flags&RTF_GATEWAY &&
- !ipv6_addr_equal(&rtmsg->rtmsg_gateway, &rt->rt6i_gateway))
+ ipv6_addr_cmp(&rtmsg->rtmsg_gateway, &rt->rt6i_gateway))
continue;
if (rtmsg->rtmsg_metric &&
rtmsg->rtmsg_metric != rt->rt6i_metric)
* is a bit fuzzy and one might need to check all default
* routers.
*/
- if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) {
+ if (ipv6_addr_cmp(saddr, &rt->rt6i_gateway)) {
if (rt->rt6i_flags & RTF_DEFAULT) {
struct rt6_info *rt1;
read_lock(&rt6_lock);
for (rt1 = ip6_routing_table.leaf; rt1; rt1 = rt1->u.next) {
- if (ipv6_addr_equal(saddr, &rt1->rt6i_gateway)) {
+ if (!ipv6_addr_cmp(saddr, &rt1->rt6i_gateway)) {
dst_hold(&rt1->u.dst);
dst_release(&rt->u.dst);
read_unlock(&rt6_lock);
write_lock_bh(&rt6_lock);
for (rt = fn->leaf; rt; rt=rt->u.next) {
if (dev == rt->rt6i_dev &&
- ipv6_addr_equal(&rt->rt6i_gateway, addr))
+ ipv6_addr_cmp(&rt->rt6i_gateway, addr) == 0)
break;
}
if (rt)
return rt6_get_dflt_router(gwaddr, dev);
}
-void rt6_purge_dflt_routers(void)
+void rt6_purge_dflt_routers(int last_resort)
{
struct rt6_info *rt;
+ u32 flags;
+
+ if (last_resort)
+ flags = RTF_ALLONLINK;
+ else
+ flags = RTF_DEFAULT | RTF_ADDRCONF;
restart:
read_lock_bh(&rt6_lock);
for (rt = ip6_routing_table.leaf; rt; rt = rt->u.next) {
- if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
+ if (rt->rt6i_flags & flags) {
dst_hold(&rt->u.dst);
rt6_reset_dflt_pointer(NULL);
return 0;
}
-int ip6_pkt_discard_out(struct sk_buff *skb)
+int ip6_pkt_discard_out(struct sk_buff **pskb)
{
- skb->dev = skb->dst->dev;
- return ip6_pkt_discard(skb);
+ (*pskb)->dev = (*pskb)->dst->dev;
+ BUG_ON(!(*pskb)->dev);
+ return ip6_pkt_discard(*pskb);
}
/*
rtm->rtm_protocol = rt->rt6i_protocol;
if (rt->rt6i_flags&RTF_DYNAMIC)
rtm->rtm_protocol = RTPROT_REDIRECT;
- else if (rt->rt6i_flags & RTF_ADDRCONF)
+ else if (rt->rt6i_flags&(RTF_ADDRCONF|RTF_ALLONLINK))
rtm->rtm_protocol = RTPROT_KERNEL;
else if (rt->rt6i_flags&RTF_DEFAULT)
rtm->rtm_protocol = RTPROT_RA;