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 --- |