diff options
Diffstat (limited to 'net/ipv6/ip6mr.c')
| -rw-r--r-- | net/ipv6/ip6mr.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 9fab274019c0..0e1d53bcf1e0 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <linux/seq_file.h> | 34 | #include <linux/seq_file.h> |
| 35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
| 36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
| 37 | #include <linux/compat.h> | ||
| 37 | #include <net/protocol.h> | 38 | #include <net/protocol.h> |
| 38 | #include <linux/skbuff.h> | 39 | #include <linux/skbuff.h> |
| 39 | #include <net/sock.h> | 40 | #include <net/sock.h> |
| @@ -1804,6 +1805,80 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) | |||
| 1804 | } | 1805 | } |
| 1805 | } | 1806 | } |
| 1806 | 1807 | ||
| 1808 | #ifdef CONFIG_COMPAT | ||
| 1809 | struct compat_sioc_sg_req6 { | ||
| 1810 | struct sockaddr_in6 src; | ||
| 1811 | struct sockaddr_in6 grp; | ||
| 1812 | compat_ulong_t pktcnt; | ||
| 1813 | compat_ulong_t bytecnt; | ||
| 1814 | compat_ulong_t wrong_if; | ||
| 1815 | }; | ||
| 1816 | |||
| 1817 | struct compat_sioc_mif_req6 { | ||
| 1818 | mifi_t mifi; | ||
| 1819 | compat_ulong_t icount; | ||
| 1820 | compat_ulong_t ocount; | ||
| 1821 | compat_ulong_t ibytes; | ||
| 1822 | compat_ulong_t obytes; | ||
| 1823 | }; | ||
| 1824 | |||
| 1825 | int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) | ||
| 1826 | { | ||
| 1827 | struct compat_sioc_sg_req6 sr; | ||
| 1828 | struct compat_sioc_mif_req6 vr; | ||
| 1829 | struct mif_device *vif; | ||
| 1830 | struct mfc6_cache *c; | ||
| 1831 | struct net *net = sock_net(sk); | ||
| 1832 | struct mr6_table *mrt; | ||
| 1833 | |||
| 1834 | mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT); | ||
| 1835 | if (mrt == NULL) | ||
| 1836 | return -ENOENT; | ||
| 1837 | |||
| 1838 | switch (cmd) { | ||
| 1839 | case SIOCGETMIFCNT_IN6: | ||
| 1840 | if (copy_from_user(&vr, arg, sizeof(vr))) | ||
| 1841 | return -EFAULT; | ||
| 1842 | if (vr.mifi >= mrt->maxvif) | ||
| 1843 | return -EINVAL; | ||
| 1844 | read_lock(&mrt_lock); | ||
| 1845 | vif = &mrt->vif6_table[vr.mifi]; | ||
| 1846 | if (MIF_EXISTS(mrt, vr.mifi)) { | ||
| 1847 | vr.icount = vif->pkt_in; | ||
| 1848 | vr.ocount = vif->pkt_out; | ||
| 1849 | vr.ibytes = vif->bytes_in; | ||
| 1850 | vr.obytes = vif->bytes_out; | ||
| 1851 | read_unlock(&mrt_lock); | ||
| 1852 | |||
| 1853 | if (copy_to_user(arg, &vr, sizeof(vr))) | ||
| 1854 | return -EFAULT; | ||
| 1855 | return 0; | ||
| 1856 | } | ||
| 1857 | read_unlock(&mrt_lock); | ||
| 1858 | return -EADDRNOTAVAIL; | ||
| 1859 | case SIOCGETSGCNT_IN6: | ||
| 1860 | if (copy_from_user(&sr, arg, sizeof(sr))) | ||
| 1861 | return -EFAULT; | ||
| 1862 | |||
| 1863 | read_lock(&mrt_lock); | ||
| 1864 | c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr); | ||
| 1865 | if (c) { | ||
| 1866 | sr.pktcnt = c->mfc_un.res.pkt; | ||
| 1867 | sr.bytecnt = c->mfc_un.res.bytes; | ||
| 1868 | sr.wrong_if = c->mfc_un.res.wrong_if; | ||
| 1869 | read_unlock(&mrt_lock); | ||
| 1870 | |||
| 1871 | if (copy_to_user(arg, &sr, sizeof(sr))) | ||
| 1872 | return -EFAULT; | ||
| 1873 | return 0; | ||
| 1874 | } | ||
| 1875 | read_unlock(&mrt_lock); | ||
| 1876 | return -EADDRNOTAVAIL; | ||
| 1877 | default: | ||
| 1878 | return -ENOIOCTLCMD; | ||
| 1879 | } | ||
| 1880 | } | ||
| 1881 | #endif | ||
| 1807 | 1882 | ||
| 1808 | static inline int ip6mr_forward2_finish(struct sk_buff *skb) | 1883 | static inline int ip6mr_forward2_finish(struct sk_buff *skb) |
| 1809 | { | 1884 | { |
