aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/Kconfig14
-rw-r--r--net/ipv6/addrconf.c93
-rw-r--r--net/ipv6/addrlabel.c8
-rw-r--r--net/ipv6/af_inet6.c2
-rw-r--r--net/ipv6/datagram.c8
-rw-r--r--net/ipv6/icmp.c4
-rw-r--r--net/ipv6/ip6_input.c4
-rw-r--r--net/ipv6/ip6_output.c68
-rw-r--r--net/ipv6/ip6_tunnel.c8
-rw-r--r--net/ipv6/ip6mr.c946
-rw-r--r--net/ipv6/mcast.c9
-rw-r--r--net/ipv6/ndisc.c6
-rw-r--r--net/ipv6/netfilter.c25
-rw-r--r--net/ipv6/netfilter/ip6_queue.c4
-rw-r--r--net/ipv6/netfilter/ip6_tables.c236
-rw-r--r--net/ipv6/netfilter/ip6t_LOG.c20
-rw-r--r--net/ipv6/netfilter/ip6t_REJECT.c32
-rw-r--r--net/ipv6/netfilter/ip6t_ah.c18
-rw-r--r--net/ipv6/netfilter/ip6t_eui64.c4
-rw-r--r--net/ipv6/netfilter/ip6t_frag.c18
-rw-r--r--net/ipv6/netfilter/ip6t_hbh.c29
-rw-r--r--net/ipv6/netfilter/ip6t_ipv6header.c8
-rw-r--r--net/ipv6/netfilter/ip6t_mh.c21
-rw-r--r--net/ipv6/netfilter/ip6t_rt.c20
-rw-r--r--net/ipv6/netfilter/ip6table_filter.c2
-rw-r--r--net/ipv6/netfilter/ip6table_mangle.c2
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c14
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c2
-rw-r--r--net/ipv6/proc.c1
-rw-r--r--net/ipv6/raw.c4
-rw-r--r--net/ipv6/route.c4
-rw-r--r--net/ipv6/sit.c8
-rw-r--r--net/ipv6/tcp_ipv6.c4
-rw-r--r--net/ipv6/udp.c5
-rw-r--r--net/ipv6/xfrm6_input.c2
-rw-r--r--net/ipv6/xfrm6_output.c4
36 files changed, 1031 insertions, 626 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index a578096..36d7437 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -229,6 +229,20 @@ config IPV6_MROUTE
Experimental support for IPv6 multicast forwarding.
If unsure, say N.
+config IPV6_MROUTE_MULTIPLE_TABLES
+ bool "IPv6: multicast policy routing"
+ depends on IPV6_MROUTE
+ select FIB_RULES
+ help
+ Normally, a multicast router runs a userspace daemon and decides
+ what to do with a multicast packet based on the source and
+ destination addresses. If you say Y here, the multicast router
+ will also be able to take interfaces and packet marks into
+ account and run multiple instances of userspace daemons
+ simultaneously, each one handling a single table.
+
+ If unsure, say N.
+
config IPV6_PIMSM_V2
bool "IPv6: PIM-SM version 2 support (EXPERIMENTAL)"
depends on IPV6_MROUTE
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 3984f52..e1a698d 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -553,7 +553,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
if (del_timer(&ifp->timer))
pr_notice("Timer is still running, when freeing ifa=%p\n", ifp);
- if (!ifp->dead) {
+ if (ifp->state != INET6_IFADDR_STATE_DEAD) {
pr_warning("Freeing alive inet6 address %p\n", ifp);
return;
}
@@ -648,6 +648,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
ipv6_addr_copy(&ifa->addr, addr);
spin_lock_init(&ifa->lock);
+ spin_lock_init(&ifa->state_lock);
init_timer(&ifa->timer);
INIT_HLIST_NODE(&ifa->addr_lst);
ifa->timer.data = (unsigned long) ifa;
@@ -714,13 +715,20 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
{
struct inet6_ifaddr *ifa, *ifn;
struct inet6_dev *idev = ifp->idev;
+ int state;
int hash;
int deleted = 0, onlink = 0;
unsigned long expires = jiffies;
hash = ipv6_addr_hash(&ifp->addr);
- ifp->dead = 1;
+ spin_lock_bh(&ifp->state_lock);
+ state = ifp->state;
+ ifp->state = INET6_IFADDR_STATE_DEAD;
+ spin_unlock_bh(&ifp->state_lock);
+
+ if (state == INET6_IFADDR_STATE_DEAD)
+ goto out;
spin_lock_bh(&addrconf_hash_lock);
hlist_del_init_rcu(&ifp->addr_lst);
@@ -818,6 +826,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
dst_release(&rt->u.dst);
}
+out:
in6_ifa_put(ifp);
}
@@ -1274,7 +1283,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev)
int ipv6_chk_addr(struct net *net, struct in6_addr *addr,
struct net_device *dev, int strict)
{
- struct inet6_ifaddr *ifp = NULL;
+ struct inet6_ifaddr *ifp;
struct hlist_node *node;
unsigned int hash = ipv6_addr_hash(addr);
@@ -1283,15 +1292,16 @@ int ipv6_chk_addr(struct net *net, struct in6_addr *addr,
if (!net_eq(dev_net(ifp->idev->dev), net))
continue;
if (ipv6_addr_equal(&ifp->addr, addr) &&
- !(ifp->flags&IFA_F_TENTATIVE)) {
- if (dev == NULL || ifp->idev->dev == dev ||
- !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))
- break;
+ !(ifp->flags&IFA_F_TENTATIVE) &&
+ (dev == NULL || ifp->idev->dev == dev ||
+ !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) {
+ rcu_read_unlock_bh();
+ return 1;
}
}
- rcu_read_unlock_bh();
- return ifp != NULL;
+ rcu_read_unlock_bh();
+ return 0;
}
EXPORT_SYMBOL(ipv6_chk_addr);
@@ -1396,10 +1406,27 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
ipv6_del_addr(ifp);
}
+static int addrconf_dad_end(struct inet6_ifaddr *ifp)
+{
+ int err = -ENOENT;
+
+ spin_lock(&ifp->state_lock);
+ if (ifp->state == INET6_IFADDR_STATE_DAD) {
+ ifp->state = INET6_IFADDR_STATE_POSTDAD;
+ err = 0;
+ }
+ spin_unlock(&ifp->state_lock);
+
+ return err;
+}
+
void addrconf_dad_failure(struct inet6_ifaddr *ifp)
{
struct inet6_dev *idev = ifp->idev;
+ if (addrconf_dad_end(ifp))
+ return;
+
if (net_ratelimit())
printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n",
ifp->idev->dev->name, &ifp->addr);
@@ -2624,6 +2651,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
LIST_HEAD(keep_list);
+ int state;
ASSERT_RTNL();
@@ -2664,7 +2692,6 @@ static int addrconf_ifdown(struct net_device *dev, int how)
ifa = list_first_entry(&idev->tempaddr_list,
struct inet6_ifaddr, tmp_list);
list_del(&ifa->tmp_list);
- ifa->dead = 1;
write_unlock_bh(&idev->lock);
spin_lock_bh(&ifa->lock);
@@ -2702,23 +2729,35 @@ static int addrconf_ifdown(struct net_device *dev, int how)
/* Flag it for later restoration when link comes up */
ifa->flags |= IFA_F_TENTATIVE;
- in6_ifa_hold(ifa);
+ ifa->state = INET6_IFADDR_STATE_DAD;
+
write_unlock_bh(&idev->lock);
+
+ in6_ifa_hold(ifa);
} else {
list_del(&ifa->if_list);
- ifa->dead = 1;
- write_unlock_bh(&idev->lock);
/* clear hash table */
spin_lock_bh(&addrconf_hash_lock);
hlist_del_init_rcu(&ifa->addr_lst);
spin_unlock_bh(&addrconf_hash_lock);
+
+ write_unlock_bh(&idev->lock);
+ spin_lock_bh(&ifa->state_lock);
+ state = ifa->state;
+ ifa->state = INET6_IFADDR_STATE_DEAD;
+ spin_unlock_bh(&ifa->state_lock);
+
+ if (state == INET6_IFADDR_STATE_DEAD)
+ goto put_ifa;
}
__ipv6_ifa_notify(RTM_DELADDR, ifa);
- if (ifa->dead)
+ if (ifa->state == INET6_IFADDR_STATE_DEAD)
atomic_notifier_call_chain(&inet6addr_chain,
NETDEV_DOWN, ifa);
+
+put_ifa:
in6_ifa_put(ifa);
write_lock_bh(&idev->lock);
@@ -2814,10 +2853,10 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
net_srandom(ifp->addr.s6_addr32[3]);
read_lock_bh(&idev->lock);
- if (ifp->dead)
+ spin_lock(&ifp->lock);
+ if (ifp->state == INET6_IFADDR_STATE_DEAD)
goto out;
- spin_lock(&ifp->lock);
if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
idev->cnf.accept_dad < 1 ||
!(ifp->flags&IFA_F_TENTATIVE) ||
@@ -2851,8 +2890,8 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
ip6_ins_rt(ifp->rt);
addrconf_dad_kick(ifp);
- spin_unlock(&ifp->lock);
out:
+ spin_unlock(&ifp->lock);
read_unlock_bh(&idev->lock);
}
@@ -2862,6 +2901,9 @@ static void addrconf_dad_timer(unsigned long data)
struct inet6_dev *idev = ifp->idev;
struct in6_addr mcaddr;
+ if (!ifp->probes && addrconf_dad_end(ifp))
+ goto out;
+
read_lock(&idev->lock);
if (idev->dead || !(idev->if_flags & IF_READY)) {
read_unlock(&idev->lock);
@@ -2869,6 +2911,12 @@ static void addrconf_dad_timer(unsigned long data)
}
spin_lock(&ifp->lock);
+ if (ifp->state == INET6_IFADDR_STATE_DEAD) {
+ spin_unlock(&ifp->lock);
+ read_unlock(&idev->lock);
+ goto out;
+ }
+
if (ifp->probes == 0) {
/*
* DAD was successful
@@ -2935,12 +2983,10 @@ static void addrconf_dad_run(struct inet6_dev *idev)
read_lock_bh(&idev->lock);
list_for_each_entry(ifp, &idev->addr_list, if_list) {
spin_lock(&ifp->lock);
- if (!(ifp->flags & IFA_F_TENTATIVE)) {
- spin_unlock(&ifp->lock);
- continue;
- }
+ if (ifp->flags & IFA_F_TENTATIVE &&
+ ifp->state == INET6_IFADDR_STATE_DAD)
+ addrconf_dad_kick(ifp);
spin_unlock(&ifp->lock);
- addrconf_dad_kick(ifp);
}
read_unlock_bh(&idev->lock);
}
@@ -4049,7 +4095,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
addrconf_leave_solict(ifp->idev, &ifp->addr);
dst_hold(&ifp->rt->u.dst);
- if (ifp->dead && ip6_del_rt(ifp->rt))
+ if (ifp->state == INET6_IFADDR_STATE_DEAD &&
+ ip6_del_rt(ifp->rt))
dst_free(&ifp->rt->u.dst);
break;
}
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index ae404c9..8c4348c 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -422,10 +422,6 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
ifal->ifal_prefixlen > 128)
return -EINVAL;
- if (ifal->ifal_index &&
- !__dev_get_by_index(net, ifal->ifal_index))
- return -EINVAL;
-
if (!tb[IFAL_ADDRESS])
return -EINVAL;
@@ -441,6 +437,10 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
switch(nlh->nlmsg_type) {
case RTM_NEWADDRLABEL:
+ if (ifal->ifal_index &&
+ !__dev_get_by_index(net, ifal->ifal_index))
+ return -EINVAL;
+
err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen,
ifal->ifal_index, label,
nlh->nlmsg_flags & NLM_F_REPLACE);
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index d2df314..e733942 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -200,7 +200,7 @@ lookup_protocol:
inet_sk(sk)->pinet6 = np = inet6_sk_generic(sk);
np->hop_limit = -1;
- np->mcast_hops = -1;
+ np->mcast_hops = IPV6_DEFAULT_MCASTHOPS;
np->mc_loop = 1;
np->pmtudisc = IPV6_PMTUDISC_WANT;
np->ipv6only = net->ipv6.sysctl.bindv6only;
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 5959230..7126846 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -222,6 +222,8 @@ void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
if (!skb)
return;
+ skb->protocol = htons(ETH_P_IPV6);
+
serr = SKB_EXT_ERR(skb);
serr->ee.ee_errno = err;
serr->ee.ee_origin = SO_EE_ORIGIN_ICMP6;
@@ -255,6 +257,8 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info)
if (!skb)
return;
+ skb->protocol = htons(ETH_P_IPV6);
+
skb_put(skb, sizeof(struct ipv6hdr));
skb_reset_network_header(skb);
iph = ipv6_hdr(skb);
@@ -358,7 +362,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
sin->sin6_flowinfo = 0;
sin->sin6_port = serr->port;
sin->sin6_scope_id = 0;
- if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
+ if (skb->protocol == htons(ETH_P_IPV6)) {
ipv6_addr_copy(&sin->sin6_addr,
(struct in6_addr *)(nh + serr->addr_offset));
if (np->sndflow)
@@ -380,7 +384,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
sin->sin6_family = AF_INET6;
sin->sin6_flowinfo = 0;
sin->sin6_scope_id = 0;
- if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
+ if (skb->protocol == htons(ETH_P_IPV6)) {
ipv6_addr_copy(&sin->sin6_addr, &ipv6_hdr(skb)->saddr);
if (np->rxopt.all)
datagram_recv_ctl(sk, msg, skb);
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index ce79929..03e62f9 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -483,7 +483,7 @@ route_done:
np->tclass, NULL, &fl, (struct rt6_info*)dst,
MSG_DONTWAIT, np->dontfrag);
if (err) {
- ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
+ ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
ip6_flush_pending_frames(sk);
goto out_put;
}
@@ -565,7 +565,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
np->dontfrag);
if (err) {
- ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
+ ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
ip6_flush_pending_frames(sk);
goto out_put;
}
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 6aa7ee1..a83e920 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -143,7 +143,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
/* Must drop socket now because of tproxy. */
skb_orphan(skb);
- return NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, dev, NULL,
+ return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, dev, NULL,
ip6_rcv_finish);
err:
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
@@ -236,7 +236,7 @@ discard:
int ip6_input(struct sk_buff *skb)
{
- return NF_HOOK(PF_INET6, NF_INET_LOCAL_IN, skb, skb->dev, NULL,
+ return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN, skb, skb->dev, NULL,
ip6_input_finish);
}
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index e7a5f17..89425af 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -67,8 +67,8 @@ int __ip6_local_out(struct sk_buff *skb)
len = 0;
ipv6_hdr(skb)->payload_len = htons(len);
- return nf_hook(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev,
- dst_output);
+ return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
+ skb_dst(skb)->dev, dst_output);
}
int ip6_local_out(struct sk_buff *skb)
@@ -83,22 +83,6 @@ int ip6_local_out(struct sk_buff *skb)
}
EXPORT_SYMBOL_GPL(ip6_local_out);
-static int ip6_output_finish(struct sk_buff *skb)
-{
- struct dst_entry *dst = skb_dst(skb);
-
- if (dst->hh)
- return neigh_hh_output(dst->hh, skb);
- else if (dst->neighbour)
- return dst->neighbour->output(skb);
-
- IP6_INC_STATS_BH(dev_net(dst->dev),
- ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
- kfree_skb(skb);
- return -EINVAL;
-
-}
-
/* dev_loopback_xmit for use with netfilter. */
static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
{
@@ -112,8 +96,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
return 0;
}
-
-static int ip6_output2(struct sk_buff *skb)
+static int ip6_finish_output2(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct net_device *dev = dst->dev;
@@ -125,7 +108,7 @@ static int ip6_output2(struct sk_buff *skb)
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) &&
- ((mroute6_socket(dev_net(dev)) &&
+ ((mroute6_socket(dev_net(dev), skb) &&
!(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
&ipv6_hdr(skb)->saddr))) {
@@ -135,8 +118,8 @@ static int ip6_output2(struct sk_buff *skb)
is not supported in any case.
*/
if (newskb)
- NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, newskb,
- NULL, newskb->dev,
+ NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING,
+ newskb, NULL, newskb->dev,
ip6_dev_loopback_xmit);
if (ipv6_hdr(skb)->hop_limit == 0) {
@@ -151,8 +134,15 @@ static int ip6_output2(struct sk_buff *skb)
skb->len);
}
- return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dev,
- ip6_output_finish);
+ if (dst->hh)
+ return neigh_hh_output(dst->hh, skb);
+ else if (dst->neighbour)
+ return dst->neighbour->output(skb);
+
+ IP6_INC_STATS_BH(dev_net(dst->dev),
+ ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
+ kfree_skb(skb);
+ return -EINVAL;
}
static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
@@ -163,21 +153,29 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
}
+static int ip6_finish_output(struct sk_buff *skb)
+{
+ if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
+ dst_allfrag(skb_dst(skb)))
+ return ip6_fragment(skb, ip6_finish_output2);
+ else
+ return ip6_finish_output2(skb);
+}
+
int ip6_output(struct sk_buff *skb)
{
+ struct net_device *dev = skb_dst(skb)->dev;
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
if (unlikely(idev->cnf.disable_ipv6)) {
- IP6_INC_STATS(dev_net(skb_dst(skb)->dev), idev,
+ IP6_INC_STATS(dev_net(dev), idev,
IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
return 0;
}
- if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
- dst_allfrag(skb_dst(skb)))
- return ip6_fragment(skb, ip6_output2);
- else
- return ip6_output2(skb);
+ return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, dev,
+ ip6_finish_output,
+ !(IP6CB(skb)->flags & IP6SKB_REROUTED));
}
/*
@@ -256,8 +254,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) {
IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)),
IPSTATS_MIB_OUT, skb->len);
- return NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
- dst_output);
+ return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
+ dst->dev, dst_output);
}
if (net_ratelimit())
@@ -509,7 +507,7 @@ int ip6_forward(struct sk_buff *skb)
if (mtu < IPV6_MIN_MTU)
mtu = IPV6_MIN_MTU;
- if (skb->len > mtu) {
+ if (skb->len > mtu && !skb_is_gso(skb)) {
/* Again, force OUTPUT device used as source address */
skb->dev = dst->dev;
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
@@ -533,7 +531,7 @@ int ip6_forward(struct sk_buff *skb)
hdr->hop_limit--;
IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
- return NF_HOOK(PF_INET6, NF_INET_FORWARD, skb, skb->dev, dst->dev,
+ return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dst->dev,
ip6_forward_finish);
error:
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 2599870..8f39893 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -723,14 +723,10 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
skb->protocol = htons(protocol);
skb->pkt_type = PACKET_HOST;
memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
- skb->dev = t->dev;
- skb_dst_drop(skb);
- nf_reset(skb);
- dscp_ecn_decapsulate(t, ipv6h, skb);
+ skb_tunnel_rx(skb, t->dev);
- t->dev->stats.rx_packets++;
- t->dev->stats.rx_bytes += skb->len;
+ dscp_ecn_decapsulate(t, ipv6h, skb);
netif_rx(skb);
rcu_read_unlock();
return 0;
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 3e33326..66078da 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -42,6 +42,7 @@
#include <linux/if_arp.h>
#include <net/checksum.h>
#include <net/netlink.h>
+#include <net/fib_rules.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
@@ -51,6 +52,34 @@
#include <linux/netfilter_ipv6.h>
#include <net/ip6_checksum.h>
+struct mr6_table {
+ struct list_head list;
+#ifdef CONFIG_NET_NS
+ struct net *net;
+#endif
+ u32 id;
+ struct sock *mroute6_sk;
+ struct timer_list ipmr_expire_timer;
+ struct list_head mfc6_unres_queue;
+ struct list_head mfc6_cache_array[MFC6_LINES];
+ struct mif_device vif6_table[MAXMIFS];
+ int maxvif;
+ atomic_t cache_resolve_queue_len;
+ int mroute_do_assert;
+ int mroute_do_pim;
+#ifdef CONFIG_IPV6_PIMSM_V2
+ int mroute_reg_vif_num;
+#endif
+};
+
+struct ip6mr_rule {
+ struct fib_rule common;
+};
+
+struct ip6mr_result {
+ struct mr6_table *mrt;
+};
+
/* Big lock, protecting vif table, mrt cache and mroute socket state.
Note that the changes are semaphored via rtnl_lock.
*/
@@ -61,9 +90,7 @@ static DEFINE_RWLOCK(mrt_lock);
* Multicast router control variables
*/
-#define MIF_EXISTS(_net, _idx) ((_net)->ipv6.vif6_table[_idx].dev != NULL)
-
-static struct mfc6_cache *mfc_unres_queue; /* Queue of unresolved entries */
+#define MIF_EXISTS(_mrt, _idx) ((_mrt)->vif6_table[_idx].dev != NULL)
/* Special spinlock for queue of unresolved entries */
static DEFINE_SPINLOCK(mfc_unres_lock);
@@ -78,20 +105,235 @@ static DEFINE_SPINLOCK(mfc_unres_lock);
static struct kmem_cache *mrt_cachep __read_mostly;
-static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache);
-static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt,
+static struct mr6_table *ip6mr_new_table(struct net *net, u32 id);
+static void ip6mr_free_table(struct mr6_table *mrt);
+
+static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
+ struct sk_buff *skb, struct mfc6_cache *cache);
+static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
mifi_t mifi, int assert);
-static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm);
-static void mroute_clean_tables(struct net *net);
+static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
+ struct mfc6_cache *c, struct rtmsg *rtm);
+static int ip6mr_rtm_dumproute(struct sk_buff *skb,
+ struct netlink_callback *cb);
+static void mroute_clean_tables(struct mr6_table *mrt);
+static void ipmr_expire_process(unsigned long arg);
+
+#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
+#define ip6mr_for_each_table(mrt, net) \
+ list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list)
+
+static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
+{
+ struct mr6_table *mrt;
+
+ ip6mr_for_each_table(mrt, net) {
+ if (mrt->id == id)
+ return mrt;
+ }
+ return NULL;
+}
+
+static int ip6mr_fib_lookup(struct net *net, struct flowi *flp,
+ struct mr6_table **mrt)
+{
+ struct ip6mr_result res;
+ struct fib_lookup_arg arg = { .result = &res, };
+ int err;
+
+ err = fib_rules_lookup(net->ipv6.mr6_rules_ops, flp, 0, &arg);
+ if (err < 0)
+ return err;
+ *mrt = res.mrt;
+ return 0;
+}
+
+static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
+ int flags, struct fib_lookup_arg *arg)
+{
+ struct ip6mr_result *res = arg->result;
+ struct mr6_table *mrt;
+
+ switch (rule->action) {
+ case FR_ACT_TO_TBL:
+ break;
+ case FR_ACT_UNREACHABLE:
+ return -ENETUNREACH;
+ case FR_ACT_PROHIBIT:
+ return -EACCES;
+ case FR_ACT_BLACKHOLE:
+ default:
+ return -EINVAL;
+ }
+
+ mrt = ip6mr_get_table(rule->fr_net, rule->table);
+ if (mrt == NULL)
+ return -EAGAIN;
+ res->mrt = mrt;
+ return 0;
+}
+
+static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags)
+{
+ return 1;
+}
+
+static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = {
+ FRA_GENERIC_POLICY,
+};
+
+static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
+ struct fib_rule_hdr *frh, struct nlattr **tb)
+{
+ return 0;
+}
+
+static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
+ struct nlattr **tb)
+{
+ return 1;
+}
+
+static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
+ struct fib_rule_hdr *frh)
+{
+ frh->dst_len = 0;
+ frh->src_len = 0;
+ frh->tos = 0;
+ return 0;
+}
+
+static const struct fib_rules_ops __net_initdata ip6mr_rules_ops_template = {
+ .family = RTNL_FAMILY_IP6MR,
+ .rule_size = sizeof(struct ip6mr_rule),
+ .addr_size = sizeof(struct in6_addr),
+ .action = ip6mr_rule_action,
+ .match = ip6mr_rule_match,
+ .configure = ip6mr_rule_configure,
+ .compare = ip6mr_rule_compare,
+ .default_pref = fib_default_rule_pref,
+ .fill = ip6mr_rule_fill,
+ .nlgroup = RTNLGRP_IPV6_RULE,
+ .policy = ip6mr_rule_policy,
+ .owner = THIS_MODULE,
+};
+
+static int __net_init ip6mr_rules_init(struct net *net)
+{
+ struct fib_rules_ops *ops;
+ struct mr6_table *mrt;
+ int err;
+
+ ops = fib_rules_register(&ip6mr_rules_ops_template, net);
+ if (IS_ERR(ops))
+ return PTR_ERR(ops);
+
+ INIT_LIST_HEAD(&net->ipv6.mr6_tables);
+
+ mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
+ if (mrt == NULL) {
+ err = -ENOMEM;
+ goto err1;
+ }
+
+ err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0);
+ if (err < 0)
+ goto err2;
+
+ net->ipv6.mr6_rules_ops = ops;
+ return 0;
+
+err2:
+ kfree(mrt);
+err1:
+ fib_rules_unregister(ops);
+ return err;
+}
+
+static void __net_exit ip6mr_rules_exit(struct net *net)
+{
+ struct mr6_table *mrt, *next;
+
+ list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
+ list_del(&mrt->list);
+ ip6mr_free_table(mrt);
+ }
+ fib_rules_unregister(net->ipv6.mr6_rules_ops);
+}
+#else
+#define ip6mr_for_each_table(mrt, net) \
+ for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
+
+static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
+{
+ return net->ipv6.mrt6;
+}
+
+static int ip6mr_fib_lookup(struct net *net, struct flowi *flp,
+ struct mr6_table **mrt)
+{
+ *mrt = net->ipv6.mrt6;
+ return 0;
+}
+
+static int __net_init ip6mr_rules_init(struct net *net)
+{
+ net->ipv6.mrt6 = ip6mr_new_table(net, RT6_TABLE_DFLT);
+ return net->ipv6.mrt6 ? 0 : -ENOMEM;
+}
+
+static void __net_exit ip6mr_rules_exit(struct net *net)
+{
+ ip6mr_free_table(net->ipv6.mrt6);
+}
+#endif
+
+static struct mr6_table *ip6mr_new_table(struct net *net, u32 id)
+{
+ struct mr6_table *mrt;
+ unsigned int i;
-static struct timer_list ipmr_expire_timer;
+ mrt = ip6mr_get_table(net, id);
+ if (mrt != NULL)
+ return mrt;
+ mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
+ if (mrt == NULL)
+ return NULL;
+ mrt->id = id;
+ write_pnet(&mrt->net, net);
+
+ /* Forwarding cache */
+ for (i = 0; i < MFC6_LINES; i++)
+ INIT_LIST_HEAD(&mrt->mfc6_cache_array[i]);
+
+ INIT_LIST_HEAD(&mrt->mfc6_unres_queue);
+
+ setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process,
+ (unsigned long)mrt);
+
+#ifdef CONFIG_IPV6_PIMSM_V2
+ mrt->mroute_reg_vif_num = -1;
+#endif
+#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
+ list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables);
+#endif
+ return mrt;
+}
+
+static void ip6mr_free_table(struct mr6_table *mrt)
+{
+ del_timer(&mrt->ipmr_expire_timer);
+ mroute_clean_tables(mrt);
+ kfree(mrt);
+}
#ifdef CONFIG_PROC_FS
struct ipmr_mfc_iter {
struct seq_net_private p;
- struct mfc6_cache **cache;
+ struct mr6_table *mrt;
+ struct list_head *cache;
int ct;
};
@@ -99,22 +341,22 @@ struct ipmr_mfc_iter {
static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
struct ipmr_mfc_iter *it, loff_t pos)
{
+ struct mr6_table *mrt = it->mrt;
struct mfc6_cache *mfc;
- it->cache = net->ipv6.mfc6_cache_array;
read_lock(&mrt_lock);
- for (it->ct = 0; it->ct < MFC6_LINES; it->ct++)
- for (mfc = net->ipv6.mfc6_cache_array[it->ct];
- mfc; mfc = mfc->next)
+ for (it->ct = 0; it->ct < MFC6_LINES; it->ct++) {
+ it->cache = &mrt->mfc6_cache_array[it->ct];
+ list_for_each_entry(mfc, it->cache, list)
if (pos-- == 0)
return mfc;
+ }
read_unlock(&mrt_lock);
- it->cache = &mfc_unres_queue;
spin_lock_bh(&mfc_unres_lock);
- for (mfc = mfc_unres_queue; mfc; mfc = mfc->next)
- if (net_eq(mfc6_net(mfc), net) &&
- pos-- == 0)
+ it->cache = &mrt->mfc6_unres_queue;
+ list_for_each_entry(mfc, it->cache, list)
+ if (pos-- == 0)
return mfc;
spin_unlock_bh(&mfc_unres_lock);
@@ -122,15 +364,13 @@ static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
return NULL;
}
-
-
-
/*
* The /proc interfaces to multicast routing /proc/ip6_mr_cache /proc/ip6_mr_vif
*/
struct ipmr_vif_iter {
struct seq_net_private p;
+ struct mr6_table *mrt;
int ct;
};
@@ -138,11 +378,13 @@ static struct mif_device *ip6mr_vif_seq_idx(struct net *net,
struct ipmr_vif_iter *iter,
loff_t pos)
{
- for (iter->ct = 0; iter->ct < net->ipv6.maxvif; ++iter->ct) {
- if (!MIF_EXISTS(net, iter->ct))
+ struct mr6_table *mrt = iter->mrt;
+
+ for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
+ if (!MIF_EXISTS(mrt, iter->ct))
continue;
if (pos-- == 0)
- return &net->ipv6.vif6_table[iter->ct];
+ return &mrt->vif6_table[iter->ct];
}
return NULL;
}
@@ -150,7 +392,15 @@ static struct mif_device *ip6mr_vif_seq_idx(struct net *net,
static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(mrt_lock)
{
+ struct ipmr_vif_iter *iter = seq->private;
struct net *net = seq_file_net(seq);
+ struct mr6_table *mrt;
+
+ mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
+ if (mrt == NULL)
+ return ERR_PTR(-ENOENT);
+
+ iter->mrt = mrt;
read_lock(&mrt_lock);
return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1)
@@ -161,15 +411,16 @@ static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct ipmr_vif_iter *iter = seq->private;
struct net *net = seq_file_net(seq);
+ struct mr6_table *mrt = iter->mrt;
++*pos;
if (v == SEQ_START_TOKEN)
return ip6mr_vif_seq_idx(net, iter, 0);
- while (++iter->ct < net->ipv6.maxvif) {
- if (!MIF_EXISTS(net, iter->ct))
+ while (++iter->ct < mrt->maxvif) {
+ if (!MIF_EXISTS(mrt, iter->ct))
continue;
- return &net->ipv6.vif6_table[iter->ct];
+ return &mrt->vif6_table[iter->ct];
}
return NULL;
}
@@ -182,7 +433,8 @@ static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
{
- struct net *net = seq_file_net(seq);
+ struct ipmr_vif_iter *iter = seq->private;
+ struct mr6_table *mrt = iter->mrt;
if (v == SEQ_START_TOKEN) {
seq_puts(seq,
@@ -193,7 +445,7 @@ static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
seq_printf(seq,
"%2td %-10s %8ld %7ld %8ld %7ld %05X\n",
- vif - net->ipv6.vif6_table,
+ vif - mrt->vif6_table,
name, vif->bytes_in, vif->pkt_in,
vif->bytes_out, vif->pkt_out,
vif->flags);
@@ -224,8 +476,15 @@ static const struct file_operations ip6mr_vif_fops = {
static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
{
+ struct ipmr_mfc_iter *it = seq->private;
struct net *net = seq_file_net(seq);
+ struct mr6_table *mrt;
+
+ mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
+ if (mrt == NULL)
+ return ERR_PTR(-ENOENT);
+ it->mrt = mrt;
return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
: SEQ_START_TOKEN;
}
@@ -235,35 +494,36 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
struct mfc6_cache *mfc = v;
struct ipmr_mfc_iter *it = seq->private;
struct net *net = seq_file_net(seq);
+ struct mr6_table *mrt = it->mrt;
++*pos;
if (v == SEQ_START_TOKEN)
return ipmr_mfc_seq_idx(net, seq->private, 0);
- if (mfc->next)
- return mfc->next;
+ if (mfc->list.next != it->cache)
+ return list_entry(mfc->list.next, struct mfc6_cache, list);
- if (it->cache == &mfc_unres_queue)
+ if (it->cache == &mrt->mfc6_unres_queue)
goto end_of_list;
- BUG_ON(it->cache != net->ipv6.mfc6_cache_array);
+ BUG_ON(it->cache != &mrt->mfc6_cache_array[it->ct]);
while (++it->ct < MFC6_LINES) {
- mfc = net->ipv6.mfc6_cache_array[it->ct];
- if (mfc)
- return mfc;
+ it->cache = &mrt->mfc6_cache_array[it->ct];
+ if (list_empty(it->cache))
+ continue;
+ return list_first_entry(it->cache, struct mfc6_cache, list);
}
/* exhausted cache_array, show unresolved */
read_unlock(&mrt_lock);
- it->cache = &mfc_unres_queue;
+ it->cache = &mrt->mfc6_unres_queue;
it->ct = 0;
spin_lock_bh(&mfc_unres_lock);
- mfc = mfc_unres_queue;
- if (mfc)
- return mfc;
+ if (!list_empty(it->cache))
+ return list_first_entry(it->cache, struct mfc6_cache, list);
end_of_list:
spin_unlock_bh(&mfc_unres_lock);
@@ -275,18 +535,17 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
{
struct ipmr_mfc_iter *it = seq->private;
- struct net *net = seq_file_net(seq);
+ struct mr6_table *mrt = it->mrt;
- if (it->cache == &mfc_unres_queue)
+ if (it->cache == &mrt->mfc6_unres_queue)
spin_unlock_bh(&mfc_unres_lock);
- else if (it->cache == net->ipv6.mfc6_cache_array)
+ else if (it->cache == mrt->mfc6_cache_array)
read_unlock(&mrt_lock);
}
static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
{
int n;
- struct net *net = seq_file_net(seq);
if (v == SEQ_START_TOKEN) {
seq_puts(seq,
@@ -296,19 +555,20 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
} else {
const struct mfc6_cache *mfc = v;
const struct ipmr_mfc_iter *it = seq->private;
+ struct mr6_table *mrt = it->mrt;
seq_printf(seq, "%pI6 %pI6 %-3hd",
&mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
mfc->mf6c_parent);
- if (it->cache != &mfc_unres_queue) {
+ if (it->cache != &mrt->mfc6_unres_queue) {
seq_printf(seq, " %8lu %8lu %8lu",
mfc->mfc_un.res.pkt,
mfc->mfc_un.res.bytes,
mfc->mfc_un.res.wrong_if);
for (n = mfc->mfc_un.res.minvif;
n < mfc->mfc_un.res.maxvif; n++) {
- if (MIF_EXISTS(net, n) &&
+ if (MIF_EXISTS(mrt, n) &&
mfc->mfc_un.res.ttls[n] < 255)
seq_printf(seq,
" %2d:%-3d",
@@ -355,7 +615,12 @@ static int pim6_rcv(struct sk_buff *skb)
struct ipv6hdr *encap;
struct net_device *reg_dev = NULL;
struct net *net = dev_net(skb->dev);
- int reg_vif_num = net->ipv6.mroute_reg_vif_num;
+ struct mr6_table *mrt;
+ struct flowi fl = {
+ .iif = skb->dev->ifindex,
+ .mark = skb->mark,
+ };
+ int reg_vif_num;
if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
goto drop;
@@ -378,9 +643,13 @@ static int pim6_rcv(struct sk_buff *skb)
ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
goto drop;
+ if (ip6mr_fib_lookup(net, &fl, &mrt) < 0)
+ goto drop;
+ reg_vif_num = mrt->mroute_reg_vif_num;
+
read_lock(&mrt_lock);
if (reg_vif_num >= 0)
- reg_dev = net->ipv6.vif6_table[reg_vif_num].dev;
+ reg_dev = mrt->vif6_table[reg_vif_num].dev;
if (reg_dev)
dev_hold(reg_dev);
read_unlock(&mrt_lock);
@@ -391,14 +660,12 @@ static int pim6_rcv(struct sk_buff *skb)
skb->mac_header = skb->network_header;
skb_pull(skb, (u8 *)encap - skb->data);
skb_reset_network_header(skb);
- skb->dev = reg_dev;
skb->protocol = htons(ETH_P_IPV6);
skb->ip_summed = 0;
skb->pkt_type = PACKET_HOST;
- skb_dst_drop(skb);
- reg_dev->stats.rx_bytes += skb->len;
- reg_dev->stats.rx_packets++;
- nf_reset(skb);
+
+ skb_tunnel_rx(skb, reg_dev);
+
netif_rx(skb);
dev_put(reg_dev);
return 0;
@@ -417,12 +684,22 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct net *net = dev_net(dev);
+ struct mr6_table *mrt;
+ struct flowi fl = {
+ .oif = dev->ifindex,
+ .iif = skb->skb_iif,
+ .mark = skb->mark,
+ };
+ int err;
+
+ err = ip6mr_fib_lookup(net, &fl, &mrt);
+ if (err < 0)
+ return err;
read_lock(&mrt_lock);
dev->stats.tx_bytes += skb->len;
dev->stats.tx_packets++;
- ip6mr_cache_report(net, skb, net->ipv6.mroute_reg_vif_num,
- MRT6MSG_WHOLEPKT);
+ ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
read_unlock(&mrt_lock);
kfree_skb(skb);
return NETDEV_TX_OK;
@@ -442,11 +719,17 @@ static void reg_vif_setup(struct net_device *dev)
dev->features |= NETIF_F_NETNS_LOCAL;
}
-static struct net_device *ip6mr_reg_vif(struct net *net)
+static struct net_device *ip6mr_reg_vif(struct net *net, struct mr6_table *mrt)
{
struct net_device *dev;
+ char name[IFNAMSIZ];
- dev = alloc_netdev(0, "pim6reg", reg_vif_setup);
+ if (mrt->id == RT6_TABLE_DFLT)
+ sprintf(name, "pim6reg");
+ else
+ sprintf(name, "pim6reg%u", mrt->id);
+
+ dev = alloc_netdev(0, name, reg_vif_setup);
if (dev == NULL)
return NULL;
@@ -478,15 +761,16 @@ failure:
* Delete a VIF entry
*/
-static int mif6_delete(struct net *net, int vifi, struct list_head *head)
+static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head)
{
struct mif_device *v;
struct net_device *dev;
struct inet6_dev *in6_dev;
- if (vifi < 0 || vifi >= net->ipv6.maxvif)
+
+ if (vifi < 0 || vifi >= mrt->maxvif)
return -EADDRNOTAVAIL;
- v = &net->ipv6.vif6_table[vifi];
+ v = &mrt->vif6_table[vifi];
write_lock_bh(&mrt_lock);
dev = v->dev;
@@ -498,17 +782,17 @@ static int mif6_delete(struct net *net, int vifi, struct list_head *head)
}
#ifdef CONFIG_IPV6_PIMSM_V2
- if (vifi == net->ipv6.mroute_reg_vif_num)
- net->ipv6.mroute_reg_vif_num = -1;
+ if (vifi == mrt->mroute_reg_vif_num)
+ mrt->mroute_reg_vif_num = -1;
#endif
- if (vifi + 1 == net->ipv6.maxvif) {
+ if (vifi + 1 == mrt->maxvif) {
int tmp;
for (tmp = vifi - 1; tmp >= 0; tmp--) {
- if (MIF_EXISTS(net, tmp))
+ if (MIF_EXISTS(mrt, tmp))
break;
}
- net->ipv6.maxvif = tmp + 1;
+ mrt->maxvif = tmp + 1;
}
write_unlock_bh(&mrt_lock);
@@ -528,7 +812,6 @@ static int mif6_delete(struct net *net, int vifi, struct list_head *head)
static inline void ip6mr_cache_free(struct mfc6_cache *c)
{
- release_net(mfc6_net(c));
kmem_cache_free(mrt_cachep, c);
}
@@ -536,12 +819,12 @@ static inline void ip6mr_cache_free(struct mfc6_cache *c)
and reporting error to netlink readers.
*/
-static void ip6mr_destroy_unres(struct mfc6_cache *c)
+static void ip6mr_destroy_unres(struct mr6_table *mrt, struct mfc6_cache *c)
{
+ struct net *net = read_pnet(&mrt->net);
struct sk_buff *skb;
- struct net *net = mfc6_net(c);
- atomic_dec(&net->ipv6.cache_resolve_queue_len);
+ atomic_dec(&mrt->cache_resolve_queue_len);
while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) {
if (ipv6_hdr(skb)->version == 0) {
@@ -559,60 +842,59 @@ static void ip6mr_destroy_unres(struct mfc6_cache *c)
}
-/* Single timer process for all the unresolved queue. */
+/* Timer process for all the unresolved queue. */
-static void ipmr_do_expire_process(unsigned long dummy)
+static void ipmr_do_expire_process(struct mr6_table *mrt)
{
unsigned long now = jiffies;
unsigned long expires = 10 * HZ;
- struct mfc6_cache *c, **cp;
-
- cp = &mfc_unres_queue;
+ struct mfc6_cache *c, *next;
- while ((c = *cp) != NULL) {
+ list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) {
if (time_after(c->mfc_un.unres.expires, now)) {
/* not yet... */
unsigned long interval = c->mfc_un.unres.expires - now;
if (interval < expires)
expires = interval;
- cp = &c->next;
continue;
}
- *cp = c->next;
- ip6mr_destroy_unres(c);
+ list_del(&c->list);
+ ip6mr_destroy_unres(mrt, c);
}
- if (mfc_unres_queue != NULL)
- mod_timer(&ipmr_expire_timer, jiffies + expires);
+ if (!list_empty(&mrt->mfc6_unres_queue))
+ mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
}
-static void ipmr_expire_process(unsigned long dummy)
+static void ipmr_expire_process(unsigned long arg)
{
+ struct mr6_table *mrt = (struct mr6_table *)arg;
+
if (!spin_trylock(&mfc_unres_lock)) {
- mod_timer(&ipmr_expire_timer, jiffies + 1);
+ mod_timer(&mrt->ipmr_expire_timer, jiffies + 1);
return;
}
- if (mfc_unres_queue != NULL)
- ipmr_do_expire_process(dummy);
+ if (!list_empty(&mrt->mfc6_unres_queue))
+ ipmr_do_expire_process(mrt);
spin_unlock(&mfc_unres_lock);
}
/* Fill oifs list. It is called under write locked mrt_lock. */
-static void ip6mr_update_thresholds(struct mfc6_cache *cache, unsigned char *ttls)
+static void ip6mr_update_thresholds(struct mr6_table *mrt, struct mfc6_cache *cache,
+ unsigned char *ttls)
{
int vifi;
- struct net *net = mfc6_net(cache);
cache->mfc_un.res.minvif = MAXMIFS;
cache->mfc_un.res.maxvif = 0;
memset(cache->mfc_un.res.ttls, 255, MAXMIFS);
- for (vifi = 0; vifi < net->ipv6.maxvif; vifi++) {
- if (MIF_EXISTS(net, vifi) &&
+ for (vifi = 0; vifi < mrt->maxvif; vifi++) {
+ if (MIF_EXISTS(mrt, vifi) &&
ttls[vifi] && ttls[vifi] < 255) {
cache->mfc_un.res.ttls[vifi] = ttls[vifi];
if (cache->mfc_un.res.minvif > vifi)
@@ -623,16 +905,17 @@ static void ip6mr_update_thresholds(struct mfc6_cache *cache, unsigned char *ttl
}
}
-static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock)
+static int mif6_add(struct net *net, struct mr6_table *mrt,
+ struct mif6ctl *vifc, int mrtsock)
{
int vifi = vifc->mif6c_mifi;
- struct mif_device *v = &net->ipv6.vif6_table[vifi];
+ struct mif_device *v = &mrt->vif6_table[vifi];
struct net_device *dev;
struct inet6_dev *in6_dev;
int err;
/* Is vif busy ? */
- if (MIF_EXISTS(net, vifi))
+ if (MIF_EXISTS(mrt, vifi))
return -EADDRINUSE;
switch (vifc->mif6c_flags) {
@@ -642,9 +925,9 @@ static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock)
* Special Purpose VIF in PIM
* All the packets will be sent to the daemon
*/
- if (net->ipv6.mroute_reg_vif_num >= 0)
+ if (mrt->mroute_reg_vif_num >= 0)
return -EADDRINUSE;
- dev = ip6mr_reg_vif(net);
+ dev = ip6mr_reg_vif(net, mrt);
if (!dev)
return -ENOBUFS;
err = dev_set_allmulti(dev, 1);
@@ -694,50 +977,48 @@ static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock)
v->dev = dev;
#ifdef CONFIG_IPV6_PIMSM_V2
if (v->flags & MIFF_REGISTER)
- net->ipv6.mroute_reg_vif_num = vifi;
+ mrt->mroute_reg_vif_num = vifi;
#endif
- if (vifi + 1 > net->ipv6.maxvif)
- net->ipv6.maxvif = vifi + 1;
+ if (vifi + 1 > mrt->maxvif)
+ mrt->maxvif = vifi + 1;
write_unlock_bh(&mrt_lock);
return 0;
}
-static struct mfc6_cache *ip6mr_cache_find(struct net *net,
+static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt,
struct in6_addr *origin,
struct in6_addr *mcastgrp)
{
int line = MFC6_HASH(mcastgrp, origin);
struct mfc6_cache *c;
- for (c = net->ipv6.mfc6_cache_array[line]; c; c = c->next) {
+ list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
if (ipv6_addr_equal(&c->mf6c_origin, origin) &&
ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp))
- break;
+ return c;
}
- return c;
+ return NULL;
}
/*
* Allocate a multicast cache entry
*/
-static struct mfc6_cache *ip6mr_cache_alloc(struct net *net)
+static struct mfc6_cache *ip6mr_cache_alloc(void)
{
struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
if (c == NULL)
return NULL;
c->mfc_un.res.minvif = MAXMIFS;
- mfc6_net_set(c, net);
return c;
}
-static struct mfc6_cache *ip6mr_cache_alloc_unres(struct net *net)
+static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
{
struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
if (c == NULL)
return NULL;
skb_queue_head_init(&c->mfc_un.unres.unresolved);
c->mfc_un.unres.expires = jiffies + 10 * HZ;
- mfc6_net_set(c, net);
return c;
}
@@ -745,7 +1026,8 @@ static struct mfc6_cache *ip6mr_cache_alloc_unres(struct net *net)
* A cache entry has gone into a resolved state from queued
*/
-static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c)
+static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt,
+ struct mfc6_cache *uc, struct mfc6_cache *c)
{
struct sk_buff *skb;
@@ -758,7 +1040,7 @@ static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c)
int err;
struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
- if (ip6mr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) {
+ if (__ip6mr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) {
nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
} else {
nlh->nlmsg_type = NLMSG_ERROR;
@@ -766,9 +1048,9 @@ static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c)
skb_trim(skb, nlh->nlmsg_len);
((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE;
}
- err = rtnl_unicast(skb, mfc6_net(uc), NETLINK_CB(skb).pid);
+ err = rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
} else
- ip6_mr_forward(skb, c);
+ ip6_mr_forward(net, mrt, skb, c);
}
}
@@ -779,8 +1061,8 @@ static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c)
* Called under mrt_lock.
*/
-static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
- int assert)
+static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
+ mifi_t mifi, int assert)
{
struct sk_buff *skb;
struct mrt6msg *msg;
@@ -816,7 +1098,7 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
msg = (struct mrt6msg *)skb_transport_header(skb);
msg->im6_mbz = 0;
msg->im6_msgtype = MRT6MSG_WHOLEPKT;
- msg->im6_mif = net->ipv6.mroute_reg_vif_num;
+ msg->im6_mif = mrt->mroute_reg_vif_num;
msg->im6_pad = 0;
ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr);
ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr);
@@ -851,7 +1133,7 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
- if (net->ipv6.mroute6_sk == NULL) {
+ if (mrt->mroute6_sk == NULL) {
kfree_skb(skb);
return -EINVAL;
}
@@ -859,7 +1141,7 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
/*
* Deliver to user space multicast routing algorithms
*/
- ret = sock_queue_rcv_skb(net->ipv6.mroute6_sk, skb);
+ ret = sock_queue_rcv_skb(mrt->mroute6_sk, skb);
if (ret < 0) {
if (net_ratelimit())
printk(KERN_WARNING "mroute6: pending queue full, dropping entries.\n");
@@ -874,26 +1156,28 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
*/
static int
-ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb)
+ip6mr_cache_unresolved(struct mr6_table *mrt, mifi_t mifi, struct sk_buff *skb)
{
+ bool found = false;
int err;
struct mfc6_cache *c;
spin_lock_bh(&mfc_unres_lock);
- for (c = mfc_unres_queue; c; c = c->next) {
- if (net_eq(mfc6_net(c), net) &&
- ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
- ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr))
+ list_for_each_entry(c, &mrt->mfc6_unres_queue, list) {
+ if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
+ ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) {
+ found = true;
break;
+ }
}
- if (c == NULL) {
+ if (!found) {
/*
* Create a new entry if allowable
*/
- if (atomic_read(&net->ipv6.cache_resolve_queue_len) >= 10 ||
- (c = ip6mr_cache_alloc_unres(net)) == NULL) {
+ if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
+ (c = ip6mr_cache_alloc_unres()) == NULL) {
spin_unlock_bh(&mfc_unres_lock);
kfree_skb(skb);
@@ -910,7 +1194,7 @@ ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb)
/*
* Reflect first query at pim6sd
*/
- err = ip6mr_cache_report(net, skb, mifi, MRT6MSG_NOCACHE);
+ err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE);
if (err < 0) {
/* If the report failed throw the cache entry
out - Brad Parker
@@ -922,11 +1206,10 @@ ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb)
return err;
}
- atomic_inc(&net->ipv6.cache_resolve_queue_len);
- c->next = mfc_unres_queue;
- mfc_unres_queue = c;
+ atomic_inc(&mrt->cache_resolve_queue_len);
+ list_add(&c->list, &mrt->mfc6_unres_queue);
- ipmr_do_expire_process(1);
+ ipmr_do_expire_process(mrt);
}
/*
@@ -948,19 +1231,18 @@ ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb)
* MFC6 cache manipulation by user space
*/
-static int ip6mr_mfc_delete(struct net *net, struct mf6cctl *mfc)
+static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc)
{
int line;
- struct mfc6_cache *c, **cp;
+ struct mfc6_cache *c, *next;
line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
- for (cp = &net->ipv6.mfc6_cache_array[line];
- (c = *cp) != NULL; cp = &c->next) {
+ list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) {
if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) {
write_lock_bh(&mrt_lock);
- *cp = c->next;
+ list_del(&c->list);
write_unlock_bh(&mrt_lock);
ip6mr_cache_free(c);
@@ -975,6 +1257,7 @@ static int ip6mr_device_event(struct notifier_block *this,
{
struct net_device *dev = ptr;
struct net *net = dev_net(dev);
+ struct mr6_table *mrt;
struct mif_device *v;
int ct;
LIST_HEAD(list);
@@ -982,10 +1265,12 @@ static int ip6mr_device_event(struct notifier_block *this,
if (event != NETDEV_UNREGISTER)
return NOTIFY_DONE;
- v = &net->ipv6.vif6_table[0];
- for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) {
- if (v->dev == dev)
- mif6_delete(net, ct, &list);
+ ip6mr_for_each_table(mrt, net) {
+ v = &mrt->vif6_table[0];
+ for (ct = 0; ct < mrt->maxvif; ct++, v++) {
+ if (v->dev == dev)
+ mif6_delete(mrt, ct, &list);
+ }
}
unregister_netdevice_many(&list);
@@ -1002,26 +1287,11 @@ static struct notifier_block ip6_mr_notifier = {
static int __net_init ip6mr_net_init(struct net *net)
{
- int err = 0;
- net->ipv6.vif6_table = kcalloc(MAXMIFS, sizeof(struct mif_device),
- GFP_KERNEL);
- if (!net->ipv6.vif6_table) {
- err = -ENOMEM;
- goto fail;
- }
-
- /* Forwarding cache */
- net->ipv6.mfc6_cache_array = kcalloc(MFC6_LINES,
- sizeof(struct mfc6_cache *),
- GFP_KERNEL);
- if (!net->ipv6.mfc6_cache_array) {
- err = -ENOMEM;
- goto fail_mfc6_cache;
- }
+ int err;
-#ifdef CONFIG_IPV6_PIMSM_V2
- net->ipv6.mroute_reg_vif_num = -1;
-#endif
+ err = ip6mr_rules_init(net);
+ if (err < 0)
+ goto fail;
#ifdef CONFIG_PROC_FS
err = -ENOMEM;
@@ -1030,16 +1300,15 @@ static int __net_init ip6mr_net_init(struct net *net)
if (!proc_net_fops_create(net, "ip6_mr_cache", 0, &ip6mr_mfc_fops))
goto proc_cache_fail;
#endif
+
return 0;
#ifdef CONFIG_PROC_FS
proc_cache_fail:
proc_net_remove(net, "ip6_mr_vif");
proc_vif_fail:
- kfree(net->ipv6.mfc6_cache_array);
+ ip6mr_rules_exit(net);
#endif
-fail_mfc6_cache:
- kfree(net->ipv6.vif6_table);
fail:
return err;
}
@@ -1050,9 +1319,7 @@ static void __net_exit ip6mr_net_exit(struct net *net)
proc_net_remove(net, "ip6_mr_cache");
proc_net_remove(net, "ip6_mr_vif");
#endif
- mroute_clean_tables(net);
- kfree(net->ipv6.mfc6_cache_array);
- kfree(net->ipv6.vif6_table);
+ ip6mr_rules_exit(net);
}
static struct pernet_operations ip6mr_net_ops = {
@@ -1075,7 +1342,6 @@ int __init ip6_mr_init(void)
if (err)
goto reg_pernet_fail;
- setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
err = register_netdevice_notifier(&ip6_mr_notifier);
if (err)
goto reg_notif_fail;
@@ -1086,13 +1352,13 @@ int __init ip6_mr_init(void)
goto add_proto_fail;
}
#endif
+ rtnl_register(RTNL_FAMILY_IP6MR, RTM_GETROUTE, NULL, ip6mr_rtm_dumproute);
return 0;
#ifdef CONFIG_IPV6_PIMSM_V2
add_proto_fail:
unregister_netdevice_notifier(&ip6_mr_notifier);
#endif
reg_notif_fail:
- del_timer(&ipmr_expire_timer);
unregister_pernet_subsys(&ip6mr_net_ops);
reg_pernet_fail:
kmem_cache_destroy(mrt_cachep);
@@ -1102,15 +1368,16 @@ reg_pernet_fail:
void ip6_mr_cleanup(void)
{
unregister_netdevice_notifier(&ip6_mr_notifier);
- del_timer(&ipmr_expire_timer);
unregister_pernet_subsys(&ip6mr_net_ops);
kmem_cache_destroy(mrt_cachep);
}
-static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock)
+static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
+ struct mf6cctl *mfc, int mrtsock)
{
+ bool found = false;
int line;
- struct mfc6_cache *uc, *c, **cp;
+ struct mfc6_cache *uc, *c;
unsigned char ttls[MAXMIFS];
int i;
@@ -1126,17 +1393,18 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock)
line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
- for (cp = &net->ipv6.mfc6_cache_array[line];
- (c = *cp) != NULL; cp = &c->next) {
+ list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
- ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr))
+ ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) {
+ found = true;
break;
+ }
}
- if (c != NULL) {
+ if (found) {
write_lock_bh(&mrt_lock);
c->mf6c_parent = mfc->mf6cc_parent;
- ip6mr_update_thresholds(c, ttls);
+ ip6mr_update_thresholds(mrt, c, ttls);
if (!mrtsock)
c->mfc_flags |= MFC_STATIC;
write_unlock_bh(&mrt_lock);
@@ -1146,43 +1414,42 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock)
if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
return -EINVAL;
- c = ip6mr_cache_alloc(net);
+ c = ip6mr_cache_alloc();
if (c == NULL)
return -ENOMEM;
c->mf6c_origin = mfc->mf6cc_origin.sin6_addr;
c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr;
c->mf6c_parent = mfc->mf6cc_parent;
- ip6mr_update_thresholds(c, ttls);
+ ip6mr_update_thresholds(mrt, c, ttls);
if (!mrtsock)
c->mfc_flags |= MFC_STATIC;
write_lock_bh(&mrt_lock);
- c->next = net->ipv6.mfc6_cache_array[line];
- net->ipv6.mfc6_cache_array[line] = c;
+ list_add(&c->list, &mrt->mfc6_cache_array[line]);
write_unlock_bh(&mrt_lock);
/*
* Check to see if we resolved a queued list. If so we
* need to send on the frames and tidy up.
*/
+ found = false;
spin_lock_bh(&mfc_unres_lock);
- for (cp = &mfc_unres_queue; (uc = *cp) != NULL;
- cp = &uc->next) {
- if (net_eq(mfc6_net(uc), net) &&
- ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
+ list_for_each_entry(uc, &mrt->mfc6_unres_queue, list) {
+ if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
- *cp = uc->next;
- atomic_dec(&net->ipv6.cache_resolve_queue_len);
+ list_del(&uc->list);
+ atomic_dec(&mrt->cache_resolve_queue_len);
+ found = true;
break;
}
}
- if (mfc_unres_queue == NULL)
- del_timer(&ipmr_expire_timer);
+ if (list_empty(&mrt->mfc6_unres_queue))
+ del_timer(&mrt->ipmr_expire_timer);
spin_unlock_bh(&mfc_unres_lock);
- if (uc) {
- ip6mr_cache_resolve(uc, c);
+ if (found) {
+ ip6mr_cache_resolve(net, mrt, uc, c);
ip6mr_cache_free(uc);
}
return 0;
@@ -1192,17 +1459,18 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock)
* Close the multicast socket, and clear the vif tables etc
*/
-static void mroute_clean_tables(struct net *net)
+static void mroute_clean_tables(struct mr6_table *mrt)
{
int i;
LIST_HEAD(list);
+ struct mfc6_cache *c, *next;
/*
* Shut down all active vif entries
*/
- for (i = 0; i < net->ipv6.maxvif; i++) {
- if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC))
- mif6_delete(net, i, &list);
+ for (i = 0; i < mrt->maxvif; i++) {
+ if (!(mrt->vif6_table[i].flags & VIFF_STATIC))
+ mif6_delete(mrt, i, &list);
}
unregister_netdevice_many(&list);
@@ -1210,48 +1478,36 @@ static void mroute_clean_tables(struct net *net)
* Wipe the cache
*/
for (i = 0; i < MFC6_LINES; i++) {
- struct mfc6_cache *c, **cp;
-
- cp = &net->ipv6.mfc6_cache_array[i];
- while ((c = *cp) != NULL) {
- if (c->mfc_flags & MFC_STATIC) {
- cp = &c->next;
+ list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) {
+ if (c->mfc_flags & MFC_STATIC)
continue;
- }
write_lock_bh(&mrt_lock);
- *cp = c->next;
+ list_del(&c->list);
write_unlock_bh(&mrt_lock);
ip6mr_cache_free(c);
}
}
- if (atomic_read(&net->ipv6.cache_resolve_queue_len) != 0) {
- struct mfc6_cache *c, **cp;
-
+ if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
spin_lock_bh(&mfc_unres_lock);
- cp = &mfc_unres_queue;
- while ((c = *cp) != NULL) {
- if (!net_eq(mfc6_net(c), net)) {
- cp = &c->next;
- continue;
- }
- *cp = c->next;
- ip6mr_destroy_unres(c);
+ list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) {
+ list_del(&c->list);
+ ip6mr_destroy_unres(mrt, c);
}
spin_unlock_bh(&mfc_unres_lock);
}
}
-static int ip6mr_sk_init(struct sock *sk)
+static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk)
{
int err = 0;
struct net *net = sock_net(sk);
rtnl_lock();
write_lock_bh(&mrt_lock);
- if (likely(net->ipv6.mroute6_sk == NULL)) {
- net->ipv6.mroute6_sk = sk;
+ if (likely(mrt->mroute6_sk == NULL)) {
+ mrt->mroute6_sk = sk;
net->ipv6.devconf_all->mc_forwarding++;
}
else
@@ -1265,24 +1521,43 @@ static int ip6mr_sk_init(struct sock *sk)
int ip6mr_sk_done(struct sock *sk)
{
- int err = 0;
+ int err = -EACCES;
struct net *net = sock_net(sk);
+ struct mr6_table *mrt;
rtnl_lock();
- if (sk == net->ipv6.mroute6_sk) {
- write_lock_bh(&mrt_lock);
- net->ipv6.mroute6_sk = NULL;
- net->ipv6.devconf_all->mc_forwarding--;
- write_unlock_bh(&mrt_lock);
+ ip6mr_for_each_table(mrt, net) {
+ if (sk == mrt->mroute6_sk) {
+ write_lock_bh(&mrt_lock);
+ mrt->mroute6_sk = NULL;
+ net->ipv6.devconf_all->mc_forwarding--;
+ write_unlock_bh(&mrt_lock);
- mroute_clean_tables(net);
- } else
- err = -EACCES;
+ mroute_clean_tables(mrt);
+ err = 0;
+ break;
+ }
+ }
rtnl_unlock();
return err;
}
+struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
+{
+ struct mr6_table *mrt;
+ struct flowi fl = {
+ .iif = skb->skb_iif,
+ .oif = skb->dev->ifindex,
+ .mark = skb->mark,
+ };
+
+ if (ip6mr_fib_lookup(net, &fl, &mrt) < 0)
+ return NULL;
+
+ return mrt->mroute6_sk;
+}
+
/*
* Socket options and virtual interface manipulation. The whole
* virtual interface system is a complete heap, but unfortunately
@@ -1297,9 +1572,14 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
struct mf6cctl mfc;
mifi_t mifi;
struct net *net = sock_net(sk);
+ struct mr6_table *mrt;
+
+ mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
+ if (mrt == NULL)
+ return -ENOENT;
if (optname != MRT6_INIT) {
- if (sk != net->ipv6.mroute6_sk && !capable(CAP_NET_ADMIN))
+ if (sk != mrt->mroute6_sk && !capable(CAP_NET_ADMIN))
return -EACCES;
}
@@ -1311,7 +1591,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
if (optlen < sizeof(int))
return -EINVAL;
- return ip6mr_sk_init(sk);
+ return ip6mr_sk_init(mrt, sk);
case MRT6_DONE:
return ip6mr_sk_done(sk);
@@ -1324,7 +1604,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
if (vif.mif6c_mifi >= MAXMIFS)
return -ENFILE;
rtnl_lock();
- ret = mif6_add(net, &vif, sk == net->ipv6.mroute6_sk);
+ ret = mif6_add(net, mrt, &vif, sk == mrt->mroute6_sk);
rtnl_unlock();
return ret;
@@ -1334,7 +1614,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
return -EFAULT;
rtnl_lock();
- ret = mif6_delete(net, mifi, NULL);
+ ret = mif6_delete(mrt, mifi, NULL);
rtnl_unlock();
return ret;
@@ -1350,10 +1630,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
return -EFAULT;
rtnl_lock();
if (optname == MRT6_DEL_MFC)
- ret = ip6mr_mfc_delete(net, &mfc);
+ ret = ip6mr_mfc_delete(mrt, &mfc);
else
- ret = ip6mr_mfc_add(net, &mfc,
- sk == net->ipv6.mroute6_sk);
+ ret = ip6mr_mfc_add(net, mrt, &mfc, sk == mrt->mroute6_sk);
rtnl_unlock();
return ret;
@@ -1365,7 +1644,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
int v;
if (get_user(v, (int __user *)optval))
return -EFAULT;
- net->ipv6.mroute_do_assert = !!v;
+ mrt->mroute_do_assert = !!v;
return 0;
}
@@ -1378,15 +1657,36 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
v = !!v;
rtnl_lock();
ret = 0;
- if (v != net->ipv6.mroute_do_pim) {
- net->ipv6.mroute_do_pim = v;
- net->ipv6.mroute_do_assert = v;
+ if (v != mrt->mroute_do_pim) {
+ mrt->mroute_do_pim = v;
+ mrt->mroute_do_assert = v;
}
rtnl_unlock();
return ret;
}
#endif
+#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
+ case MRT6_TABLE:
+ {
+ u32 v;
+
+ if (optlen != sizeof(u32))
+ return -EINVAL;
+ if (get_user(v, (u32 __user *)optval))
+ return -EFAULT;
+ if (sk == mrt->mroute6_sk)
+ return -EBUSY;
+
+ rtnl_lock();
+ ret = 0;
+ if (!ip6mr_new_table(net, v))
+ ret = -ENOMEM;
+ raw6_sk(sk)->ip6mr_table = v;
+ rtnl_unlock();
+ return ret;
+ }
+#endif
/*
* Spurious command, or MRT6_VERSION which you cannot
* set.
@@ -1406,6 +1706,11 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
int olr;
int val;
struct net *net = sock_net(sk);
+ struct mr6_table *mrt;
+
+ mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
+ if (mrt == NULL)
+ return -ENOENT;
switch (optname) {
case MRT6_VERSION:
@@ -1413,11 +1718,11 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
break;
#ifdef CONFIG_IPV6_PIMSM_V2
case MRT6_PIM:
- val = net->ipv6.mroute_do_pim;
+ val = mrt->mroute_do_pim;
break;
#endif
case MRT6_ASSERT:
- val = net->ipv6.mroute_do_assert;
+ val = mrt->mroute_do_assert;
break;
default:
return -ENOPROTOOPT;
@@ -1448,16 +1753,21 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
struct mif_device *vif;
struct mfc6_cache *c;
struct net *net = sock_net(sk);
+ struct mr6_table *mrt;
+
+ mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
+ if (mrt == NULL)
+ return -ENOENT;
switch (cmd) {
case SIOCGETMIFCNT_IN6:
if (copy_from_user(&vr, arg, sizeof(vr)))
return -EFAULT;
- if (vr.mifi >= net->ipv6.maxvif)
+ if (vr.mifi >= mrt->maxvif)
return -EINVAL;
read_lock(&mrt_lock);
- vif = &net->ipv6.vif6_table[vr.mifi];
- if (MIF_EXISTS(net, vr.mifi)) {
+ vif = &mrt->vif6_table[vr.mifi];
+ if (MIF_EXISTS(mrt, vr.mifi)) {
vr.icount = vif->pkt_in;
vr.ocount = vif->pkt_out;
vr.ibytes = vif->bytes_in;
@@ -1475,7 +1785,7 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
return -EFAULT;
read_lock(&mrt_lock);
- c = ip6mr_cache_find(net, &sr.src.sin6_addr, &sr.grp.sin6_addr);
+ c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
if (c) {
sr.pktcnt = c->mfc_un.res.pkt;
sr.bytecnt = c->mfc_un.res.bytes;
@@ -1505,11 +1815,11 @@ static inline int ip6mr_forward2_finish(struct sk_buff *skb)
* Processing handlers for ip6mr_forward
*/
-static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
+static int ip6mr_forward2(struct net *net, struct mr6_table *mrt,
+ struct sk_buff *skb, struct mfc6_cache *c, int vifi)
{
struct ipv6hdr *ipv6h;
- struct net *net = mfc6_net(c);
- struct mif_device *vif = &net->ipv6.vif6_table[vifi];
+ struct mif_device *vif = &mrt->vif6_table[vifi];
struct net_device *dev;
struct dst_entry *dst;
struct flowi fl;
@@ -1523,7 +1833,7 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
vif->bytes_out += skb->len;
vif->dev->stats.tx_bytes += skb->len;
vif->dev->stats.tx_packets++;
- ip6mr_cache_report(net, skb, vifi, MRT6MSG_WHOLEPKT);
+ ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
goto out_free;
}
#endif
@@ -1570,7 +1880,7 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
IP6CB(skb)->flags |= IP6SKB_FORWARDED;
- return NF_HOOK(PF_INET6, NF_INET_FORWARD, skb, skb->dev, dev,
+ return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dev,
ip6mr_forward2_finish);
out_free:
@@ -1578,22 +1888,22 @@ out_free:
return 0;
}
-static int ip6mr_find_vif(struct net_device *dev)
+static int ip6mr_find_vif(struct mr6_table *mrt, struct net_device *dev)
{
- struct net *net = dev_net(dev);
int ct;
- for (ct = net->ipv6.maxvif - 1; ct >= 0; ct--) {
- if (net->ipv6.vif6_table[ct].dev == dev)
+
+ for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
+ if (mrt->vif6_table[ct].dev == dev)
break;
}
return ct;
}
-static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache)
+static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
+ struct sk_buff *skb, struct mfc6_cache *cache)
{
int psend = -1;
int vif, ct;
- struct net *net = mfc6_net(cache);
vif = cache->mf6c_parent;
cache->mfc_un.res.pkt++;
@@ -1602,30 +1912,30 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache)
/*
* Wrong interface: drop packet and (maybe) send PIM assert.
*/
- if (net->ipv6.vif6_table[vif].dev != skb->dev) {
+ if (mrt->vif6_table[vif].dev != skb->dev) {
int true_vifi;
cache->mfc_un.res.wrong_if++;
- true_vifi = ip6mr_find_vif(skb->dev);
+ true_vifi = ip6mr_find_vif(mrt, skb->dev);
- if (true_vifi >= 0 && net->ipv6.mroute_do_assert &&
+ if (true_vifi >= 0 && mrt->mroute_do_assert &&
/* pimsm uses asserts, when switching from RPT to SPT,
so that we cannot check that packet arrived on an oif.
It is bad, but otherwise we would need to move pretty
large chunk of pimd to kernel. Ough... --ANK
*/
- (net->ipv6.mroute_do_pim ||
+ (mrt->mroute_do_pim ||
cache->mfc_un.res.ttls[true_vifi] < 255) &&
time_after(jiffies,
cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
cache->mfc_un.res.last_assert = jiffies;
- ip6mr_cache_report(net, skb, true_vifi, MRT6MSG_WRONGMIF);
+ ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
}
goto dont_forward;
}
- net->ipv6.vif6_table[vif].pkt_in++;
- net->ipv6.vif6_table[vif].bytes_in += skb->len;
+ mrt->vif6_table[vif].pkt_in++;
+ mrt->vif6_table[vif].bytes_in += skb->len;
/*
* Forward the frame
@@ -1635,13 +1945,13 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache)
if (psend != -1) {
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2)
- ip6mr_forward2(skb2, cache, psend);
+ ip6mr_forward2(net, mrt, skb2, cache, psend);
}
psend = ct;
}
}
if (psend != -1) {
- ip6mr_forward2(skb, cache, psend);
+ ip6mr_forward2(net, mrt, skb, cache, psend);
return 0;
}
@@ -1659,9 +1969,19 @@ int ip6_mr_input(struct sk_buff *skb)
{
struct mfc6_cache *cache;
struct net *net = dev_net(skb->dev);
+ struct mr6_table *mrt;
+ struct flowi fl = {
+ .iif = skb->dev->ifindex,
+ .mark = skb->mark,
+ };
+ int err;
+
+ err = ip6mr_fib_lookup(net, &fl, &mrt);
+ if (err < 0)
+ return err;
read_lock(&mrt_lock);
- cache = ip6mr_cache_find(net,
+ cache = ip6mr_cache_find(mrt,
&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
/*
@@ -1670,9 +1990,9 @@ int ip6_mr_input(struct sk_buff *skb)
if (cache == NULL) {
int vif;
- vif = ip6mr_find_vif(skb->dev);
+ vif = ip6mr_find_vif(mrt, skb->dev);
if (vif >= 0) {
- int err = ip6mr_cache_unresolved(net, vif, skb);
+ int err = ip6mr_cache_unresolved(mrt, vif, skb);
read_unlock(&mrt_lock);
return err;
@@ -1682,7 +2002,7 @@ int ip6_mr_input(struct sk_buff *skb)
return -ENODEV;
}
- ip6_mr_forward(skb, cache);
+ ip6_mr_forward(net, mrt, skb, cache);
read_unlock(&mrt_lock);
@@ -1690,32 +2010,31 @@ int ip6_mr_input(struct sk_buff *skb)
}
-static int
-ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm)
+static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
+ struct mfc6_cache *c, struct rtmsg *rtm)
{
int ct;
struct rtnexthop *nhp;
- struct net *net = mfc6_net(c);
u8 *b = skb_tail_pointer(skb);
struct rtattr *mp_head;
/* If cache is unresolved, don't try to parse IIF and OIF */
- if (c->mf6c_parent > MAXMIFS)
+ if (c->mf6c_parent >= MAXMIFS)
return -ENOENT;
- if (MIF_EXISTS(net, c->mf6c_parent))
- RTA_PUT(skb, RTA_IIF, 4, &net->ipv6.vif6_table[c->mf6c_parent].dev->ifindex);
+ if (MIF_EXISTS(mrt, c->mf6c_parent))
+ RTA_PUT(skb, RTA_IIF, 4, &mrt->vif6_table[c->mf6c_parent].dev->ifindex);
mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
- if (MIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) {
+ if (MIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
goto rtattr_failure;
nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
nhp->rtnh_flags = 0;
nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
- nhp->rtnh_ifindex = net->ipv6.vif6_table[ct].dev->ifindex;
+ nhp->rtnh_ifindex = mrt->vif6_table[ct].dev->ifindex;
nhp->rtnh_len = sizeof(*nhp);
}
}
@@ -1733,11 +2052,16 @@ int ip6mr_get_route(struct net *net,
struct sk_buff *skb, struct rtmsg *rtm, int nowait)
{
int err;
+ struct mr6_table *mrt;
struct mfc6_cache *cache;
struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
+ mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
+ if (mrt == NULL)
+ return -ENOENT;
+
read_lock(&mrt_lock);
- cache = ip6mr_cache_find(net, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
+ cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
if (!cache) {
struct sk_buff *skb2;
@@ -1751,7 +2075,7 @@ int ip6mr_get_route(struct net *net,
}
dev = skb->dev;
- if (dev == NULL || (vif = ip6mr_find_vif(dev)) < 0) {
+ if (dev == NULL || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
read_unlock(&mrt_lock);
return -ENODEV;
}
@@ -1780,7 +2104,7 @@ int ip6mr_get_route(struct net *net,
ipv6_addr_copy(&iph->saddr, &rt->rt6i_src.addr);
ipv6_addr_copy(&iph->daddr, &rt->rt6i_dst.addr);
- err = ip6mr_cache_unresolved(net, vif, skb2);
+ err = ip6mr_cache_unresolved(mrt, vif, skb2);
read_unlock(&mrt_lock);
return err;
@@ -1789,8 +2113,88 @@ int ip6mr_get_route(struct net *net,
if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
cache->mfc_flags |= MFC_NOTIFY;
- err = ip6mr_fill_mroute(skb, cache, rtm);
+ err = __ip6mr_fill_mroute(mrt, skb, cache, rtm);
read_unlock(&mrt_lock);
return err;
}
+static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
+ u32 pid, u32 seq, struct mfc6_cache *c)
+{
+ struct nlmsghdr *nlh;
+ struct rtmsg *rtm;
+
+ nlh = nlmsg_put(skb, pid, seq, RTM_NEWROUTE, sizeof(*rtm), NLM_F_MULTI);
+ if (nlh == NULL)
+ return -EMSGSIZE;
+
+ rtm = nlmsg_data(nlh);
+ rtm->rtm_family = RTNL_FAMILY_IPMR;
+ rtm->rtm_dst_len = 128;
+ rtm->rtm_src_len = 128;
+ rtm->rtm_tos = 0;
+ rtm->rtm_table = mrt->id;
+ NLA_PUT_U32(skb, RTA_TABLE, mrt->id);
+ rtm->rtm_scope = RT_SCOPE_UNIVERSE;
+ rtm->rtm_protocol = RTPROT_UNSPEC;
+ rtm->rtm_flags = 0;
+
+ NLA_PUT(skb, RTA_SRC, 16, &c->mf6c_origin);
+ NLA_PUT(skb, RTA_DST, 16, &c->mf6c_mcastgrp);
+
+ if (__ip6mr_fill_mroute(mrt, skb, c, rtm) < 0)
+ goto nla_put_failure;
+
+ return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+}
+
+static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct net *net = sock_net(skb->sk);
+ struct mr6_table *mrt;
+ struct mfc6_cache *mfc;
+ unsigned int t = 0, s_t;
+ unsigned int h = 0, s_h;
+ unsigned int e = 0, s_e;
+
+ s_t = cb->args[0];
+ s_h = cb->args[1];
+ s_e = cb->args[2];
+
+ read_lock(&mrt_lock);
+ ip6mr_for_each_table(mrt, net) {
+ if (t < s_t)
+ goto next_table;
+ if (t > s_t)
+ s_h = 0;
+ for (h = s_h; h < MFC6_LINES; h++) {
+ list_for_each_entry(mfc, &mrt->mfc6_cache_array[h], list) {
+ if (e < s_e)
+ goto next_entry;
+ if (ip6mr_fill_mroute(mrt, skb,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq,
+ mfc) < 0)
+ goto done;
+next_entry:
+ e++;
+ }
+ e = s_e = 0;
+ }
+ s_h = 0;
+next_table:
+ t++;
+ }
+done:
+ read_unlock(&mrt_lock);
+
+ cb->args[2] = e;
+ cb->args[1] = h;
+ cb->args[0] = t;
+
+ return skb->len;
+}
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 006aee6..ab1622d 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1356,7 +1356,10 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
IPV6_TLV_PADN, 0 };
/* we assume size > sizeof(ra) here */
- skb = sock_alloc_send_skb(sk, size + LL_ALLOCATED_SPACE(dev), 1, &err);
+ size += LL_ALLOCATED_SPACE(dev);
+ /* limit our allocations to order-0 page */
+ size = min_t(int, size, SKB_MAX_ORDER(0, 0));
+ skb = sock_alloc_send_skb(sk, size, 1, &err);
if (!skb)
return NULL;
@@ -1428,7 +1431,7 @@ static void mld_sendpack(struct sk_buff *skb)
payload_len = skb->len;
- err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
+ err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
dst_output);
out:
if (!err) {
@@ -1793,7 +1796,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
goto err_out;
skb_dst_set(skb, dst);
- err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
+ err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
dst_output);
out:
if (!err) {
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index da0a4d2..0abdc24 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -536,7 +536,7 @@ void ndisc_send_skb(struct sk_buff *skb,
idev = in6_dev_get(dst->dev);
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
- err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
+ err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
dst_output);
if (!err) {
ICMP6MSGOUT_INC_STATS(net, idev, type);
@@ -890,8 +890,6 @@ out:
in6_ifa_put(ifp);
else
in6_dev_put(idev);
-
- return;
}
static void ndisc_recv_na(struct sk_buff *skb)
@@ -1618,7 +1616,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
skb_dst_set(buff, dst);
idev = in6_dev_get(dst->dev);
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
- err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
+ err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
dst_output);
if (!err) {
ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT);
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index d5ed92b..a74951c 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -25,20 +25,6 @@ int ip6_route_me_harder(struct sk_buff *skb)
};
dst = ip6_route_output(net, skb->sk, &fl);
-
-#ifdef CONFIG_XFRM
- if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
- xfrm_decode_session(skb, &fl, AF_INET6) == 0) {
- struct dst_entry *dst2 = skb_dst(skb);
-
- if (xfrm_lookup(net, &dst2, &fl, skb->sk, 0)) {
- skb_dst_set(skb, NULL);
- return -1;
- }
- skb_dst_set(skb, dst2);
- }
-#endif
-
if (dst->error) {
IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
@@ -50,6 +36,17 @@ int ip6_route_me_harder(struct sk_buff *skb)
skb_dst_drop(skb);
skb_dst_set(skb, dst);
+
+#ifdef CONFIG_XFRM
+ if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
+ xfrm_decode_session(skb, &fl, AF_INET6) == 0) {
+ skb_dst_set(skb, NULL);
+ if (xfrm_lookup(net, &dst, &fl, skb->sk, 0))
+ return -1;
+ skb_dst_set(skb, dst);
+ }
+#endif
+
return 0;
}
EXPORT_SYMBOL(ip6_route_me_harder);
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 6a68a74..8c20174 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -162,8 +162,7 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
break;
case IPQ_COPY_PACKET:
- if ((entry->skb->ip_summed == CHECKSUM_PARTIAL ||
- entry->skb->ip_summed == CHECKSUM_COMPLETE) &&
+ if (entry->skb->ip_summed == CHECKSUM_PARTIAL &&
(*errp = skb_checksum_help(entry->skb))) {
read_unlock_bh(&queue_lock);
return NULL;
@@ -463,7 +462,6 @@ __ipq_rcv_skb(struct sk_buff *skb)
if (flags & NLM_F_ACK)
netlink_ack(skb, nlh, 0);
- return;
}
static void
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 9210e31..9d2d68f 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -40,24 +40,19 @@ MODULE_DESCRIPTION("IPv6 packet filter");
/*#define DEBUG_IP_FIREWALL_USER*/
#ifdef DEBUG_IP_FIREWALL
-#define dprintf(format, args...) printk(format , ## args)
+#define dprintf(format, args...) pr_info(format , ## args)
#else
#define dprintf(format, args...)
#endif
#ifdef DEBUG_IP_FIREWALL_USER
-#define duprintf(format, args...) printk(format , ## args)
+#define duprintf(format, args...) pr_info(format , ## args)
#else
#define duprintf(format, args...)
#endif
#ifdef CONFIG_NETFILTER_DEBUG
-#define IP_NF_ASSERT(x) \
-do { \
- if (!(x)) \
- printk("IP_NF_ASSERT: %s:%s:%u\n", \
- __func__, __FILE__, __LINE__); \
-} while(0)
+#define IP_NF_ASSERT(x) WARN_ON(!(x))
#else
#define IP_NF_ASSERT(x)
#endif
@@ -197,30 +192,14 @@ ip6_checkentry(const struct ip6t_ip6 *ipv6)
}
static unsigned int
-ip6t_error(struct sk_buff *skb, const struct xt_target_param *par)
+ip6t_error(struct sk_buff *skb, const struct xt_action_param *par)
{
if (net_ratelimit())
- printk("ip6_tables: error: `%s'\n",
- (const char *)par->targinfo);
+ pr_info("error: `%s'\n", (const char *)par->targinfo);
return NF_DROP;
}
-/* Performance critical - called for every packet */
-static inline bool
-do_match(const struct ip6t_entry_match *m, const struct sk_buff *skb,
- struct xt_match_param *par)
-{
- par->match = m->u.kernel.match;
- par->matchinfo = m->data;
-
- /* Stop iteration if it doesn't match */
- if (!m->u.kernel.match->match(skb, par))
- return true;
- else
- return false;
-}
-
static inline struct ip6t_entry *
get_entry(const void *base, unsigned int offset)
{
@@ -352,18 +331,15 @@ ip6t_do_table(struct sk_buff *skb,
const struct net_device *out,
struct xt_table *table)
{
-#define tb_comefrom ((struct ip6t_entry *)table_base)->comefrom
-
static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
- bool hotdrop = false;
/* Initializing verdict to NF_DROP keeps gcc happy. */
unsigned int verdict = NF_DROP;
const char *indev, *outdev;
const void *table_base;
- struct ip6t_entry *e, *back;
+ struct ip6t_entry *e, **jumpstack;
+ unsigned int *stackptr, origptr, cpu;
const struct xt_table_info *private;
- struct xt_match_param mtpar;
- struct xt_target_param tgpar;
+ struct xt_action_param acpar;
/* Initialization */
indev = in ? in->name : nulldevname;
@@ -374,39 +350,42 @@ ip6t_do_table(struct sk_buff *skb,
* things we don't know, ie. tcp syn flag or ports). If the
* rule is also a fragment-specific rule, non-fragments won't
* match it. */
- mtpar.hotdrop = &hotdrop;
- mtpar.in = tgpar.in = in;
- mtpar.out = tgpar.out = out;
- mtpar.family = tgpar.family = NFPROTO_IPV6;
- mtpar.hooknum = tgpar.hooknum = hook;
+ acpar.hotdrop = false;
+ acpar.in = in;
+ acpar.out = out;
+ acpar.family = NFPROTO_IPV6;
+ acpar.hooknum = hook;
IP_NF_ASSERT(table->valid_hooks & (1 << hook));
xt_info_rdlock_bh();
private = table->private;
- table_base = private->entries[smp_processor_id()];
+ cpu = smp_processor_id();
+ table_base = private->entries[cpu];
+ jumpstack = (struct ip6t_entry **)private->jumpstack[cpu];
+ stackptr = per_cpu_ptr(private->stackptr, cpu);
+ origptr = *stackptr;
e = get_entry(table_base, private->hook_entry[hook]);
- /* For return from builtin chain */
- back = get_entry(table_base, private->underflow[hook]);
-
do {
const struct ip6t_entry_target *t;
const struct xt_entry_match *ematch;
IP_NF_ASSERT(e);
- IP_NF_ASSERT(back);
if (!ip6_packet_match(skb, indev, outdev, &e->ipv6,
- &mtpar.thoff, &mtpar.fragoff, &hotdrop)) {
+ &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) {
no_match:
e = ip6t_next_entry(e);
continue;
}
- xt_ematch_foreach(ematch, e)
- if (do_match(ematch, skb, &mtpar) != 0)
+ xt_ematch_foreach(ematch, e) {
+ acpar.match = ematch->u.kernel.match;
+ acpar.matchinfo = ematch->data;
+ if (!acpar.match->match(skb, &acpar))
goto no_match;
+ }
ADD_COUNTER(e->counters,
ntohs(ipv6_hdr(skb)->payload_len) +
@@ -433,62 +412,47 @@ ip6t_do_table(struct sk_buff *skb,
verdict = (unsigned)(-v) - 1;
break;
}
- e = back;
- back = get_entry(table_base, back->comefrom);
+ if (*stackptr == 0)
+ e = get_entry(table_base,
+ private->underflow[hook]);
+ else
+ e = ip6t_next_entry(jumpstack[--*stackptr]);
continue;
}
if (table_base + v != ip6t_next_entry(e) &&
!(e->ipv6.flags & IP6T_F_GOTO)) {
- /* Save old back ptr in next entry */
- struct ip6t_entry *next = ip6t_next_entry(e);
- next->comefrom = (void *)back - table_base;
- /* set back pointer to next entry */
- back = next;
+ if (*stackptr >= private->stacksize) {
+ verdict = NF_DROP;
+ break;
+ }
+ jumpstack[(*stackptr)++] = e;
}
e = get_entry(table_base, v);
continue;
}
- /* Targets which reenter must return
- abs. verdicts */
- tgpar.target = t->u.kernel.target;
- tgpar.targinfo = t->data;
-
-#ifdef CONFIG_NETFILTER_DEBUG
- tb_comefrom = 0xeeeeeeec;
-#endif
- verdict = t->u.kernel.target->target(skb, &tgpar);
+ acpar.target = t->u.kernel.target;
+ acpar.targinfo = t->data;
-#ifdef CONFIG_NETFILTER_DEBUG
- if (tb_comefrom != 0xeeeeeeec && verdict == IP6T_CONTINUE) {
- printk("Target %s reentered!\n",
- t->u.kernel.target->name);
- verdict = NF_DROP;
- }
- tb_comefrom = 0x57acc001;
-#endif
+ verdict = t->u.kernel.target->target(skb, &acpar);
if (verdict == IP6T_CONTINUE)
e = ip6t_next_entry(e);
else
/* Verdict */
break;
- } while (!hotdrop);
+ } while (!acpar.hotdrop);
-#ifdef CONFIG_NETFILTER_DEBUG
- tb_comefrom = NETFILTER_LINK_POISON;
-#endif
xt_info_rdunlock_bh();
+ *stackptr = origptr;
#ifdef DEBUG_ALLOW_ALL
return NF_ACCEPT;
#else
- if (hotdrop)
+ if (acpar.hotdrop)
return NF_DROP;
else return verdict;
#endif
-
-#undef tb_comefrom
}
/* Figures out from what hook each rule can be called: returns 0 if
@@ -517,7 +481,7 @@ mark_source_chains(const struct xt_table_info *newinfo,
int visited = e->comefrom & (1 << hook);
if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
- printk("iptables: loop hook %u pos %u %08X.\n",
+ pr_err("iptables: loop hook %u pos %u %08X.\n",
hook, pos, e->comefrom);
return 0;
}
@@ -661,12 +625,11 @@ find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par)
struct xt_match *match;
int ret;
- match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
- m->u.user.revision),
- "ip6t_%s", m->u.user.name);
- if (IS_ERR(match) || !match) {
+ match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
+ m->u.user.revision);
+ if (IS_ERR(match)) {
duprintf("find_check_match: `%s' not found\n", m->u.user.name);
- return match ? PTR_ERR(match) : -ENOENT;
+ return PTR_ERR(match);
}
m->u.kernel.match = match;
@@ -734,13 +697,11 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
}
t = ip6t_get_target(e);
- target = try_then_request_module(xt_find_target(AF_INET6,
- t->u.user.name,
- t->u.user.revision),
- "ip6t_%s", t->u.user.name);
- if (IS_ERR(target) || !target) {
+ target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
+ t->u.user.revision);
+ if (IS_ERR(target)) {
duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
- ret = target ? PTR_ERR(target) : -ENOENT;
+ ret = PTR_ERR(target);
goto cleanup_matches;
}
t->u.kernel.target = target;
@@ -873,6 +834,9 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
if (ret != 0)
return ret;
++i;
+ if (strcmp(ip6t_get_target(iter)->u.user.name,
+ XT_ERROR_TARGET) == 0)
+ ++newinfo->stacksize;
}
if (i != repl->num_entries) {
@@ -1509,13 +1473,12 @@ compat_find_calc_match(struct ip6t_entry_match *m,
{
struct xt_match *match;
- match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
- m->u.user.revision),
- "ip6t_%s", m->u.user.name);
- if (IS_ERR(match) || !match) {
+ match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
+ m->u.user.revision);
+ if (IS_ERR(match)) {
duprintf("compat_check_calc_match: `%s' not found\n",
m->u.user.name);
- return match ? PTR_ERR(match) : -ENOENT;
+ return PTR_ERR(match);
}
m->u.kernel.match = match;
*size += xt_compat_match_offset(match);
@@ -1582,14 +1545,12 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
}
t = compat_ip6t_get_target(e);
- target = try_then_request_module(xt_find_target(AF_INET6,
- t->u.user.name,
- t->u.user.revision),
- "ip6t_%s", t->u.user.name);
- if (IS_ERR(target) || !target) {
+ target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
+ t->u.user.revision);
+ if (IS_ERR(target)) {
duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
t->u.user.name);
- ret = target ? PTR_ERR(target) : -ENOENT;
+ ret = PTR_ERR(target);
goto release_matches;
}
t->u.kernel.target = target;
@@ -2127,8 +2088,7 @@ struct xt_table *ip6t_register_table(struct net *net,
{
int ret;
struct xt_table_info *newinfo;
- struct xt_table_info bootstrap
- = { 0, 0, 0, { 0 }, { 0 }, { } };
+ struct xt_table_info bootstrap = {0};
void *loc_cpu_entry;
struct xt_table *new_table;
@@ -2188,7 +2148,7 @@ icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
}
static bool
-icmp6_match(const struct sk_buff *skb, const struct xt_match_param *par)
+icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct icmp6hdr *ic;
struct icmp6hdr _icmph;
@@ -2204,7 +2164,7 @@ icmp6_match(const struct sk_buff *skb, const struct xt_match_param *par)
* can't. Hence, no choice but to drop.
*/
duprintf("Dropping evil ICMP tinygram.\n");
- *par->hotdrop = true;
+ par->hotdrop = true;
return false;
}
@@ -2216,31 +2176,32 @@ icmp6_match(const struct sk_buff *skb, const struct xt_match_param *par)
}
/* Called when user tries to insert an entry of this type. */
-static bool icmp6_checkentry(const struct xt_mtchk_param *par)
+static int icmp6_checkentry(const struct xt_mtchk_param *par)
{
const struct ip6t_icmp *icmpinfo = par->matchinfo;
/* Must specify no unknown invflags */
- return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
+ return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
}
/* The built-in targets: standard (NULL) and error. */
-static struct xt_target ip6t_standard_target __read_mostly = {
- .name = IP6T_STANDARD_TARGET,
- .targetsize = sizeof(int),
- .family = NFPROTO_IPV6,
+static struct xt_target ip6t_builtin_tg[] __read_mostly = {
+ {
+ .name = IP6T_STANDARD_TARGET,
+ .targetsize = sizeof(int),
+ .family = NFPROTO_IPV6,
#ifdef CONFIG_COMPAT
- .compatsize = sizeof(compat_int_t),
- .compat_from_user = compat_standard_from_user,
- .compat_to_user = compat_standard_to_user,
+ .compatsize = sizeof(compat_int_t),
+ .compat_from_user = compat_standard_from_user,
+ .compat_to_user = compat_standard_to_user,
#endif
-};
-
-static struct xt_target ip6t_error_target __read_mostly = {
- .name = IP6T_ERROR_TARGET,
- .target = ip6t_error,
- .targetsize = IP6T_FUNCTION_MAXNAMELEN,
- .family = NFPROTO_IPV6,
+ },
+ {
+ .name = IP6T_ERROR_TARGET,
+ .target = ip6t_error,
+ .targetsize = IP6T_FUNCTION_MAXNAMELEN,
+ .family = NFPROTO_IPV6,
+ },
};
static struct nf_sockopt_ops ip6t_sockopts = {
@@ -2260,13 +2221,15 @@ static struct nf_sockopt_ops ip6t_sockopts = {
.owner = THIS_MODULE,
};
-static struct xt_match icmp6_matchstruct __read_mostly = {
- .name = "icmp6",
- .match = icmp6_match,
- .matchsize = sizeof(struct ip6t_icmp),
- .checkentry = icmp6_checkentry,
- .proto = IPPROTO_ICMPV6,
- .family = NFPROTO_IPV6,
+static struct xt_match ip6t_builtin_mt[] __read_mostly = {
+ {
+ .name = "icmp6",
+ .match = icmp6_match,
+ .matchsize = sizeof(struct ip6t_icmp),
+ .checkentry = icmp6_checkentry,
+ .proto = IPPROTO_ICMPV6,
+ .family = NFPROTO_IPV6,
+ },
};
static int __net_init ip6_tables_net_init(struct net *net)
@@ -2293,13 +2256,10 @@ static int __init ip6_tables_init(void)
goto err1;
/* Noone else will be downing sem now, so we won't sleep */
- ret = xt_register_target(&ip6t_standard_target);
+ ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
if (ret < 0)
goto err2;
- ret = xt_register_target(&ip6t_error_target);
- if (ret < 0)
- goto err3;
- ret = xt_register_match(&icmp6_matchstruct);
+ ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
if (ret < 0)
goto err4;
@@ -2308,15 +2268,13 @@ static int __init ip6_tables_init(void)
if (ret < 0)
goto err5;
- printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
+ pr_info("(C) 2000-2006 Netfilter Core Team\n");
return 0;
err5:
- xt_unregister_match(&icmp6_matchstruct);
+ xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
err4:
- xt_unregister_target(&ip6t_error_target);
-err3:
- xt_unregister_target(&ip6t_standard_target);
+ xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
err2:
unregister_pernet_subsys(&ip6_tables_net_ops);
err1:
@@ -2327,10 +2285,8 @@ static void __exit ip6_tables_fini(void)
{
nf_unregister_sockopt(&ip6t_sockopts);
- xt_unregister_match(&icmp6_matchstruct);
- xt_unregister_target(&ip6t_error_target);
- xt_unregister_target(&ip6t_standard_target);
-
+ xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
+ xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
unregister_pernet_subsys(&ip6_tables_net_ops);
}
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index b285fdf..af4ee11 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -9,9 +9,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/ip.h>
@@ -378,7 +377,7 @@ static struct nf_loginfo default_loginfo = {
.type = NF_LOG_TYPE_LOG,
.u = {
.log = {
- .level = 0,
+ .level = 5,
.logflags = NF_LOG_MASK,
},
},
@@ -437,7 +436,7 @@ ip6t_log_packet(u_int8_t pf,
}
static unsigned int
-log_tg6(struct sk_buff *skb, const struct xt_target_param *par)
+log_tg6(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct ip6t_log_info *loginfo = par->targinfo;
struct nf_loginfo li;
@@ -452,20 +451,19 @@ log_tg6(struct sk_buff *skb, const struct xt_target_param *par)
}
-static bool log_tg6_check(const struct xt_tgchk_param *par)
+static int log_tg6_check(const struct xt_tgchk_param *par)
{
const struct ip6t_log_info *loginfo = par->targinfo;
if (loginfo->level >= 8) {
- pr_debug("LOG: level %u >= 8\n", loginfo->level);
- return false;
+ pr_debug("level %u >= 8\n", loginfo->level);
+ return -EINVAL;
}
if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
- pr_debug("LOG: prefix term %i\n",
- loginfo->prefix[sizeof(loginfo->prefix)-1]);
- return false;
+ pr_debug("prefix not null-terminated\n");
+ return -EINVAL;
}
- return true;
+ return 0;
}
static struct xt_target log_tg6_reg __read_mostly = {
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index 39b50c3..47d2277 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -14,6 +14,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/gfp.h>
#include <linux/module.h>
@@ -50,7 +51,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
(!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
- pr_debug("ip6t_REJECT: addr is not unicast.\n");
+ pr_debug("addr is not unicast.\n");
return;
}
@@ -58,7 +59,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto);
if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
- pr_debug("ip6t_REJECT: Can't get TCP header.\n");
+ pr_debug("Cannot get TCP header.\n");
return;
}
@@ -66,7 +67,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
/* IP header checks: fragment, too short. */
if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) {
- pr_debug("ip6t_REJECT: proto(%d) != IPPROTO_TCP, "
+ pr_debug("proto(%d) != IPPROTO_TCP, "
"or too short. otcplen = %d\n",
proto, otcplen);
return;
@@ -77,14 +78,14 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
/* No RST for RST. */
if (otcph.rst) {
- pr_debug("ip6t_REJECT: RST is set\n");
+ pr_debug("RST is set\n");
return;
}
/* Check checksum. */
if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP,
skb_checksum(oldskb, tcphoff, otcplen, 0))) {
- pr_debug("ip6t_REJECT: TCP checksum is invalid\n");
+ pr_debug("TCP checksum is invalid\n");
return;
}
@@ -108,7 +109,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
if (!nskb) {
if (net_ratelimit())
- printk("ip6t_REJECT: Can't alloc skb\n");
+ pr_debug("cannot alloc skb\n");
dst_release(dst);
return;
}
@@ -174,15 +175,12 @@ send_unreach(struct net *net, struct sk_buff *skb_in, unsigned char code,
}
static unsigned int
-reject_tg6(struct sk_buff *skb, const struct xt_target_param *par)
+reject_tg6(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct ip6t_reject_info *reject = par->targinfo;
struct net *net = dev_net((par->in != NULL) ? par->in : par->out);
pr_debug("%s: medium point\n", __func__);
- /* WARNING: This code causes reentry within ip6tables.
- This means that the ip6tables jump stack is now crap. We
- must return an absolute verdict. --RR */
switch (reject->with) {
case IP6T_ICMP6_NO_ROUTE:
send_unreach(net, skb, ICMPV6_NOROUTE, par->hooknum);
@@ -207,30 +205,30 @@ reject_tg6(struct sk_buff *skb, const struct xt_target_param *par)
break;
default:
if (net_ratelimit())
- printk(KERN_WARNING "ip6t_REJECT: case %u not handled yet\n", reject->with);
+ pr_info("case %u not handled yet\n", reject->with);
break;
}
return NF_DROP;
}
-static bool reject_tg6_check(const struct xt_tgchk_param *par)
+static int reject_tg6_check(const struct xt_tgchk_param *par)
{
const struct ip6t_reject_info *rejinfo = par->targinfo;
const struct ip6t_entry *e = par->entryinfo;
if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
- printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
- return false;
+ pr_info("ECHOREPLY is not supported.\n");
+ return -EINVAL;
} else if (rejinfo->with == IP6T_TCP_RESET) {
/* Must specify that it's a TCP packet */
if (e->ipv6.proto != IPPROTO_TCP ||
(e->ipv6.invflags & XT_INV_PROTO)) {
- printk("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
- return false;
+ pr_info("TCP_RESET illegal for non-tcp\n");
+ return -EINVAL;
}
}
- return true;
+ return 0;
}
static struct xt_target reject_tg6_reg __read_mostly = {
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c
index ac0b7c6..89cccc5 100644
--- a/net/ipv6/netfilter/ip6t_ah.c
+++ b/net/ipv6/netfilter/ip6t_ah.c
@@ -6,7 +6,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
@@ -29,14 +29,14 @@ spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert)
{
bool r;
- pr_debug("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",
+ pr_debug("spi_match:%c 0x%x <= 0x%x <= 0x%x\n",
invert ? '!' : ' ', min, spi, max);
r = (spi >= min && spi <= max) ^ invert;
pr_debug(" result %s\n", r ? "PASS" : "FAILED");
return r;
}
-static bool ah_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool ah_mt6(const struct sk_buff *skb, struct xt_action_param *par)
{
struct ip_auth_hdr _ah;
const struct ip_auth_hdr *ah;
@@ -48,13 +48,13 @@ static bool ah_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL);
if (err < 0) {
if (err != -ENOENT)
- *par->hotdrop = true;
+ par->hotdrop = true;
return false;
}
ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah);
if (ah == NULL) {
- *par->hotdrop = true;
+ par->hotdrop = true;
return false;
}
@@ -87,15 +87,15 @@ static bool ah_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
!(ahinfo->hdrres && ah->reserved);
}
-static bool ah_mt6_check(const struct xt_mtchk_param *par)
+static int ah_mt6_check(const struct xt_mtchk_param *par)
{
const struct ip6t_ah *ahinfo = par->matchinfo;
if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
- pr_debug("ip6t_ah: unknown flags %X\n", ahinfo->invflags);
- return false;
+ pr_debug("unknown flags %X\n", ahinfo->invflags);
+ return -EINVAL;
}
- return true;
+ return 0;
}
static struct xt_match ah_mt6_reg __read_mostly = {
diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c
index ca287f6..aab0706 100644
--- a/net/ipv6/netfilter/ip6t_eui64.c
+++ b/net/ipv6/netfilter/ip6t_eui64.c
@@ -20,14 +20,14 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
static bool
-eui64_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+eui64_mt6(const struct sk_buff *skb, struct xt_action_param *par)
{
unsigned char eui64[8];
if (!(skb_mac_header(skb) >= skb->head &&
skb_mac_header(skb) + ETH_HLEN <= skb->data) &&
par->fragoff != 0) {
- *par->hotdrop = true;
+ par->hotdrop = true;
return false;
}
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c
index 7b91c25..eda898f 100644
--- a/net/ipv6/netfilter/ip6t_frag.c
+++ b/net/ipv6/netfilter/ip6t_frag.c
@@ -6,7 +6,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
@@ -27,7 +27,7 @@ static inline bool
id_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert)
{
bool r;
- pr_debug("frag id_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ',
+ pr_debug("id_match:%c 0x%x <= 0x%x <= 0x%x\n", invert ? '!' : ' ',
min, id, max);
r = (id >= min && id <= max) ^ invert;
pr_debug(" result %s\n", r ? "PASS" : "FAILED");
@@ -35,7 +35,7 @@ id_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert)
}
static bool
-frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+frag_mt6(const struct sk_buff *skb, struct xt_action_param *par)
{
struct frag_hdr _frag;
const struct frag_hdr *fh;
@@ -46,13 +46,13 @@ frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL);
if (err < 0) {
if (err != -ENOENT)
- *par->hotdrop = true;
+ par->hotdrop = true;
return false;
}
fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag);
if (fh == NULL) {
- *par->hotdrop = true;
+ par->hotdrop = true;
return false;
}
@@ -102,15 +102,15 @@ frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
(ntohs(fh->frag_off) & IP6_MF));
}
-static bool frag_mt6_check(const struct xt_mtchk_param *par)
+static int frag_mt6_check(const struct xt_mtchk_param *par)
{
const struct ip6t_frag *fraginfo = par->matchinfo;
if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) {
- pr_debug("ip6t_frag: unknown flags %X\n", fraginfo->invflags);
- return false;
+ pr_debug("unknown flags %X\n", fraginfo->invflags);
+ return -EINVAL;
}
- return true;
+ return 0;
}
static struct xt_match frag_mt6_reg __read_mostly = {
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c
index e606775..59df051 100644
--- a/net/ipv6/netfilter/ip6t_hbh.c
+++ b/net/ipv6/netfilter/ip6t_hbh.c
@@ -6,7 +6,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
@@ -41,8 +41,10 @@ MODULE_ALIAS("ip6t_dst");
* 5 -> RTALERT 2 x x
*/
+static struct xt_match hbh_mt6_reg[] __read_mostly;
+
static bool
-hbh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
{
struct ipv6_opt_hdr _optsh;
const struct ipv6_opt_hdr *oh;
@@ -58,16 +60,18 @@ hbh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
unsigned int optlen;
int err;
- err = ipv6_find_hdr(skb, &ptr, par->match->data, NULL);
+ err = ipv6_find_hdr(skb, &ptr,
+ (par->match == &hbh_mt6_reg[0]) ?
+ NEXTHDR_HOP : NEXTHDR_DEST, NULL);
if (err < 0) {
if (err != -ENOENT)
- *par->hotdrop = true;
+ par->hotdrop = true;
return false;
}
oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
if (oh == NULL) {
- *par->hotdrop = true;
+ par->hotdrop = true;
return false;
}
@@ -160,32 +164,32 @@ hbh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
return false;
}
-static bool hbh_mt6_check(const struct xt_mtchk_param *par)
+static int hbh_mt6_check(const struct xt_mtchk_param *par)
{
const struct ip6t_opts *optsinfo = par->matchinfo;
if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
- pr_debug("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
- return false;
+ pr_debug("unknown flags %X\n", optsinfo->invflags);
+ return -EINVAL;
}
if (optsinfo->flags & IP6T_OPTS_NSTRICT) {
- pr_debug("ip6t_opts: Not strict - not implemented");
- return false;
+ pr_debug("Not strict - not implemented");
+ return -EINVAL;
}
- return true;
+ return 0;
}
static struct xt_match hbh_mt6_reg[] __read_mostly = {
{
+ /* Note, hbh_mt6 relies on the order of hbh_mt6_reg */
.name = "hbh",
.family = NFPROTO_IPV6,
.match = hbh_mt6,
.matchsize = sizeof(struct ip6t_opts),
.checkentry = hbh_mt6_check,
.me = THIS_MODULE,
- .data = NEXTHDR_HOP,
},
{
.name = "dst",
@@ -194,7 +198,6 @@ static struct xt_match hbh_mt6_reg[] __read_mostly = {
.matchsize = sizeof(struct ip6t_opts),
.checkentry = hbh_mt6_check,
.me = THIS_MODULE,
- .data = NEXTHDR_DEST,
},
};
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c
index 91490ad..54bd979 100644
--- a/net/ipv6/netfilter/ip6t_ipv6header.c
+++ b/net/ipv6/netfilter/ip6t_ipv6header.c
@@ -27,7 +27,7 @@ MODULE_DESCRIPTION("Xtables: IPv6 header types match");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
static bool
-ipv6header_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+ipv6header_mt6(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct ip6t_ipv6header_info *info = par->matchinfo;
unsigned int temp;
@@ -118,16 +118,16 @@ ipv6header_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
}
}
-static bool ipv6header_mt6_check(const struct xt_mtchk_param *par)
+static int ipv6header_mt6_check(const struct xt_mtchk_param *par)
{
const struct ip6t_ipv6header_info *info = par->matchinfo;
/* invflags is 0 or 0xff in hard mode */
if ((!info->modeflag) && info->invflags != 0x00 &&
info->invflags != 0xFF)
- return false;
+ return -EINVAL;
- return true;
+ return 0;
}
static struct xt_match ipv6header_mt6_reg __read_mostly = {
diff --git a/net/ipv6/netfilter/ip6t_mh.c b/net/ipv6/netfilter/ip6t_mh.c
index aafe4e6..0c90c66 100644
--- a/net/ipv6/netfilter/ip6t_mh.c
+++ b/net/ipv6/netfilter/ip6t_mh.c
@@ -11,6 +11,7 @@
* Based on net/netfilter/xt_tcpudp.c
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h>
#include <linux/module.h>
#include <net/ip.h>
@@ -24,12 +25,6 @@
MODULE_DESCRIPTION("Xtables: IPv6 Mobility Header match");
MODULE_LICENSE("GPL");
-#ifdef DEBUG_IP_FIREWALL_USER
-#define duprintf(format, args...) printk(format , ## args)
-#else
-#define duprintf(format, args...)
-#endif
-
/* Returns 1 if the type is matched by the range, 0 otherwise */
static inline bool
type_match(u_int8_t min, u_int8_t max, u_int8_t type, bool invert)
@@ -37,7 +32,7 @@ type_match(u_int8_t min, u_int8_t max, u_int8_t type, bool invert)
return (type >= min && type <= max) ^ invert;
}
-static bool mh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool mh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
{
struct ip6_mh _mh;
const struct ip6_mh *mh;
@@ -51,15 +46,15 @@ static bool mh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
if (mh == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
- duprintf("Dropping evil MH tinygram.\n");
- *par->hotdrop = true;
+ pr_debug("Dropping evil MH tinygram.\n");
+ par->hotdrop = true;
return false;
}
if (mh->ip6mh_proto != IPPROTO_NONE) {
- duprintf("Dropping invalid MH Payload Proto: %u\n",
+ pr_debug("Dropping invalid MH Payload Proto: %u\n",
mh->ip6mh_proto);
- *par->hotdrop = true;
+ par->hotdrop = true;
return false;
}
@@ -67,12 +62,12 @@ static bool mh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
!!(mhinfo->invflags & IP6T_MH_INV_TYPE));
}
-static bool mh_mt6_check(const struct xt_mtchk_param *par)
+static int mh_mt6_check(const struct xt_mtchk_param *par)
{
const struct ip6t_mh *mhinfo = par->matchinfo;
/* Must specify no unknown invflags */
- return !(mhinfo->invflags & ~IP6T_MH_INV_MASK);
+ return (mhinfo->invflags & ~IP6T_MH_INV_MASK) ? -EINVAL : 0;
}
static struct xt_match mh_mt6_reg __read_mostly = {
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
index b77307f..d8488c5 100644
--- a/net/ipv6/netfilter/ip6t_rt.c
+++ b/net/ipv6/netfilter/ip6t_rt.c
@@ -6,7 +6,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
@@ -29,14 +29,14 @@ static inline bool
segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert)
{
bool r;
- pr_debug("rt segsleft_match:%c 0x%x <= 0x%x <= 0x%x",
+ pr_debug("segsleft_match:%c 0x%x <= 0x%x <= 0x%x\n",
invert ? '!' : ' ', min, id, max);
r = (id >= min && id <= max) ^ invert;
pr_debug(" result %s\n", r ? "PASS" : "FAILED");
return r;
}
-static bool rt_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool rt_mt6(const struct sk_buff *skb, struct xt_action_param *par)
{
struct ipv6_rt_hdr _route;
const struct ipv6_rt_hdr *rh;
@@ -52,13 +52,13 @@ static bool rt_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL);
if (err < 0) {
if (err != -ENOENT)
- *par->hotdrop = true;
+ par->hotdrop = true;
return false;
}
rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
if (rh == NULL) {
- *par->hotdrop = true;
+ par->hotdrop = true;
return false;
}
@@ -183,23 +183,23 @@ static bool rt_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
return false;
}
-static bool rt_mt6_check(const struct xt_mtchk_param *par)
+static int rt_mt6_check(const struct xt_mtchk_param *par)
{
const struct ip6t_rt *rtinfo = par->matchinfo;
if (rtinfo->invflags & ~IP6T_RT_INV_MASK) {
- pr_debug("ip6t_rt: unknown flags %X\n", rtinfo->invflags);
- return false;
+ pr_debug("unknown flags %X\n", rtinfo->invflags);
+ return -EINVAL;
}
if ((rtinfo->flags & (IP6T_RT_RES | IP6T_RT_FST_MASK)) &&
(!(rtinfo->flags & IP6T_RT_TYP) ||
(rtinfo->rt_type != 0) ||
(rtinfo->invflags & IP6T_RT_INV_TYP))) {
pr_debug("`--rt-type 0' required before `--rt-0-*'");
- return false;
+ return -EINVAL;
}
- return true;
+ return 0;
}
static struct xt_match rt_mt6_reg __read_mostly = {
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index d6fc9af..c9e37c8 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -81,7 +81,7 @@ static int __init ip6table_filter_init(void)
int ret;
if (forward < 0 || forward > NF_MAX_VERDICT) {
- printk("iptables forward must be 0 or 1\n");
+ pr_err("iptables forward must be 0 or 1\n");
return -EINVAL;
}
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index 6a102b5..679a0a3 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -43,7 +43,7 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out)
if (skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr)) {
if (net_ratelimit())
- printk("ip6t_hook: happy cracking.\n");
+ pr_warning("ip6t_hook: happy cracking.\n");
return NF_ACCEPT;
}
#endif
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 996c3f4..ff43461 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -280,7 +280,7 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum,
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct ipv6hdr)) {
if (net_ratelimit())
- printk("ipv6_conntrack_local: packet too short\n");
+ pr_notice("ipv6_conntrack_local: packet too short\n");
return NF_ACCEPT;
}
return __ipv6_conntrack_in(dev_net(out), hooknum, skb, okfn);
@@ -406,37 +406,37 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
ret = nf_ct_frag6_init();
if (ret < 0) {
- printk("nf_conntrack_ipv6: can't initialize frag6.\n");
+ pr_err("nf_conntrack_ipv6: can't initialize frag6.\n");
return ret;
}
ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6);
if (ret < 0) {
- printk("nf_conntrack_ipv6: can't register tcp.\n");
+ pr_err("nf_conntrack_ipv6: can't register tcp.\n");
goto cleanup_frag6;
}
ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6);
if (ret < 0) {
- printk("nf_conntrack_ipv6: can't register udp.\n");
+ pr_err("nf_conntrack_ipv6: can't register udp.\n");
goto cleanup_tcp;
}
ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmpv6);
if (ret < 0) {
- printk("nf_conntrack_ipv6: can't register icmpv6.\n");
+ pr_err("nf_conntrack_ipv6: can't register icmpv6.\n");
goto cleanup_udp;
}
ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6);
if (ret < 0) {
- printk("nf_conntrack_ipv6: can't register ipv6\n");
+ pr_err("nf_conntrack_ipv6: can't register ipv6\n");
goto cleanup_icmpv6;
}
ret = nf_register_hooks(ipv6_conntrack_ops,
ARRAY_SIZE(ipv6_conntrack_ops));
if (ret < 0) {
- printk("nf_conntrack_ipv6: can't register pre-routing defrag "
+ pr_err("nf_conntrack_ipv6: can't register pre-routing defrag "
"hook.\n");
goto cleanup_ipv6;
}
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index dd5b9bd..6fb8901 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -644,7 +644,7 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
s2 = s->next;
s->next = NULL;
- NF_HOOK_THRESH(PF_INET6, hooknum, s, in, out, okfn,
+ NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s, in, out, okfn,
NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
s = s2;
}
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index 458eabf..566798d 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -168,7 +168,6 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib)
i & 0x100 ? "Out" : "In", i & 0xff);
seq_printf(seq, "%-32s\t%lu\n", name, val);
}
- return;
}
static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **mib,
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 0e3d2dd..4a4dcbe 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -640,8 +640,8 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
goto error_fault;
IP6_UPD_PO_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
- err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
- dst_output);
+ err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
+ rt->u.dst.dev, dst_output);
if (err > 0)
err = net_xmit_errno(err);
if (err)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 05ebd78..252d761 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -316,7 +316,6 @@ static void rt6_probe(struct rt6_info *rt)
#else
static inline void rt6_probe(struct rt6_info *rt)
{
- return;
}
#endif
@@ -815,7 +814,7 @@ struct dst_entry * ip6_route_output(struct net *net, struct sock *sk,
{
int flags = 0;
- if (fl->oif || rt6_need_strict(&fl->fl6_dst))
+ if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl->fl6_dst))
flags |= RT6_LOOKUP_F_IFACE;
if (!ipv6_addr_any(&fl->fl6_src))
@@ -1553,7 +1552,6 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
out:
dst_release(&rt->u.dst);
- return;
}
/*
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 5abae10..e51e650 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -566,11 +566,9 @@ static int ipip6_rcv(struct sk_buff *skb)
kfree_skb(skb);
return 0;
}
- tunnel->dev->stats.rx_packets++;
- tunnel->dev->stats.rx_bytes += skb->len;
- skb->dev = tunnel->dev;
- skb_dst_drop(skb);
- nf_reset(skb);
+
+ skb_tunnel_rx(skb, tunnel->dev);
+
ipip6_ecn_decapsulate(iph, skb);
netif_rx(skb);
rcu_read_unlock();
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 6603511..2b7c3a1 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -604,7 +604,7 @@ static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer,
kfree(newkey);
return -ENOMEM;
}
- sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
+ sk_nocaps_add(sk, NETIF_F_GSO_MASK);
}
if (tcp_alloc_md5sig_pool(sk) == NULL) {
kfree(newkey);
@@ -741,7 +741,7 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
return -ENOMEM;
tp->md5sig_info = p;
- sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
+ sk_nocaps_add(sk, NETIF_F_GSO_MASK);
}
newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 3d7a2c0..87be586 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -328,6 +328,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
int err;
int is_udplite = IS_UDPLITE(sk);
int is_udp4;
+ bool slow;
if (addr_len)
*addr_len=sizeof(struct sockaddr_in6);
@@ -424,7 +425,7 @@ out:
return err;
csum_copy_err:
- lock_sock_bh(sk);
+ slow = lock_sock_fast(sk);
if (!skb_kill_datagram(sk, skb, flags)) {
if (is_udp4)
UDP_INC_STATS_USER(sock_net(sk),
@@ -433,7 +434,7 @@ csum_copy_err:
UDP6_INC_STATS_USER(sock_net(sk),
UDP_MIB_INERRORS, is_udplite);
}
- unlock_sock_bh(sk);
+ unlock_sock_fast(sk, slow);
if (flags & MSG_DONTWAIT)
return -EAGAIN;
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index 2bc98ed..f8c3cf8 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -42,7 +42,7 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)
ipv6_hdr(skb)->payload_len = htons(skb->len);
__skb_push(skb, skb->data - skb_network_header(skb));
- NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
+ NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
ip6_rcv_finish);
return -1;
}
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 0c92112..6434bd5 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -90,6 +90,6 @@ static int xfrm6_output_finish(struct sk_buff *skb)
int xfrm6_output(struct sk_buff *skb)
{
- return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb_dst(skb)->dev,
- xfrm6_output_finish);
+ return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL,
+ skb_dst(skb)->dev, xfrm6_output_finish);
}