#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/init.h>
+#include <linux/slab.h>
#include <net/protocol.h>
#include <linux/skbuff.h>
#include <net/sock.h>
static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm);
static void mroute_clean_tables(struct net *net);
-#ifdef CONFIG_IPV6_PIMSM_V2
-static struct inet6_protocol pim6_protocol;
-#endif
-
static struct timer_list ipmr_expire_timer;
return 0;
}
-static struct seq_operations ipmr_mfc_seq_ops = {
+static const struct seq_operations ipmr_mfc_seq_ops = {
.start = ipmr_mfc_seq_start,
.next = ipmr_mfc_seq_next,
.stop = ipmr_mfc_seq_stop,
return 0;
}
-static struct inet6_protocol pim6_protocol = {
+static const struct inet6_protocol pim6_protocol = {
.handler = pim6_rcv,
};
* Delete a VIF entry
*/
-static int mif6_delete(struct net *net, int vifi)
+static int mif6_delete(struct net *net, int vifi, struct list_head *head)
{
struct mif_device *v;
struct net_device *dev;
in6_dev->cnf.mc_forwarding--;
if (v->flags & MIFF_REGISTER)
- unregister_netdevice(dev);
+ unregister_netdevice_queue(dev, head);
dev_put(dev);
return 0;
struct net *net = dev_net(dev);
struct mif_device *v;
int ct;
+ LIST_HEAD(list);
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);
+ mif6_delete(net, ct, &list);
}
+ unregister_netdevice_many(&list);
+
return NOTIFY_DONE;
}
unsigned char ttls[MAXMIFS];
int i;
+ if (mfc->mf6cc_parent >= MAXMIFS)
+ return -ENFILE;
+
memset(ttls, 255, MAXMIFS);
for (i = 0; i < MAXMIFS; i++) {
if (IF_ISSET(i, &mfc->mf6cc_ifset))
static void mroute_clean_tables(struct net *net)
{
int i;
+ LIST_HEAD(list);
/*
* 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);
+ mif6_delete(net, i, &list);
}
+ unregister_netdevice_many(&list);
/*
* Wipe the cache
* MOSPF/PIM router set up we can clean this up.
*/
-int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int optlen)
+int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
{
int ret;
struct mif6ctl vif;
switch (optname) {
case MRT6_INIT:
if (sk->sk_type != SOCK_RAW ||
- inet_sk(sk)->num != IPPROTO_ICMPV6)
+ inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
return -EOPNOTSUPP;
if (optlen < sizeof(int))
return -EINVAL;
if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
return -EFAULT;
rtnl_lock();
- ret = mif6_delete(net, mifi);
+ ret = mif6_delete(net, mifi, NULL);
rtnl_unlock();
return ret;
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:
int ct;
struct rtnexthop *nhp;
struct net *net = mfc6_net(c);
- struct net_device *dev = net->ipv6.vif6_table[c->mf6c_parent].dev;
u8 *b = skb_tail_pointer(skb);
struct rtattr *mp_head;
- if (dev)
- RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex);
+ /* If cache is unresolved, don't try to parse IIF and OIF */
+ 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);
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 (c->mfc_un.res.ttls[ct] < 255) {
+ if (MIF_EXISTS(net, 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)));