aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipmr.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2011-01-29 11:15:56 -0500
committerDavid S. Miller <davem@davemloft.net>2011-01-30 04:14:38 -0500
commit709b46e8d90badda1898caea50483c12af178e96 (patch)
tree799b57704dda3684777fb57a6e413dabac78858c /net/ipv4/ipmr.c
parent13ad17745c2cbd437d9e24b2d97393e0be11c439 (diff)
net: Add compat ioctl support for the ipv4 multicast ioctl SIOCGETSGCNT
SIOCGETSGCNT is not a unique ioctl value as it it maps tio SIOCPROTOPRIVATE +1, which unfortunately means the existing infrastructure for compat networking ioctls is insufficient. A trivial compact ioctl implementation would conflict with: SIOCAX25ADDUID SIOCAIPXPRISLT SIOCGETSGCNT_IN6 SIOCGETSGCNT SIOCRSSCAUSE SIOCX25SSUBSCRIP SIOCX25SDTEFACILITIES To make this work I have updated the compat_ioctl decode path to mirror the the normal ioctl decode path. I have added an ipv4 inet_compat_ioctl function so that I can have ipv4 specific compat ioctls. I have added a compat_ioctl function into struct proto so I can break out ioctls by which kind of ip socket I am using. I have added a compat_raw_ioctl function because SIOCGETSGCNT only works on raw sockets. I have added a ipmr_compat_ioctl that mirrors the normal ipmr_ioctl. This was necessary because unfortunately the struct layout for the SIOCGETSGCNT has unsigned longs in it so changes between 32bit and 64bit kernels. This change was sufficient to run a 32bit ip multicast routing daemon on a 64bit kernel. Reported-by: Bill Fenner <fenner@aristanetworks.com> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/ipmr.c')
-rw-r--r--net/ipv4/ipmr.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 3f3a9afd73e0..7e41ac0b9260 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -60,6 +60,7 @@
60#include <linux/notifier.h> 60#include <linux/notifier.h>
61#include <linux/if_arp.h> 61#include <linux/if_arp.h>
62#include <linux/netfilter_ipv4.h> 62#include <linux/netfilter_ipv4.h>
63#include <linux/compat.h>
63#include <net/ipip.h> 64#include <net/ipip.h>
64#include <net/checksum.h> 65#include <net/checksum.h>
65#include <net/netlink.h> 66#include <net/netlink.h>
@@ -1434,6 +1435,51 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
1434 } 1435 }
1435} 1436}
1436 1437
1438#ifdef CONFIG_COMPAT
1439struct compat_sioc_sg_req {
1440 struct in_addr src;
1441 struct in_addr grp;
1442 compat_ulong_t pktcnt;
1443 compat_ulong_t bytecnt;
1444 compat_ulong_t wrong_if;
1445};
1446
1447int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
1448{
1449 struct sioc_sg_req sr;
1450 struct mfc_cache *c;
1451 struct net *net = sock_net(sk);
1452 struct mr_table *mrt;
1453
1454 mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
1455 if (mrt == NULL)
1456 return -ENOENT;
1457
1458 switch (cmd) {
1459 case SIOCGETSGCNT:
1460 if (copy_from_user(&sr, arg, sizeof(sr)))
1461 return -EFAULT;
1462
1463 rcu_read_lock();
1464 c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr);
1465 if (c) {
1466 sr.pktcnt = c->mfc_un.res.pkt;
1467 sr.bytecnt = c->mfc_un.res.bytes;
1468 sr.wrong_if = c->mfc_un.res.wrong_if;
1469 rcu_read_unlock();
1470
1471 if (copy_to_user(arg, &sr, sizeof(sr)))
1472 return -EFAULT;
1473 return 0;
1474 }
1475 rcu_read_unlock();
1476 return -EADDRNOTAVAIL;
1477 default:
1478 return -ENOIOCTLCMD;
1479 }
1480}
1481#endif
1482
1437 1483
1438static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr) 1484static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
1439{ 1485{