diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2011-01-29 11:15:56 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-01-30 04:14:38 -0500 |
commit | 709b46e8d90badda1898caea50483c12af178e96 (patch) | |
tree | 799b57704dda3684777fb57a6e413dabac78858c /net/ipv4/ipmr.c | |
parent | 13ad17745c2cbd437d9e24b2d97393e0be11c439 (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.c | 46 |
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 | ||
1439 | struct 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 | |||
1447 | int 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 | ||
1438 | static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr) | 1484 | static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr) |
1439 | { | 1485 | { |