ip6mr.c (6853f21f764b04e58df5e44629fec1fb8f3cbf2e) ip6mr.c (8571ab479a6e1ef46ead5ebee567e128a422767c)
1/*
2 * Linux IPv6 multicast routing support for BSD pim6sd
3 * Based on net/ipv4/ipmr.c.
4 *
5 * (c) 2004 Mickael Hoerdt, <hoerdt@clarinet.u-strasbg.fr>
6 * LSIIT Laboratory, Strasbourg, France
7 * (c) 2004 Jean-Philippe Andriot, <jean-philippe.andriot@6WIND.com>
8 * 6WIND, Paris, France

--- 44 unchanged lines hidden (view full) ---

53#include <linux/export.h>
54#include <net/ip6_checksum.h>
55#include <linux/netconf.h>
56
57struct mr6_table {
58 struct list_head list;
59 possible_net_t net;
60 u32 id;
1/*
2 * Linux IPv6 multicast routing support for BSD pim6sd
3 * Based on net/ipv4/ipmr.c.
4 *
5 * (c) 2004 Mickael Hoerdt, <hoerdt@clarinet.u-strasbg.fr>
6 * LSIIT Laboratory, Strasbourg, France
7 * (c) 2004 Jean-Philippe Andriot, <jean-philippe.andriot@6WIND.com>
8 * 6WIND, Paris, France

--- 44 unchanged lines hidden (view full) ---

53#include <linux/export.h>
54#include <net/ip6_checksum.h>
55#include <linux/netconf.h>
56
57struct mr6_table {
58 struct list_head list;
59 possible_net_t net;
60 u32 id;
61 struct sock *mroute6_sk;
61 struct sock __rcu *mroute6_sk;
62 struct timer_list ipmr_expire_timer;
63 struct list_head mfc6_unres_queue;
64 struct list_head mfc6_cache_array[MFC6_LINES];
65 struct vif_device vif6_table[MAXMIFS];
66 int maxvif;
67 atomic_t cache_resolve_queue_len;
68 bool mroute_do_assert;
69 bool mroute_do_pim;

--- 1046 unchanged lines hidden (view full) ---

1116 * Bounce a cache query up to pim6sd and netlink.
1117 *
1118 * Called under mrt_lock.
1119 */
1120
1121static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
1122 mifi_t mifi, int assert)
1123{
62 struct timer_list ipmr_expire_timer;
63 struct list_head mfc6_unres_queue;
64 struct list_head mfc6_cache_array[MFC6_LINES];
65 struct vif_device vif6_table[MAXMIFS];
66 int maxvif;
67 atomic_t cache_resolve_queue_len;
68 bool mroute_do_assert;
69 bool mroute_do_pim;

--- 1046 unchanged lines hidden (view full) ---

1116 * Bounce a cache query up to pim6sd and netlink.
1117 *
1118 * Called under mrt_lock.
1119 */
1120
1121static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
1122 mifi_t mifi, int assert)
1123{
1124 struct sock *mroute6_sk;
1124 struct sk_buff *skb;
1125 struct mrt6msg *msg;
1126 int ret;
1127
1128#ifdef CONFIG_IPV6_PIMSM_V2
1129 if (assert == MRT6MSG_WHOLEPKT)
1130 skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt)
1131 +sizeof(*msg));

--- 53 unchanged lines hidden (view full) ---

1185 msg->im6_pad = 0;
1186 msg->im6_src = ipv6_hdr(pkt)->saddr;
1187 msg->im6_dst = ipv6_hdr(pkt)->daddr;
1188
1189 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
1190 skb->ip_summed = CHECKSUM_UNNECESSARY;
1191 }
1192
1125 struct sk_buff *skb;
1126 struct mrt6msg *msg;
1127 int ret;
1128
1129#ifdef CONFIG_IPV6_PIMSM_V2
1130 if (assert == MRT6MSG_WHOLEPKT)
1131 skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt)
1132 +sizeof(*msg));

--- 53 unchanged lines hidden (view full) ---

1186 msg->im6_pad = 0;
1187 msg->im6_src = ipv6_hdr(pkt)->saddr;
1188 msg->im6_dst = ipv6_hdr(pkt)->daddr;
1189
1190 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
1191 skb->ip_summed = CHECKSUM_UNNECESSARY;
1192 }
1193
1193 if (!mrt->mroute6_sk) {
1194 rcu_read_lock();
1195 mroute6_sk = rcu_dereference(mrt->mroute6_sk);
1196 if (!mroute6_sk) {
1197 rcu_read_unlock();
1194 kfree_skb(skb);
1195 return -EINVAL;
1196 }
1197
1198 mrt6msg_netlink_event(mrt, skb);
1199
1198 kfree_skb(skb);
1199 return -EINVAL;
1200 }
1201
1202 mrt6msg_netlink_event(mrt, skb);
1203
1200 /*
1201 * Deliver to user space multicast routing algorithms
1202 */
1203 ret = sock_queue_rcv_skb(mrt->mroute6_sk, skb);
1204 /* Deliver to user space multicast routing algorithms */
1205 ret = sock_queue_rcv_skb(mroute6_sk, skb);
1206 rcu_read_unlock();
1204 if (ret < 0) {
1205 net_warn_ratelimited("mroute6: pending queue full, dropping entries\n");
1206 kfree_skb(skb);
1207 }
1208
1209 return ret;
1210}
1211

--- 367 unchanged lines hidden (view full) ---

1579
1580static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk)
1581{
1582 int err = 0;
1583 struct net *net = sock_net(sk);
1584
1585 rtnl_lock();
1586 write_lock_bh(&mrt_lock);
1207 if (ret < 0) {
1208 net_warn_ratelimited("mroute6: pending queue full, dropping entries\n");
1209 kfree_skb(skb);
1210 }
1211
1212 return ret;
1213}
1214

--- 367 unchanged lines hidden (view full) ---

1582
1583static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk)
1584{
1585 int err = 0;
1586 struct net *net = sock_net(sk);
1587
1588 rtnl_lock();
1589 write_lock_bh(&mrt_lock);
1587 if (likely(mrt->mroute6_sk == NULL)) {
1588 mrt->mroute6_sk = sk;
1589 net->ipv6.devconf_all->mc_forwarding++;
1590 } else {
1590 if (rtnl_dereference(mrt->mroute6_sk)) {
1591 err = -EADDRINUSE;
1591 err = -EADDRINUSE;
1592 } else {
1593 rcu_assign_pointer(mrt->mroute6_sk, sk);
1594 net->ipv6.devconf_all->mc_forwarding++;
1592 }
1593 write_unlock_bh(&mrt_lock);
1594
1595 if (!err)
1596 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
1597 NETCONFA_MC_FORWARDING,
1598 NETCONFA_IFINDEX_ALL,
1599 net->ipv6.devconf_all);

--- 9 unchanged lines hidden (view full) ---

1609 struct mr6_table *mrt;
1610
1611 if (sk->sk_type != SOCK_RAW ||
1612 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1613 return err;
1614
1615 rtnl_lock();
1616 ip6mr_for_each_table(mrt, net) {
1595 }
1596 write_unlock_bh(&mrt_lock);
1597
1598 if (!err)
1599 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
1600 NETCONFA_MC_FORWARDING,
1601 NETCONFA_IFINDEX_ALL,
1602 net->ipv6.devconf_all);

--- 9 unchanged lines hidden (view full) ---

1612 struct mr6_table *mrt;
1613
1614 if (sk->sk_type != SOCK_RAW ||
1615 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1616 return err;
1617
1618 rtnl_lock();
1619 ip6mr_for_each_table(mrt, net) {
1617 if (sk == mrt->mroute6_sk) {
1620 if (sk == rtnl_dereference(mrt->mroute6_sk)) {
1618 write_lock_bh(&mrt_lock);
1621 write_lock_bh(&mrt_lock);
1619 mrt->mroute6_sk = NULL;
1622 RCU_INIT_POINTER(mrt->mroute6_sk, NULL);
1620 net->ipv6.devconf_all->mc_forwarding--;
1621 write_unlock_bh(&mrt_lock);
1622 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
1623 NETCONFA_MC_FORWARDING,
1624 NETCONFA_IFINDEX_ALL,
1625 net->ipv6.devconf_all);
1626
1627 mroute_clean_tables(mrt, false);
1628 err = 0;
1629 break;
1630 }
1631 }
1632 rtnl_unlock();
1623 net->ipv6.devconf_all->mc_forwarding--;
1624 write_unlock_bh(&mrt_lock);
1625 inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
1626 NETCONFA_MC_FORWARDING,
1627 NETCONFA_IFINDEX_ALL,
1628 net->ipv6.devconf_all);
1629
1630 mroute_clean_tables(mrt, false);
1631 err = 0;
1632 break;
1633 }
1634 }
1635 rtnl_unlock();
1636 synchronize_rcu();
1633
1634 return err;
1635}
1636
1637
1638 return err;
1639}
1640
1637struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
1641bool mroute6_is_socket(struct net *net, struct sk_buff *skb)
1638{
1639 struct mr6_table *mrt;
1640 struct flowi6 fl6 = {
1641 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
1642 .flowi6_oif = skb->dev->ifindex,
1643 .flowi6_mark = skb->mark,
1644 };
1645
1646 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
1647 return NULL;
1648
1642{
1643 struct mr6_table *mrt;
1644 struct flowi6 fl6 = {
1645 .flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX,
1646 .flowi6_oif = skb->dev->ifindex,
1647 .flowi6_mark = skb->mark,
1648 };
1649
1650 if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
1651 return NULL;
1652
1649 return mrt->mroute6_sk;
1653 return rcu_access_pointer(mrt->mroute6_sk);
1650}
1654}
1655EXPORT_SYMBOL(mroute6_is_socket);
1651
1652/*
1653 * Socket options and virtual interface manipulation. The whole
1654 * virtual interface system is a complete heap, but unfortunately
1655 * that's how BSD mrouted happens to think. Maybe one day with a proper
1656 * MOSPF/PIM router set up we can clean this up.
1657 */
1658

--- 10 unchanged lines hidden (view full) ---

1669 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1670 return -EOPNOTSUPP;
1671
1672 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1673 if (!mrt)
1674 return -ENOENT;
1675
1676 if (optname != MRT6_INIT) {
1656
1657/*
1658 * Socket options and virtual interface manipulation. The whole
1659 * virtual interface system is a complete heap, but unfortunately
1660 * that's how BSD mrouted happens to think. Maybe one day with a proper
1661 * MOSPF/PIM router set up we can clean this up.
1662 */
1663

--- 10 unchanged lines hidden (view full) ---

1674 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1675 return -EOPNOTSUPP;
1676
1677 mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
1678 if (!mrt)
1679 return -ENOENT;
1680
1681 if (optname != MRT6_INIT) {
1677 if (sk != mrt->mroute6_sk && !ns_capable(net->user_ns, CAP_NET_ADMIN))
1682 if (sk != rcu_access_pointer(mrt->mroute6_sk) &&
1683 !ns_capable(net->user_ns, CAP_NET_ADMIN))
1678 return -EACCES;
1679 }
1680
1681 switch (optname) {
1682 case MRT6_INIT:
1683 if (optlen < sizeof(int))
1684 return -EINVAL;
1685

--- 5 unchanged lines hidden (view full) ---

1691 case MRT6_ADD_MIF:
1692 if (optlen < sizeof(vif))
1693 return -EINVAL;
1694 if (copy_from_user(&vif, optval, sizeof(vif)))
1695 return -EFAULT;
1696 if (vif.mif6c_mifi >= MAXMIFS)
1697 return -ENFILE;
1698 rtnl_lock();
1684 return -EACCES;
1685 }
1686
1687 switch (optname) {
1688 case MRT6_INIT:
1689 if (optlen < sizeof(int))
1690 return -EINVAL;
1691

--- 5 unchanged lines hidden (view full) ---

1697 case MRT6_ADD_MIF:
1698 if (optlen < sizeof(vif))
1699 return -EINVAL;
1700 if (copy_from_user(&vif, optval, sizeof(vif)))
1701 return -EFAULT;
1702 if (vif.mif6c_mifi >= MAXMIFS)
1703 return -ENFILE;
1704 rtnl_lock();
1699 ret = mif6_add(net, mrt, &vif, sk == mrt->mroute6_sk);
1705 ret = mif6_add(net, mrt, &vif,
1706 sk == rtnl_dereference(mrt->mroute6_sk));
1700 rtnl_unlock();
1701 return ret;
1702
1703 case MRT6_DEL_MIF:
1704 if (optlen < sizeof(mifi_t))
1705 return -EINVAL;
1706 if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
1707 return -EFAULT;

--- 18 unchanged lines hidden (view full) ---

1726 return -EFAULT;
1727 if (parent == 0)
1728 parent = mfc.mf6cc_parent;
1729 rtnl_lock();
1730 if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
1731 ret = ip6mr_mfc_delete(mrt, &mfc, parent);
1732 else
1733 ret = ip6mr_mfc_add(net, mrt, &mfc,
1707 rtnl_unlock();
1708 return ret;
1709
1710 case MRT6_DEL_MIF:
1711 if (optlen < sizeof(mifi_t))
1712 return -EINVAL;
1713 if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
1714 return -EFAULT;

--- 18 unchanged lines hidden (view full) ---

1733 return -EFAULT;
1734 if (parent == 0)
1735 parent = mfc.mf6cc_parent;
1736 rtnl_lock();
1737 if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
1738 ret = ip6mr_mfc_delete(mrt, &mfc, parent);
1739 else
1740 ret = ip6mr_mfc_add(net, mrt, &mfc,
1734 sk == mrt->mroute6_sk, parent);
1741 sk ==
1742 rtnl_dereference(mrt->mroute6_sk),
1743 parent);
1735 rtnl_unlock();
1736 return ret;
1737
1738 /*
1739 * Control PIM assert (to activate pim will activate assert)
1740 */
1741 case MRT6_ASSERT:
1742 {

--- 35 unchanged lines hidden (view full) ---

1778
1779 if (optlen != sizeof(u32))
1780 return -EINVAL;
1781 if (get_user(v, (u32 __user *)optval))
1782 return -EFAULT;
1783 /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
1784 if (v != RT_TABLE_DEFAULT && v >= 100000000)
1785 return -EINVAL;
1744 rtnl_unlock();
1745 return ret;
1746
1747 /*
1748 * Control PIM assert (to activate pim will activate assert)
1749 */
1750 case MRT6_ASSERT:
1751 {

--- 35 unchanged lines hidden (view full) ---

1787
1788 if (optlen != sizeof(u32))
1789 return -EINVAL;
1790 if (get_user(v, (u32 __user *)optval))
1791 return -EFAULT;
1792 /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
1793 if (v != RT_TABLE_DEFAULT && v >= 100000000)
1794 return -EINVAL;
1786 if (sk == mrt->mroute6_sk)
1795 if (sk == rcu_access_pointer(mrt->mroute6_sk))
1787 return -EBUSY;
1788
1789 rtnl_lock();
1790 ret = 0;
1791 if (!ip6mr_new_table(net, v))
1792 ret = -ENOMEM;
1793 raw6_sk(sk)->ip6mr_table = v;
1794 rtnl_unlock();

--- 792 unchanged lines hidden ---
1796 return -EBUSY;
1797
1798 rtnl_lock();
1799 ret = 0;
1800 if (!ip6mr_new_table(net, v))
1801 ret = -ENOMEM;
1802 raw6_sk(sk)->ip6mr_table = v;
1803 rtnl_unlock();

--- 792 unchanged lines hidden ---