#include <linux/in6.h>
#include <linux/init.h>
#include <linux/if_arp.h>
-
-#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#endif
-
#include <net/net_namespace.h>
#include <net/snmp.h>
#include <net/ipv6.h>
.negative_advice = ip6_negative_advice,
.link_failure = ip6_link_failure,
.update_pmtu = ip6_rt_update_pmtu,
+ .local_out = ip6_local_out,
.entry_size = sizeof(struct rt6_info),
};
static int ip6_pkt_prohibit(struct sk_buff *skb);
static int ip6_pkt_prohibit_out(struct sk_buff *skb);
-static int ip6_pkt_blk_hole(struct sk_buff *skb);
struct rt6_info ip6_prohibit_entry = {
.u = {
.obsolete = -1,
.error = -EINVAL,
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
- .input = ip6_pkt_blk_hole,
- .output = ip6_pkt_blk_hole,
+ .input = dst_discard,
+ .output = dst_discard,
.ops = &ip6_dst_ops,
.path = (struct dst_entry*)&ip6_blk_hole_entry,
}
static inline int rt6_check_neigh(struct rt6_info *rt)
{
struct neighbour *neigh = rt->rt6i_nexthop;
- int m = 0;
+ int m;
if (rt->rt6i_flags & RTF_NONEXTHOP ||
!(rt->rt6i_flags & RTF_GATEWAY))
m = 1;
read_lock_bh(&neigh->lock);
if (neigh->nud_state & NUD_VALID)
m = 2;
- else if (!(neigh->nud_state & NUD_FAILED))
+#ifdef CONFIG_IPV6_ROUTER_PREF
+ else if (neigh->nud_state & NUD_FAILED)
+ m = 0;
+#endif
+ else
m = 1;
read_unlock_bh(&neigh->lock);
- }
+ } else
+ m = 0;
return m;
}
rt = rt6_device_match(rt, fl->oif, flags);
BACKTRACK(&fl->fl6_src);
out:
- dst_hold(&rt->u.dst);
+ dst_use(&rt->u.dst, jiffies);
read_unlock_bh(&table->tb6_lock);
-
- rt->u.dst.lastuse = jiffies;
- rt->u.dst.__use++;
-
return rt;
}
EXPORT_SYMBOL(ip6_route_output);
-static int ip6_blackhole_output(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return 0;
-}
-
int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl)
{
struct rt6_info *ort = (struct rt6_info *) *dstp;
atomic_set(&new->__refcnt, 1);
new->__use = 1;
- new->input = ip6_blackhole_output;
- new->output = ip6_blackhole_output;
+ new->input = dst_discard;
+ new->output = dst_discard;
memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
new->dev = ort->u.dst.dev;
return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
}
-static int ip6_pkt_blk_hole(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return 0;
-}
-
#endif
/*
static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
+ struct net *net = skb->sk->sk_net;
struct fib6_config cfg;
int err;
+ if (net != &init_net)
+ return -EINVAL;
+
err = rtm_to_fib6_config(skb, nlh, &cfg);
if (err < 0)
return err;
static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
+ struct net *net = skb->sk->sk_net;
struct fib6_config cfg;
int err;
+ if (net != &init_net)
+ return -EINVAL;
+
err = rtm_to_fib6_config(skb, nlh, &cfg);
if (err < 0)
return err;
static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
{
+ struct net *net = in_skb->sk->sk_net;
struct nlattr *tb[RTA_MAX+1];
struct rt6_info *rt;
struct sk_buff *skb;
struct flowi fl;
int err, iif = 0;
+ if (net != &init_net)
+ return -EINVAL;
+
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
if (err < 0)
goto errout;
goto errout;
}
- err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
+ err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
errout:
return err;
}
kfree_skb(skb);
goto errout;
}
- err = rtnl_notify(skb, pid, RTNLGRP_IPV6_ROUTE, nlh, gfp_any());
+ err = rtnl_notify(skb, &init_net, pid, RTNLGRP_IPV6_ROUTE, nlh, gfp_any());
errout:
if (err < 0)
- rtnl_set_sk_err(RTNLGRP_IPV6_ROUTE, err);
+ rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_ROUTE, err);
}
/*
static int rt6_info_route(struct rt6_info *rt, void *p_arg)
{
- struct rt6_proc_arg *arg = (struct rt6_proc_arg *) p_arg;
+ struct seq_file *m = p_arg;
- if (arg->skip < arg->offset / RT6_INFO_LEN) {
- arg->skip++;
- return 0;
- }
-
- if (arg->len >= arg->length)
- return 0;
-
- arg->len += sprintf(arg->buffer + arg->len,
- NIP6_SEQFMT " %02x ",
- NIP6(rt->rt6i_dst.addr),
- rt->rt6i_dst.plen);
+ seq_printf(m, NIP6_SEQFMT " %02x ", NIP6(rt->rt6i_dst.addr),
+ rt->rt6i_dst.plen);
#ifdef CONFIG_IPV6_SUBTREES
- arg->len += sprintf(arg->buffer + arg->len,
- NIP6_SEQFMT " %02x ",
- NIP6(rt->rt6i_src.addr),
- rt->rt6i_src.plen);
+ seq_printf(m, NIP6_SEQFMT " %02x ", NIP6(rt->rt6i_src.addr),
+ rt->rt6i_src.plen);
#else
- arg->len += sprintf(arg->buffer + arg->len,
- "00000000000000000000000000000000 00 ");
+ seq_puts(m, "00000000000000000000000000000000 00 ");
#endif
if (rt->rt6i_nexthop) {
- arg->len += sprintf(arg->buffer + arg->len,
- NIP6_SEQFMT,
- NIP6(*((struct in6_addr *)rt->rt6i_nexthop->primary_key)));
+ seq_printf(m, NIP6_SEQFMT,
+ NIP6(*((struct in6_addr *)rt->rt6i_nexthop->primary_key)));
} else {
- arg->len += sprintf(arg->buffer + arg->len,
- "00000000000000000000000000000000");
+ seq_puts(m, "00000000000000000000000000000000");
}
- arg->len += sprintf(arg->buffer + arg->len,
- " %08x %08x %08x %08x %8s\n",
- rt->rt6i_metric, atomic_read(&rt->u.dst.__refcnt),
- rt->u.dst.__use, rt->rt6i_flags,
- rt->rt6i_dev ? rt->rt6i_dev->name : "");
+ seq_printf(m, " %08x %08x %08x %08x %8s\n",
+ rt->rt6i_metric, atomic_read(&rt->u.dst.__refcnt),
+ rt->u.dst.__use, rt->rt6i_flags,
+ rt->rt6i_dev ? rt->rt6i_dev->name : "");
return 0;
}
-static int rt6_proc_info(char *buffer, char **start, off_t offset, int length)
+static int ipv6_route_show(struct seq_file *m, void *v)
{
- struct rt6_proc_arg arg = {
- .buffer = buffer,
- .offset = offset,
- .length = length,
- };
-
- fib6_clean_all(rt6_info_route, 0, &arg);
-
- *start = buffer;
- if (offset)
- *start += offset % RT6_INFO_LEN;
-
- arg.len -= offset % RT6_INFO_LEN;
-
- if (arg.len > length)
- arg.len = length;
- if (arg.len < 0)
- arg.len = 0;
+ fib6_clean_all(rt6_info_route, 0, m);
+ return 0;
+}
- return arg.len;
+static int ipv6_route_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ipv6_route_show, NULL);
}
+static const struct file_operations ipv6_route_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = ipv6_route_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static int rt6_stats_seq_show(struct seq_file *seq, void *v)
{
seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
ctl_table ipv6_route_table[] = {
{
- .ctl_name = NET_IPV6_ROUTE_FLUSH,
.procname = "flush",
.data = &flush_delay,
.maxlen = sizeof(int),
void __init ip6_route_init(void)
{
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *p;
-#endif
ip6_dst_ops.kmem_cachep =
kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep;
fib6_init();
-#ifdef CONFIG_PROC_FS
- p = proc_net_create(&init_net, "ipv6_route", 0, rt6_proc_info);
- if (p)
- p->owner = THIS_MODULE;
-
+ proc_net_fops_create(&init_net, "ipv6_route", 0, &ipv6_route_proc_fops);
proc_net_fops_create(&init_net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
-#endif
#ifdef CONFIG_XFRM
xfrm6_init();
#endif