aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6mr.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6mr.c')
-rw-r--r--net/ipv6/ip6mr.c140
1 files changed, 107 insertions, 33 deletions
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 66078dad7fe8..82a809901f8e 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>
@@ -134,14 +135,15 @@ static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
134 return NULL; 135 return NULL;
135} 136}
136 137
137static int ip6mr_fib_lookup(struct net *net, struct flowi *flp, 138static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
138 struct mr6_table **mrt) 139 struct mr6_table **mrt)
139{ 140{
140 struct ip6mr_result res; 141 struct ip6mr_result res;
141 struct fib_lookup_arg arg = { .result = &res, }; 142 struct fib_lookup_arg arg = { .result = &res, };
142 int err; 143 int err;
143 144
144 err = fib_rules_lookup(net->ipv6.mr6_rules_ops, flp, 0, &arg); 145 err = fib_rules_lookup(net->ipv6.mr6_rules_ops,
146 flowi6_to_flowi(flp6), 0, &arg);
145 if (err < 0) 147 if (err < 0)
146 return err; 148 return err;
147 *mrt = res.mrt; 149 *mrt = res.mrt;
@@ -269,7 +271,7 @@ static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
269 return net->ipv6.mrt6; 271 return net->ipv6.mrt6;
270} 272}
271 273
272static int ip6mr_fib_lookup(struct net *net, struct flowi *flp, 274static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
273 struct mr6_table **mrt) 275 struct mr6_table **mrt)
274{ 276{
275 *mrt = net->ipv6.mrt6; 277 *mrt = net->ipv6.mrt6;
@@ -616,9 +618,9 @@ static int pim6_rcv(struct sk_buff *skb)
616 struct net_device *reg_dev = NULL; 618 struct net_device *reg_dev = NULL;
617 struct net *net = dev_net(skb->dev); 619 struct net *net = dev_net(skb->dev);
618 struct mr6_table *mrt; 620 struct mr6_table *mrt;
619 struct flowi fl = { 621 struct flowi6 fl6 = {
620 .iif = skb->dev->ifindex, 622 .flowi6_iif = skb->dev->ifindex,
621 .mark = skb->mark, 623 .flowi6_mark = skb->mark,
622 }; 624 };
623 int reg_vif_num; 625 int reg_vif_num;
624 626
@@ -643,7 +645,7 @@ static int pim6_rcv(struct sk_buff *skb)
643 ntohs(encap->payload_len) + sizeof(*pim) > skb->len) 645 ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
644 goto drop; 646 goto drop;
645 647
646 if (ip6mr_fib_lookup(net, &fl, &mrt) < 0) 648 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
647 goto drop; 649 goto drop;
648 reg_vif_num = mrt->mroute_reg_vif_num; 650 reg_vif_num = mrt->mroute_reg_vif_num;
649 651
@@ -661,12 +663,13 @@ static int pim6_rcv(struct sk_buff *skb)
661 skb_pull(skb, (u8 *)encap - skb->data); 663 skb_pull(skb, (u8 *)encap - skb->data);
662 skb_reset_network_header(skb); 664 skb_reset_network_header(skb);
663 skb->protocol = htons(ETH_P_IPV6); 665 skb->protocol = htons(ETH_P_IPV6);
664 skb->ip_summed = 0; 666 skb->ip_summed = CHECKSUM_NONE;
665 skb->pkt_type = PACKET_HOST; 667 skb->pkt_type = PACKET_HOST;
666 668
667 skb_tunnel_rx(skb, reg_dev); 669 skb_tunnel_rx(skb, reg_dev);
668 670
669 netif_rx(skb); 671 netif_rx(skb);
672
670 dev_put(reg_dev); 673 dev_put(reg_dev);
671 return 0; 674 return 0;
672 drop: 675 drop:
@@ -685,14 +688,14 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
685{ 688{
686 struct net *net = dev_net(dev); 689 struct net *net = dev_net(dev);
687 struct mr6_table *mrt; 690 struct mr6_table *mrt;
688 struct flowi fl = { 691 struct flowi6 fl6 = {
689 .oif = dev->ifindex, 692 .flowi6_oif = dev->ifindex,
690 .iif = skb->skb_iif, 693 .flowi6_iif = skb->skb_iif,
691 .mark = skb->mark, 694 .flowi6_mark = skb->mark,
692 }; 695 };
693 int err; 696 int err;
694 697
695 err = ip6mr_fib_lookup(net, &fl, &mrt); 698 err = ip6mr_fib_lookup(net, &fl6, &mrt);
696 if (err < 0) 699 if (err < 0)
697 return err; 700 return err;
698 701
@@ -986,8 +989,8 @@ static int mif6_add(struct net *net, struct mr6_table *mrt,
986} 989}
987 990
988static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt, 991static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt,
989 struct in6_addr *origin, 992 const struct in6_addr *origin,
990 struct in6_addr *mcastgrp) 993 const struct in6_addr *mcastgrp)
991{ 994{
992 int line = MFC6_HASH(mcastgrp, origin); 995 int line = MFC6_HASH(mcastgrp, origin);
993 struct mfc6_cache *c; 996 struct mfc6_cache *c;
@@ -1037,7 +1040,6 @@ static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt,
1037 1040
1038 while((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) { 1041 while((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
1039 if (ipv6_hdr(skb)->version == 0) { 1042 if (ipv6_hdr(skb)->version == 0) {
1040 int err;
1041 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); 1043 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
1042 1044
1043 if (__ip6mr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) { 1045 if (__ip6mr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) {
@@ -1048,7 +1050,7 @@ static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt,
1048 skb_trim(skb, nlh->nlmsg_len); 1050 skb_trim(skb, nlh->nlmsg_len);
1049 ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE; 1051 ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE;
1050 } 1052 }
1051 err = rtnl_unicast(skb, net, NETLINK_CB(skb).pid); 1053 rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
1052 } else 1054 } else
1053 ip6_mr_forward(net, mrt, skb, c); 1055 ip6_mr_forward(net, mrt, skb, c);
1054 } 1056 }
@@ -1546,13 +1548,13 @@ int ip6mr_sk_done(struct sock *sk)
1546struct sock *mroute6_socket(struct net *net, struct sk_buff *skb) 1548struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
1547{ 1549{
1548 struct mr6_table *mrt; 1550 struct mr6_table *mrt;
1549 struct flowi fl = { 1551 struct flowi6 fl6 = {
1550 .iif = skb->skb_iif, 1552 .flowi6_iif = skb->skb_iif,
1551 .oif = skb->dev->ifindex, 1553 .flowi6_oif = skb->dev->ifindex,
1552 .mark = skb->mark, 1554 .flowi6_mark = skb->mark,
1553 }; 1555 };
1554 1556
1555 if (ip6mr_fib_lookup(net, &fl, &mrt) < 0) 1557 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
1556 return NULL; 1558 return NULL;
1557 1559
1558 return mrt->mroute6_sk; 1560 return mrt->mroute6_sk;
@@ -1803,6 +1805,80 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
1803 } 1805 }
1804} 1806}
1805 1807
1808#ifdef CONFIG_COMPAT
1809struct 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
1817struct 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
1825int 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
1806 1882
1807static inline int ip6mr_forward2_finish(struct sk_buff *skb) 1883static inline int ip6mr_forward2_finish(struct sk_buff *skb)
1808{ 1884{
@@ -1822,7 +1898,7 @@ static int ip6mr_forward2(struct net *net, struct mr6_table *mrt,
1822 struct mif_device *vif = &mrt->vif6_table[vifi]; 1898 struct mif_device *vif = &mrt->vif6_table[vifi];
1823 struct net_device *dev; 1899 struct net_device *dev;
1824 struct dst_entry *dst; 1900 struct dst_entry *dst;
1825 struct flowi fl; 1901 struct flowi6 fl6;
1826 1902
1827 if (vif->dev == NULL) 1903 if (vif->dev == NULL)
1828 goto out_free; 1904 goto out_free;
@@ -1840,14 +1916,12 @@ static int ip6mr_forward2(struct net *net, struct mr6_table *mrt,
1840 1916
1841 ipv6h = ipv6_hdr(skb); 1917 ipv6h = ipv6_hdr(skb);
1842 1918
1843 fl = (struct flowi) { 1919 fl6 = (struct flowi6) {
1844 .oif = vif->link, 1920 .flowi6_oif = vif->link,
1845 .nl_u = { .ip6_u = 1921 .daddr = ipv6h->daddr,
1846 { .daddr = ipv6h->daddr, }
1847 }
1848 }; 1922 };
1849 1923
1850 dst = ip6_route_output(net, NULL, &fl); 1924 dst = ip6_route_output(net, NULL, &fl6);
1851 if (!dst) 1925 if (!dst)
1852 goto out_free; 1926 goto out_free;
1853 1927
@@ -1970,13 +2044,13 @@ int ip6_mr_input(struct sk_buff *skb)
1970 struct mfc6_cache *cache; 2044 struct mfc6_cache *cache;
1971 struct net *net = dev_net(skb->dev); 2045 struct net *net = dev_net(skb->dev);
1972 struct mr6_table *mrt; 2046 struct mr6_table *mrt;
1973 struct flowi fl = { 2047 struct flowi6 fl6 = {
1974 .iif = skb->dev->ifindex, 2048 .flowi6_iif = skb->dev->ifindex,
1975 .mark = skb->mark, 2049 .flowi6_mark = skb->mark,
1976 }; 2050 };
1977 int err; 2051 int err;
1978 2052
1979 err = ip6mr_fib_lookup(net, &fl, &mrt); 2053 err = ip6mr_fib_lookup(net, &fl6, &mrt);
1980 if (err < 0) 2054 if (err < 0)
1981 return err; 2055 return err;
1982 2056