]> Pileus Git - ~andy/linux/blobdiff - net/ipv6/ip6mr.c
ipmr/ip6mr: report origin of mfc entry into rtnl msg
[~andy/linux] / net / ipv6 / ip6mr.c
index f7c7c6319720246f67f3cdbf09daea76634df0ba..d51b91122866b1f5a53321a11331f3a69f7bc199 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/netfilter_ipv6.h>
 #include <linux/export.h>
 #include <net/ip6_checksum.h>
+#include <linux/netconf.h>
 
 struct mr6_table {
        struct list_head        list;
@@ -66,8 +67,8 @@ struct mr6_table {
        struct mif_device       vif6_table[MAXMIFS];
        int                     maxvif;
        atomic_t                cache_resolve_queue_len;
-       int                     mroute_do_assert;
-       int                     mroute_do_pim;
+       bool                    mroute_do_assert;
+       bool                    mroute_do_pim;
 #ifdef CONFIG_IPV6_PIMSM_V2
        int                     mroute_reg_vif_num;
 #endif
@@ -805,8 +806,12 @@ static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head)
        dev_set_allmulti(dev, -1);
 
        in6_dev = __in6_dev_get(dev);
-       if (in6_dev)
+       if (in6_dev) {
                in6_dev->cnf.mc_forwarding--;
+               inet6_netconf_notify_devconf(dev_net(dev),
+                                            NETCONFA_MC_FORWARDING,
+                                            dev->ifindex, &in6_dev->cnf);
+       }
 
        if (v->flags & MIFF_REGISTER)
                unregister_netdevice_queue(dev, head);
@@ -958,8 +963,12 @@ static int mif6_add(struct net *net, struct mr6_table *mrt,
        }
 
        in6_dev = __in6_dev_get(dev);
-       if (in6_dev)
+       if (in6_dev) {
                in6_dev->cnf.mc_forwarding++;
+               inet6_netconf_notify_devconf(dev_net(dev),
+                                            NETCONFA_MC_FORWARDING,
+                                            dev->ifindex, &in6_dev->cnf);
+       }
 
        /*
         *      Fill in the VIF structures
@@ -1513,6 +1522,9 @@ static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk)
        if (likely(mrt->mroute6_sk == NULL)) {
                mrt->mroute6_sk = sk;
                net->ipv6.devconf_all->mc_forwarding++;
+               inet6_netconf_notify_devconf(net, NETCONFA_MC_FORWARDING,
+                                            NETCONFA_IFINDEX_ALL,
+                                            net->ipv6.devconf_all);
        }
        else
                err = -EADDRINUSE;
@@ -1535,6 +1547,10 @@ int ip6mr_sk_done(struct sock *sk)
                        write_lock_bh(&mrt_lock);
                        mrt->mroute6_sk = NULL;
                        net->ipv6.devconf_all->mc_forwarding--;
+                       inet6_netconf_notify_devconf(net,
+                                                    NETCONFA_MC_FORWARDING,
+                                                    NETCONFA_IFINDEX_ALL,
+                                                    net->ipv6.devconf_all);
                        write_unlock_bh(&mrt_lock);
 
                        mroute_clean_tables(mrt);
@@ -1583,7 +1599,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
                return -ENOENT;
 
        if (optname != MRT6_INIT) {
-               if (sk != mrt->mroute6_sk && !capable(CAP_NET_ADMIN))
+               if (sk != mrt->mroute6_sk && !ns_capable(net->user_ns, CAP_NET_ADMIN))
                        return -EACCES;
        }
 
@@ -1646,9 +1662,12 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
        case MRT6_ASSERT:
        {
                int v;
+
+               if (optlen != sizeof(v))
+                       return -EINVAL;
                if (get_user(v, (int __user *)optval))
                        return -EFAULT;
-               mrt->mroute_do_assert = !!v;
+               mrt->mroute_do_assert = v;
                return 0;
        }
 
@@ -1656,6 +1675,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
        case MRT6_PIM:
        {
                int v;
+
+               if (optlen != sizeof(v))
+                       return -EINVAL;
                if (get_user(v, (int __user *)optval))
                        return -EFAULT;
                v = !!v;
@@ -2097,8 +2119,8 @@ static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
 {
        int ct;
        struct rtnexthop *nhp;
-       u8 *b = skb_tail_pointer(skb);
-       struct rtattr *mp_head;
+       struct nlattr *mp_attr;
+       struct rta_mfc_stats mfcs;
 
        /* If cache is unresolved, don't try to parse IIF and OIF */
        if (c->mf6c_parent >= MAXMIFS)
@@ -2107,28 +2129,35 @@ static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
        if (MIF_EXISTS(mrt, c->mf6c_parent) &&
            nla_put_u32(skb, RTA_IIF, mrt->vif6_table[c->mf6c_parent].dev->ifindex) < 0)
                return -EMSGSIZE;
-
-       mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
+       mp_attr = nla_nest_start(skb, RTA_MULTIPATH);
+       if (mp_attr == NULL)
+               return -EMSGSIZE;
 
        for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
                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 = nla_reserve_nohdr(skb, sizeof(*nhp));
+                       if (nhp == NULL) {
+                               nla_nest_cancel(skb, mp_attr);
+                               return -EMSGSIZE;
+                       }
+
                        nhp->rtnh_flags = 0;
                        nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
                        nhp->rtnh_ifindex = mrt->vif6_table[ct].dev->ifindex;
                        nhp->rtnh_len = sizeof(*nhp);
                }
        }
-       mp_head->rta_type = RTA_MULTIPATH;
-       mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
+
+       nla_nest_end(skb, mp_attr);
+
+       mfcs.mfcs_packets = c->mfc_un.res.pkt;
+       mfcs.mfcs_bytes = c->mfc_un.res.bytes;
+       mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if;
+       if (nla_put(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs) < 0)
+               return -EMSGSIZE;
+
        rtm->rtm_type = RTN_MULTICAST;
        return 1;
-
-rtattr_failure:
-       nlmsg_trim(skb, b);
-       return -EMSGSIZE;
 }
 
 int ip6mr_get_route(struct net *net,
@@ -2220,7 +2249,10 @@ static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
        if (nla_put_u32(skb, RTA_TABLE, mrt->id))
                goto nla_put_failure;
        rtm->rtm_scope    = RT_SCOPE_UNIVERSE;
-       rtm->rtm_protocol = RTPROT_UNSPEC;
+       if (c->mfc_flags & MFC_STATIC)
+               rtm->rtm_protocol = RTPROT_STATIC;
+       else
+               rtm->rtm_protocol = RTPROT_MROUTED;
        rtm->rtm_flags    = 0;
 
        if (nla_put(skb, RTA_SRC, 16, &c->mf6c_origin) ||