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>
This commit is contained in:

committed by
David S. Miller

parent
13ad17745c
commit
709b46e8d9
@@ -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,51 @@ 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;
|
||||
};
|
||||
|
||||
int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
|
||||
{
|
||||
struct sioc_sg_req sr;
|
||||
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 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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user