diff options
Diffstat (limited to 'net/ipv4/ipmr.c')
-rw-r--r-- | net/ipv4/ipmr.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 3f3a9afd73e0..8b65a12654e7 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,81 @@ 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 | struct compat_sioc_vif_req { | ||
1448 | vifi_t vifi; /* Which iface */ | ||
1449 | compat_ulong_t icount; | ||
1450 | compat_ulong_t ocount; | ||
1451 | compat_ulong_t ibytes; | ||
1452 | compat_ulong_t obytes; | ||
1453 | }; | ||
1454 | |||
1455 | int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) | ||
1456 | { | ||
1457 | struct compat_sioc_sg_req sr; | ||
1458 | struct compat_sioc_vif_req vr; | ||
1459 | struct vif_device *vif; | ||
1460 | struct mfc_cache *c; | ||
1461 | struct net *net = sock_net(sk); | ||
1462 | struct mr_table *mrt; | ||
1463 | |||
1464 | mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT); | ||
1465 | if (mrt == NULL) | ||
1466 | return -ENOENT; | ||
1467 | |||
1468 | switch (cmd) { | ||
1469 | case SIOCGETVIFCNT: | ||
1470 | if (copy_from_user(&vr, arg, sizeof(vr))) | ||
1471 | return -EFAULT; | ||
1472 | if (vr.vifi >= mrt->maxvif) | ||
1473 | return -EINVAL; | ||
1474 | read_lock(&mrt_lock); | ||
1475 | vif = &mrt->vif_table[vr.vifi]; | ||
1476 | if (VIF_EXISTS(mrt, vr.vifi)) { | ||
1477 | vr.icount = vif->pkt_in; | ||
1478 | vr.ocount = vif->pkt_out; | ||
1479 | vr.ibytes = vif->bytes_in; | ||
1480 | vr.obytes = vif->bytes_out; | ||
1481 | read_unlock(&mrt_lock); | ||
1482 | |||
1483 | if (copy_to_user(arg, &vr, sizeof(vr))) | ||
1484 | return -EFAULT; | ||
1485 | return 0; | ||
1486 | } | ||
1487 | read_unlock(&mrt_lock); | ||
1488 | return -EADDRNOTAVAIL; | ||
1489 | case SIOCGETSGCNT: | ||
1490 | if (copy_from_user(&sr, arg, sizeof(sr))) | ||
1491 | return -EFAULT; | ||
1492 | |||
1493 | rcu_read_lock(); | ||
1494 | c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr); | ||
1495 | if (c) { | ||
1496 | sr.pktcnt = c->mfc_un.res.pkt; | ||
1497 | sr.bytecnt = c->mfc_un.res.bytes; | ||
1498 | sr.wrong_if = c->mfc_un.res.wrong_if; | ||
1499 | rcu_read_unlock(); | ||
1500 | |||
1501 | if (copy_to_user(arg, &sr, sizeof(sr))) | ||
1502 | return -EFAULT; | ||
1503 | return 0; | ||
1504 | } | ||
1505 | rcu_read_unlock(); | ||
1506 | return -EADDRNOTAVAIL; | ||
1507 | default: | ||
1508 | return -ENOIOCTLCMD; | ||
1509 | } | ||
1510 | } | ||
1511 | #endif | ||
1512 | |||
1437 | 1513 | ||
1438 | static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr) | 1514 | static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr) |
1439 | { | 1515 | { |