]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/ipv4/ipmr.c
ipv4: Remove flowi from struct rtable.
[mv-sheeva.git] / net / ipv4 / ipmr.c
index 3f3a9afd73e02f1d5a4f89eb85d1bf7ba47b4ddc..9d5f6340af13fb6012abdde7bdd0c66c1fd4d45e 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/notifier.h>
 #include <linux/if_arp.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/compat.h>
 #include <net/ipip.h>
 #include <net/checksum.h>
 #include <net/netlink.h>
@@ -1434,6 +1435,81 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
        }
 }
 
+#ifdef CONFIG_COMPAT
+struct compat_sioc_sg_req {
+       struct in_addr src;
+       struct in_addr grp;
+       compat_ulong_t pktcnt;
+       compat_ulong_t bytecnt;
+       compat_ulong_t wrong_if;
+};
+
+struct compat_sioc_vif_req {
+       vifi_t  vifi;           /* Which iface */
+       compat_ulong_t icount;
+       compat_ulong_t ocount;
+       compat_ulong_t ibytes;
+       compat_ulong_t obytes;
+};
+
+int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
+{
+       struct compat_sioc_sg_req sr;
+       struct compat_sioc_vif_req vr;
+       struct vif_device *vif;
+       struct mfc_cache *c;
+       struct net *net = sock_net(sk);
+       struct mr_table *mrt;
+
+       mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
+       if (mrt == NULL)
+               return -ENOENT;
+
+       switch (cmd) {
+       case SIOCGETVIFCNT:
+               if (copy_from_user(&vr, arg, sizeof(vr)))
+                       return -EFAULT;
+               if (vr.vifi >= mrt->maxvif)
+                       return -EINVAL;
+               read_lock(&mrt_lock);
+               vif = &mrt->vif_table[vr.vifi];
+               if (VIF_EXISTS(mrt, vr.vifi)) {
+                       vr.icount = vif->pkt_in;
+                       vr.ocount = vif->pkt_out;
+                       vr.ibytes = vif->bytes_in;
+                       vr.obytes = vif->bytes_out;
+                       read_unlock(&mrt_lock);
+
+                       if (copy_to_user(arg, &vr, sizeof(vr)))
+                               return -EFAULT;
+                       return 0;
+               }
+               read_unlock(&mrt_lock);
+               return -EADDRNOTAVAIL;
+       case SIOCGETSGCNT:
+               if (copy_from_user(&sr, arg, sizeof(sr)))
+                       return -EFAULT;
+
+               rcu_read_lock();
+               c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr);
+               if (c) {
+                       sr.pktcnt = c->mfc_un.res.pkt;
+                       sr.bytecnt = c->mfc_un.res.bytes;
+                       sr.wrong_if = c->mfc_un.res.wrong_if;
+                       rcu_read_unlock();
+
+                       if (copy_to_user(arg, &sr, sizeof(sr)))
+                               return -EFAULT;
+                       return 0;
+               }
+               rcu_read_unlock();
+               return -EADDRNOTAVAIL;
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+#endif
+
 
 static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
@@ -1542,8 +1618,8 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
                        .fl4_tos = RT_TOS(iph->tos),
                        .proto = IPPROTO_IPIP
                };
-
-               if (ip_route_output_key(net, &rt, &fl))
+               rt = ip_route_output_key(net, &fl);
+               if (IS_ERR(rt))
                        goto out_free;
                encap = sizeof(struct iphdr);
        } else {
@@ -1553,8 +1629,8 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
                        .fl4_tos = RT_TOS(iph->tos),
                        .proto = IPPROTO_IPIP
                };
-
-               if (ip_route_output_key(net, &rt, &fl))
+               rt = ip_route_output_key(net, &fl);
+               if (IS_ERR(rt))
                        goto out_free;
        }
 
@@ -1737,12 +1813,22 @@ int ip_mr_input(struct sk_buff *skb)
        if (IPCB(skb)->flags & IPSKB_FORWARDED)
                goto dont_forward;
 
-       err = ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt);
-       if (err < 0) {
-               kfree_skb(skb);
-               return err;
+       {
+               struct rtable *rt = skb_rtable(skb);
+               struct flowi fl = {
+                       .fl4_dst = rt->rt_key_dst,
+                       .fl4_src = rt->rt_key_src,
+                       .fl4_tos = rt->rt_tos,
+                       .oif = rt->rt_oif,
+                       .iif = rt->rt_iif,
+                       .mark = rt->rt_mark,
+               };
+               err = ipmr_fib_lookup(net, &fl, &mrt);
+               if (err < 0) {
+                       kfree_skb(skb);
+                       return err;
+               }
        }
-
        if (!local) {
                if (IPCB(skb)->opt.router_alert) {
                        if (ip_call_ra_chain(skb))
@@ -1870,9 +1956,19 @@ int pim_rcv_v1(struct sk_buff *skb)
 
        pim = igmp_hdr(skb);
 
-       if (ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt) < 0)
-               goto drop;
-
+       {
+               struct rtable *rt = skb_rtable(skb);
+               struct flowi fl = {
+                       .fl4_dst = rt->rt_key_dst,
+                       .fl4_src = rt->rt_key_src,
+                       .fl4_tos = rt->rt_tos,
+                       .oif = rt->rt_oif,
+                       .iif = rt->rt_iif,
+                       .mark = rt->rt_mark,
+               };
+               if (ipmr_fib_lookup(net, &fl, &mrt) < 0)
+                       goto drop;
+       }
        if (!mrt->mroute_do_pim ||
            pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
                goto drop;
@@ -1902,9 +1998,19 @@ static int pim_rcv(struct sk_buff *skb)
             csum_fold(skb_checksum(skb, 0, skb->len, 0))))
                goto drop;
 
-       if (ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt) < 0)
-               goto drop;
-
+       {
+               struct rtable *rt = skb_rtable(skb);
+               struct flowi fl = {
+                       .fl4_dst = rt->rt_key_dst,
+                       .fl4_src = rt->rt_key_src,
+                       .fl4_tos = rt->rt_tos,
+                       .oif = rt->rt_oif,
+                       .iif = rt->rt_iif,
+                       .mark = rt->rt_mark,
+               };
+               if (ipmr_fib_lookup(net, &fl, &mrt) < 0)
+                       goto drop;
+       }
        if (__pim_rcv(mrt, skb, sizeof(*pim))) {
 drop:
                kfree_skb(skb);