.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Linux IPv6 multicast routing support for BSD pim6sd |
---|
3 | 4 | * Based on net/ipv4/ipmr.c. |
---|
.. | .. |
---|
8 | 9 | * 6WIND, Paris, France |
---|
9 | 10 | * Copyright (C)2007,2008 USAGI/WIDE Project |
---|
10 | 11 | * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> |
---|
11 | | - * |
---|
12 | | - * This program is free software; you can redistribute it and/or |
---|
13 | | - * modify it under the terms of the GNU General Public License |
---|
14 | | - * as published by the Free Software Foundation; either version |
---|
15 | | - * 2 of the License, or (at your option) any later version. |
---|
16 | | - * |
---|
17 | 12 | */ |
---|
18 | 13 | |
---|
19 | 14 | #include <linux/uaccess.h> |
---|
.. | .. |
---|
88 | 83 | static void ip6mr_free_table(struct mr_table *mrt); |
---|
89 | 84 | |
---|
90 | 85 | static void ip6_mr_forward(struct net *net, struct mr_table *mrt, |
---|
91 | | - struct sk_buff *skb, struct mfc6_cache *cache); |
---|
| 86 | + struct net_device *dev, struct sk_buff *skb, |
---|
| 87 | + struct mfc6_cache *cache); |
---|
92 | 88 | static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, |
---|
93 | 89 | mifi_t mifi, int assert); |
---|
94 | 90 | static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc, |
---|
.. | .. |
---|
96 | 92 | static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt); |
---|
97 | 93 | static int ip6mr_rtm_dumproute(struct sk_buff *skb, |
---|
98 | 94 | struct netlink_callback *cb); |
---|
99 | | -static void mroute_clean_tables(struct mr_table *mrt, bool all); |
---|
| 95 | +static void mroute_clean_tables(struct mr_table *mrt, int flags); |
---|
100 | 96 | static void ipmr_expire_process(struct timer_list *t); |
---|
101 | 97 | |
---|
102 | 98 | #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES |
---|
103 | 99 | #define ip6mr_for_each_table(mrt, net) \ |
---|
104 | | - list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list) |
---|
| 100 | + list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list, \ |
---|
| 101 | + lockdep_rtnl_is_held() || \ |
---|
| 102 | + list_empty(&net->ipv6.mr6_tables)) |
---|
105 | 103 | |
---|
106 | 104 | static struct mr_table *ip6mr_mr_table_iter(struct net *net, |
---|
107 | 105 | struct mr_table *mrt) |
---|
.. | .. |
---|
141 | 139 | .flags = FIB_LOOKUP_NOREF, |
---|
142 | 140 | }; |
---|
143 | 141 | |
---|
| 142 | + /* update flow if oif or iif point to device enslaved to l3mdev */ |
---|
| 143 | + l3mdev_update_flow(net, flowi6_to_flowi(flp6)); |
---|
| 144 | + |
---|
144 | 145 | err = fib_rules_lookup(net->ipv6.mr6_rules_ops, |
---|
145 | 146 | flowi6_to_flowi(flp6), 0, &arg); |
---|
146 | 147 | if (err < 0) |
---|
.. | .. |
---|
167 | 168 | return -EINVAL; |
---|
168 | 169 | } |
---|
169 | 170 | |
---|
170 | | - mrt = ip6mr_get_table(rule->fr_net, rule->table); |
---|
| 171 | + arg->table = fib_rule_get_table(rule, arg); |
---|
| 172 | + |
---|
| 173 | + mrt = ip6mr_get_table(rule->fr_net, arg->table); |
---|
171 | 174 | if (!mrt) |
---|
172 | 175 | return -EAGAIN; |
---|
173 | 176 | res->mrt = mrt; |
---|
.. | .. |
---|
266 | 269 | rtnl_unlock(); |
---|
267 | 270 | } |
---|
268 | 271 | |
---|
269 | | -static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb) |
---|
| 272 | +static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb, |
---|
| 273 | + struct netlink_ext_ack *extack) |
---|
270 | 274 | { |
---|
271 | | - return fib_rules_dump(net, nb, RTNL_FAMILY_IP6MR); |
---|
| 275 | + return fib_rules_dump(net, nb, RTNL_FAMILY_IP6MR, extack); |
---|
272 | 276 | } |
---|
273 | 277 | |
---|
274 | 278 | static unsigned int ip6mr_rules_seq_read(struct net *net) |
---|
.. | .. |
---|
325 | 329 | rtnl_unlock(); |
---|
326 | 330 | } |
---|
327 | 331 | |
---|
328 | | -static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb) |
---|
| 332 | +static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb, |
---|
| 333 | + struct netlink_ext_ack *extack) |
---|
329 | 334 | { |
---|
330 | 335 | return 0; |
---|
331 | 336 | } |
---|
.. | .. |
---|
351 | 356 | .key_offset = offsetof(struct mfc6_cache, cmparg), |
---|
352 | 357 | .key_len = sizeof(struct mfc6_cache_cmp_arg), |
---|
353 | 358 | .nelem_hint = 3, |
---|
354 | | - .locks_mul = 1, |
---|
355 | 359 | .obj_cmpfn = ip6mr_hash_cmp, |
---|
356 | 360 | .automatic_shrinking = true, |
---|
357 | 361 | }; |
---|
.. | .. |
---|
389 | 393 | static void ip6mr_free_table(struct mr_table *mrt) |
---|
390 | 394 | { |
---|
391 | 395 | del_timer_sync(&mrt->ipmr_expire_timer); |
---|
392 | | - mroute_clean_tables(mrt, true); |
---|
| 396 | + mroute_clean_tables(mrt, MRT6_FLUSH_MIFS | MRT6_FLUSH_MIFS_STATIC | |
---|
| 397 | + MRT6_FLUSH_MFC | MRT6_FLUSH_MFC_STATIC); |
---|
393 | 398 | rhltable_destroy(&mrt->mfc_hash); |
---|
394 | 399 | kfree(mrt); |
---|
395 | 400 | } |
---|
.. | .. |
---|
658 | 663 | return NULL; |
---|
659 | 664 | } |
---|
660 | 665 | |
---|
661 | | - if (dev_open(dev)) |
---|
| 666 | + if (dev_open(dev, NULL)) |
---|
662 | 667 | goto failure; |
---|
663 | 668 | |
---|
664 | 669 | dev_hold(dev); |
---|
.. | .. |
---|
735 | 740 | |
---|
736 | 741 | in6_dev = __in6_dev_get(dev); |
---|
737 | 742 | if (in6_dev) { |
---|
738 | | - in6_dev->cnf.mc_forwarding--; |
---|
| 743 | + atomic_dec(&in6_dev->cnf.mc_forwarding); |
---|
739 | 744 | inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF, |
---|
740 | 745 | NETCONFA_MC_FORWARDING, |
---|
741 | 746 | dev->ifindex, &in6_dev->cnf); |
---|
.. | .. |
---|
903 | 908 | |
---|
904 | 909 | in6_dev = __in6_dev_get(dev); |
---|
905 | 910 | if (in6_dev) { |
---|
906 | | - in6_dev->cnf.mc_forwarding++; |
---|
| 911 | + atomic_inc(&in6_dev->cnf.mc_forwarding); |
---|
907 | 912 | inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF, |
---|
908 | 913 | NETCONFA_MC_FORWARDING, |
---|
909 | 914 | dev->ifindex, &in6_dev->cnf); |
---|
.. | .. |
---|
1023 | 1028 | } |
---|
1024 | 1029 | rtnl_unicast(skb, net, NETLINK_CB(skb).portid); |
---|
1025 | 1030 | } else |
---|
1026 | | - ip6_mr_forward(net, mrt, skb, c); |
---|
| 1031 | + ip6_mr_forward(net, mrt, skb->dev, skb, c); |
---|
1027 | 1032 | } |
---|
1028 | 1033 | } |
---|
1029 | 1034 | |
---|
.. | .. |
---|
1064 | 1069 | And all this only to mangle msg->im6_msgtype and |
---|
1065 | 1070 | to set msg->im6_mbz to "mbz" :-) |
---|
1066 | 1071 | */ |
---|
1067 | | - skb_push(skb, -skb_network_offset(pkt)); |
---|
| 1072 | + __skb_pull(skb, skb_network_offset(pkt)); |
---|
1068 | 1073 | |
---|
1069 | 1074 | skb_push(skb, sizeof(*msg)); |
---|
1070 | 1075 | skb_reset_transport_header(skb); |
---|
.. | .. |
---|
1129 | 1134 | |
---|
1130 | 1135 | /* Queue a packet for resolution. It gets locked cache entry! */ |
---|
1131 | 1136 | static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi, |
---|
1132 | | - struct sk_buff *skb) |
---|
| 1137 | + struct sk_buff *skb, struct net_device *dev) |
---|
1133 | 1138 | { |
---|
1134 | 1139 | struct mfc6_cache *c; |
---|
1135 | 1140 | bool found = false; |
---|
.. | .. |
---|
1149 | 1154 | * Create a new entry if allowable |
---|
1150 | 1155 | */ |
---|
1151 | 1156 | |
---|
1152 | | - if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 || |
---|
1153 | | - (c = ip6mr_cache_alloc_unres()) == NULL) { |
---|
| 1157 | + c = ip6mr_cache_alloc_unres(); |
---|
| 1158 | + if (!c) { |
---|
1154 | 1159 | spin_unlock_bh(&mfc_unres_lock); |
---|
1155 | 1160 | |
---|
1156 | 1161 | kfree_skb(skb); |
---|
.. | .. |
---|
1189 | 1194 | kfree_skb(skb); |
---|
1190 | 1195 | err = -ENOBUFS; |
---|
1191 | 1196 | } else { |
---|
| 1197 | + if (dev) { |
---|
| 1198 | + skb->dev = dev; |
---|
| 1199 | + skb->skb_iif = dev->ifindex; |
---|
| 1200 | + } |
---|
1192 | 1201 | skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb); |
---|
1193 | 1202 | err = 0; |
---|
1194 | 1203 | } |
---|
.. | .. |
---|
1253 | 1262 | return net->ipv6.ipmr_seq + ip6mr_rules_seq_read(net); |
---|
1254 | 1263 | } |
---|
1255 | 1264 | |
---|
1256 | | -static int ip6mr_dump(struct net *net, struct notifier_block *nb) |
---|
| 1265 | +static int ip6mr_dump(struct net *net, struct notifier_block *nb, |
---|
| 1266 | + struct netlink_ext_ack *extack) |
---|
1257 | 1267 | { |
---|
1258 | 1268 | return mr_dump(net, nb, RTNL_FAMILY_IP6MR, ip6mr_rules_dump, |
---|
1259 | | - ip6mr_mr_table_iter, &mrt_lock); |
---|
| 1269 | + ip6mr_mr_table_iter, &mrt_lock, extack); |
---|
1260 | 1270 | } |
---|
1261 | 1271 | |
---|
1262 | 1272 | static struct notifier_block ip6_mr_notifier = { |
---|
.. | .. |
---|
1488 | 1498 | * Close the multicast socket, and clear the vif tables etc |
---|
1489 | 1499 | */ |
---|
1490 | 1500 | |
---|
1491 | | -static void mroute_clean_tables(struct mr_table *mrt, bool all) |
---|
| 1501 | +static void mroute_clean_tables(struct mr_table *mrt, int flags) |
---|
1492 | 1502 | { |
---|
1493 | 1503 | struct mr_mfc *c, *tmp; |
---|
1494 | 1504 | LIST_HEAD(list); |
---|
1495 | 1505 | int i; |
---|
1496 | 1506 | |
---|
1497 | 1507 | /* Shut down all active vif entries */ |
---|
1498 | | - for (i = 0; i < mrt->maxvif; i++) { |
---|
1499 | | - if (!all && (mrt->vif_table[i].flags & VIFF_STATIC)) |
---|
1500 | | - continue; |
---|
1501 | | - mif6_delete(mrt, i, 0, &list); |
---|
| 1508 | + if (flags & (MRT6_FLUSH_MIFS | MRT6_FLUSH_MIFS_STATIC)) { |
---|
| 1509 | + for (i = 0; i < mrt->maxvif; i++) { |
---|
| 1510 | + if (((mrt->vif_table[i].flags & VIFF_STATIC) && |
---|
| 1511 | + !(flags & MRT6_FLUSH_MIFS_STATIC)) || |
---|
| 1512 | + (!(mrt->vif_table[i].flags & VIFF_STATIC) && !(flags & MRT6_FLUSH_MIFS))) |
---|
| 1513 | + continue; |
---|
| 1514 | + mif6_delete(mrt, i, 0, &list); |
---|
| 1515 | + } |
---|
| 1516 | + unregister_netdevice_many(&list); |
---|
1502 | 1517 | } |
---|
1503 | | - unregister_netdevice_many(&list); |
---|
1504 | 1518 | |
---|
1505 | 1519 | /* Wipe the cache */ |
---|
1506 | | - list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) { |
---|
1507 | | - if (!all && (c->mfc_flags & MFC_STATIC)) |
---|
1508 | | - continue; |
---|
1509 | | - rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params); |
---|
1510 | | - list_del_rcu(&c->list); |
---|
1511 | | - call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net), |
---|
1512 | | - FIB_EVENT_ENTRY_DEL, |
---|
1513 | | - (struct mfc6_cache *)c, mrt->id); |
---|
1514 | | - mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE); |
---|
1515 | | - mr_cache_put(c); |
---|
| 1520 | + if (flags & (MRT6_FLUSH_MFC | MRT6_FLUSH_MFC_STATIC)) { |
---|
| 1521 | + list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) { |
---|
| 1522 | + if (((c->mfc_flags & MFC_STATIC) && !(flags & MRT6_FLUSH_MFC_STATIC)) || |
---|
| 1523 | + (!(c->mfc_flags & MFC_STATIC) && !(flags & MRT6_FLUSH_MFC))) |
---|
| 1524 | + continue; |
---|
| 1525 | + rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params); |
---|
| 1526 | + list_del_rcu(&c->list); |
---|
| 1527 | + call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net), |
---|
| 1528 | + FIB_EVENT_ENTRY_DEL, |
---|
| 1529 | + (struct mfc6_cache *)c, mrt->id); |
---|
| 1530 | + mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE); |
---|
| 1531 | + mr_cache_put(c); |
---|
| 1532 | + } |
---|
1516 | 1533 | } |
---|
1517 | 1534 | |
---|
1518 | | - if (atomic_read(&mrt->cache_resolve_queue_len) != 0) { |
---|
1519 | | - spin_lock_bh(&mfc_unres_lock); |
---|
1520 | | - list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { |
---|
1521 | | - list_del(&c->list); |
---|
1522 | | - mr6_netlink_event(mrt, (struct mfc6_cache *)c, |
---|
1523 | | - RTM_DELROUTE); |
---|
1524 | | - ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c); |
---|
| 1535 | + if (flags & MRT6_FLUSH_MFC) { |
---|
| 1536 | + if (atomic_read(&mrt->cache_resolve_queue_len) != 0) { |
---|
| 1537 | + spin_lock_bh(&mfc_unres_lock); |
---|
| 1538 | + list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { |
---|
| 1539 | + list_del(&c->list); |
---|
| 1540 | + mr6_netlink_event(mrt, (struct mfc6_cache *)c, |
---|
| 1541 | + RTM_DELROUTE); |
---|
| 1542 | + ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c); |
---|
| 1543 | + } |
---|
| 1544 | + spin_unlock_bh(&mfc_unres_lock); |
---|
1525 | 1545 | } |
---|
1526 | | - spin_unlock_bh(&mfc_unres_lock); |
---|
1527 | 1546 | } |
---|
1528 | 1547 | } |
---|
1529 | 1548 | |
---|
.. | .. |
---|
1539 | 1558 | } else { |
---|
1540 | 1559 | rcu_assign_pointer(mrt->mroute_sk, sk); |
---|
1541 | 1560 | sock_set_flag(sk, SOCK_RCU_FREE); |
---|
1542 | | - net->ipv6.devconf_all->mc_forwarding++; |
---|
| 1561 | + atomic_inc(&net->ipv6.devconf_all->mc_forwarding); |
---|
1543 | 1562 | } |
---|
1544 | 1563 | write_unlock_bh(&mrt_lock); |
---|
1545 | 1564 | |
---|
.. | .. |
---|
1572 | 1591 | * so the RCU grace period before sk freeing |
---|
1573 | 1592 | * is guaranteed by sk_destruct() |
---|
1574 | 1593 | */ |
---|
1575 | | - net->ipv6.devconf_all->mc_forwarding--; |
---|
| 1594 | + atomic_dec(&net->ipv6.devconf_all->mc_forwarding); |
---|
1576 | 1595 | write_unlock_bh(&mrt_lock); |
---|
1577 | 1596 | inet6_netconf_notify_devconf(net, RTM_NEWNETCONF, |
---|
1578 | 1597 | NETCONFA_MC_FORWARDING, |
---|
1579 | 1598 | NETCONFA_IFINDEX_ALL, |
---|
1580 | 1599 | net->ipv6.devconf_all); |
---|
1581 | 1600 | |
---|
1582 | | - mroute_clean_tables(mrt, false); |
---|
| 1601 | + mroute_clean_tables(mrt, MRT6_FLUSH_MIFS | MRT6_FLUSH_MFC); |
---|
1583 | 1602 | err = 0; |
---|
1584 | 1603 | break; |
---|
1585 | 1604 | } |
---|
.. | .. |
---|
1612 | 1631 | * MOSPF/PIM router set up we can clean this up. |
---|
1613 | 1632 | */ |
---|
1614 | 1633 | |
---|
1615 | | -int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) |
---|
| 1634 | +int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval, |
---|
| 1635 | + unsigned int optlen) |
---|
1616 | 1636 | { |
---|
1617 | 1637 | int ret, parent = 0; |
---|
1618 | 1638 | struct mif6ctl vif; |
---|
.. | .. |
---|
1648 | 1668 | case MRT6_ADD_MIF: |
---|
1649 | 1669 | if (optlen < sizeof(vif)) |
---|
1650 | 1670 | return -EINVAL; |
---|
1651 | | - if (copy_from_user(&vif, optval, sizeof(vif))) |
---|
| 1671 | + if (copy_from_sockptr(&vif, optval, sizeof(vif))) |
---|
1652 | 1672 | return -EFAULT; |
---|
1653 | 1673 | if (vif.mif6c_mifi >= MAXMIFS) |
---|
1654 | 1674 | return -ENFILE; |
---|
.. | .. |
---|
1661 | 1681 | case MRT6_DEL_MIF: |
---|
1662 | 1682 | if (optlen < sizeof(mifi_t)) |
---|
1663 | 1683 | return -EINVAL; |
---|
1664 | | - if (copy_from_user(&mifi, optval, sizeof(mifi_t))) |
---|
| 1684 | + if (copy_from_sockptr(&mifi, optval, sizeof(mifi_t))) |
---|
1665 | 1685 | return -EFAULT; |
---|
1666 | 1686 | rtnl_lock(); |
---|
1667 | 1687 | ret = mif6_delete(mrt, mifi, 0, NULL); |
---|
.. | .. |
---|
1675 | 1695 | case MRT6_ADD_MFC: |
---|
1676 | 1696 | case MRT6_DEL_MFC: |
---|
1677 | 1697 | parent = -1; |
---|
1678 | | - /* fall through */ |
---|
| 1698 | + fallthrough; |
---|
1679 | 1699 | case MRT6_ADD_MFC_PROXY: |
---|
1680 | 1700 | case MRT6_DEL_MFC_PROXY: |
---|
1681 | 1701 | if (optlen < sizeof(mfc)) |
---|
1682 | 1702 | return -EINVAL; |
---|
1683 | | - if (copy_from_user(&mfc, optval, sizeof(mfc))) |
---|
| 1703 | + if (copy_from_sockptr(&mfc, optval, sizeof(mfc))) |
---|
1684 | 1704 | return -EFAULT; |
---|
1685 | 1705 | if (parent == 0) |
---|
1686 | 1706 | parent = mfc.mf6cc_parent; |
---|
.. | .. |
---|
1695 | 1715 | rtnl_unlock(); |
---|
1696 | 1716 | return ret; |
---|
1697 | 1717 | |
---|
| 1718 | + case MRT6_FLUSH: |
---|
| 1719 | + { |
---|
| 1720 | + int flags; |
---|
| 1721 | + |
---|
| 1722 | + if (optlen != sizeof(flags)) |
---|
| 1723 | + return -EINVAL; |
---|
| 1724 | + if (copy_from_sockptr(&flags, optval, sizeof(flags))) |
---|
| 1725 | + return -EFAULT; |
---|
| 1726 | + rtnl_lock(); |
---|
| 1727 | + mroute_clean_tables(mrt, flags); |
---|
| 1728 | + rtnl_unlock(); |
---|
| 1729 | + return 0; |
---|
| 1730 | + } |
---|
| 1731 | + |
---|
1698 | 1732 | /* |
---|
1699 | 1733 | * Control PIM assert (to activate pim will activate assert) |
---|
1700 | 1734 | */ |
---|
.. | .. |
---|
1704 | 1738 | |
---|
1705 | 1739 | if (optlen != sizeof(v)) |
---|
1706 | 1740 | return -EINVAL; |
---|
1707 | | - if (get_user(v, (int __user *)optval)) |
---|
| 1741 | + if (copy_from_sockptr(&v, optval, sizeof(v))) |
---|
1708 | 1742 | return -EFAULT; |
---|
1709 | 1743 | mrt->mroute_do_assert = v; |
---|
1710 | 1744 | return 0; |
---|
.. | .. |
---|
1717 | 1751 | |
---|
1718 | 1752 | if (optlen != sizeof(v)) |
---|
1719 | 1753 | return -EINVAL; |
---|
1720 | | - if (get_user(v, (int __user *)optval)) |
---|
| 1754 | + if (copy_from_sockptr(&v, optval, sizeof(v))) |
---|
1721 | 1755 | return -EFAULT; |
---|
1722 | 1756 | v = !!v; |
---|
1723 | 1757 | rtnl_lock(); |
---|
.. | .. |
---|
1738 | 1772 | |
---|
1739 | 1773 | if (optlen != sizeof(u32)) |
---|
1740 | 1774 | return -EINVAL; |
---|
1741 | | - if (get_user(v, (u32 __user *)optval)) |
---|
| 1775 | + if (copy_from_sockptr(&v, optval, sizeof(v))) |
---|
1742 | 1776 | return -EFAULT; |
---|
1743 | 1777 | /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */ |
---|
1744 | 1778 | if (v != RT_TABLE_DEFAULT && v >= 100000000) |
---|
.. | .. |
---|
1968 | 2002 | */ |
---|
1969 | 2003 | |
---|
1970 | 2004 | static int ip6mr_forward2(struct net *net, struct mr_table *mrt, |
---|
1971 | | - struct sk_buff *skb, struct mfc6_cache *c, int vifi) |
---|
| 2005 | + struct sk_buff *skb, int vifi) |
---|
1972 | 2006 | { |
---|
1973 | 2007 | struct ipv6hdr *ipv6h; |
---|
1974 | 2008 | struct vif_device *vif = &mrt->vif_table[vifi]; |
---|
.. | .. |
---|
2053 | 2087 | } |
---|
2054 | 2088 | |
---|
2055 | 2089 | static void ip6_mr_forward(struct net *net, struct mr_table *mrt, |
---|
2056 | | - struct sk_buff *skb, struct mfc6_cache *c) |
---|
| 2090 | + struct net_device *dev, struct sk_buff *skb, |
---|
| 2091 | + struct mfc6_cache *c) |
---|
2057 | 2092 | { |
---|
2058 | 2093 | int psend = -1; |
---|
2059 | 2094 | int vif, ct; |
---|
2060 | | - int true_vifi = ip6mr_find_vif(mrt, skb->dev); |
---|
| 2095 | + int true_vifi = ip6mr_find_vif(mrt, dev); |
---|
2061 | 2096 | |
---|
2062 | 2097 | vif = c->_c.mfc_parent; |
---|
2063 | 2098 | c->_c.mfc_un.res.pkt++; |
---|
.. | .. |
---|
2083 | 2118 | /* |
---|
2084 | 2119 | * Wrong interface: drop packet and (maybe) send PIM assert. |
---|
2085 | 2120 | */ |
---|
2086 | | - if (mrt->vif_table[vif].dev != skb->dev) { |
---|
| 2121 | + if (mrt->vif_table[vif].dev != dev) { |
---|
2087 | 2122 | c->_c.mfc_un.res.wrong_if++; |
---|
2088 | 2123 | |
---|
2089 | 2124 | if (true_vifi >= 0 && mrt->mroute_do_assert && |
---|
.. | .. |
---|
2133 | 2168 | if (psend != -1) { |
---|
2134 | 2169 | struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); |
---|
2135 | 2170 | if (skb2) |
---|
2136 | | - ip6mr_forward2(net, mrt, skb2, |
---|
2137 | | - c, psend); |
---|
| 2171 | + ip6mr_forward2(net, mrt, skb2, psend); |
---|
2138 | 2172 | } |
---|
2139 | 2173 | psend = ct; |
---|
2140 | 2174 | } |
---|
2141 | 2175 | } |
---|
2142 | 2176 | last_forward: |
---|
2143 | 2177 | if (psend != -1) { |
---|
2144 | | - ip6mr_forward2(net, mrt, skb, c, psend); |
---|
| 2178 | + ip6mr_forward2(net, mrt, skb, psend); |
---|
2145 | 2179 | return; |
---|
2146 | 2180 | } |
---|
2147 | 2181 | |
---|
.. | .. |
---|
2164 | 2198 | .flowi6_mark = skb->mark, |
---|
2165 | 2199 | }; |
---|
2166 | 2200 | int err; |
---|
| 2201 | + struct net_device *dev; |
---|
| 2202 | + |
---|
| 2203 | + /* skb->dev passed in is the master dev for vrfs. |
---|
| 2204 | + * Get the proper interface that does have a vif associated with it. |
---|
| 2205 | + */ |
---|
| 2206 | + dev = skb->dev; |
---|
| 2207 | + if (netif_is_l3_master(skb->dev)) { |
---|
| 2208 | + dev = dev_get_by_index_rcu(net, IPCB(skb)->iif); |
---|
| 2209 | + if (!dev) { |
---|
| 2210 | + kfree_skb(skb); |
---|
| 2211 | + return -ENODEV; |
---|
| 2212 | + } |
---|
| 2213 | + } |
---|
2167 | 2214 | |
---|
2168 | 2215 | err = ip6mr_fib_lookup(net, &fl6, &mrt); |
---|
2169 | 2216 | if (err < 0) { |
---|
.. | .. |
---|
2175 | 2222 | cache = ip6mr_cache_find(mrt, |
---|
2176 | 2223 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); |
---|
2177 | 2224 | if (!cache) { |
---|
2178 | | - int vif = ip6mr_find_vif(mrt, skb->dev); |
---|
| 2225 | + int vif = ip6mr_find_vif(mrt, dev); |
---|
2179 | 2226 | |
---|
2180 | 2227 | if (vif >= 0) |
---|
2181 | 2228 | cache = ip6mr_cache_find_any(mrt, |
---|
.. | .. |
---|
2189 | 2236 | if (!cache) { |
---|
2190 | 2237 | int vif; |
---|
2191 | 2238 | |
---|
2192 | | - vif = ip6mr_find_vif(mrt, skb->dev); |
---|
| 2239 | + vif = ip6mr_find_vif(mrt, dev); |
---|
2193 | 2240 | if (vif >= 0) { |
---|
2194 | | - int err = ip6mr_cache_unresolved(mrt, vif, skb); |
---|
| 2241 | + int err = ip6mr_cache_unresolved(mrt, vif, skb, dev); |
---|
2195 | 2242 | read_unlock(&mrt_lock); |
---|
2196 | 2243 | |
---|
2197 | 2244 | return err; |
---|
.. | .. |
---|
2201 | 2248 | return -ENODEV; |
---|
2202 | 2249 | } |
---|
2203 | 2250 | |
---|
2204 | | - ip6_mr_forward(net, mrt, skb, cache); |
---|
| 2251 | + ip6_mr_forward(net, mrt, dev, skb, cache); |
---|
2205 | 2252 | |
---|
2206 | 2253 | read_unlock(&mrt_lock); |
---|
2207 | 2254 | |
---|
.. | .. |
---|
2267 | 2314 | iph->saddr = rt->rt6i_src.addr; |
---|
2268 | 2315 | iph->daddr = rt->rt6i_dst.addr; |
---|
2269 | 2316 | |
---|
2270 | | - err = ip6mr_cache_unresolved(mrt, vif, skb2); |
---|
| 2317 | + err = ip6mr_cache_unresolved(mrt, vif, skb2, dev); |
---|
2271 | 2318 | read_unlock(&mrt_lock); |
---|
2272 | 2319 | |
---|
2273 | 2320 | return err; |
---|
.. | .. |
---|
2443 | 2490 | |
---|
2444 | 2491 | static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) |
---|
2445 | 2492 | { |
---|
| 2493 | + const struct nlmsghdr *nlh = cb->nlh; |
---|
| 2494 | + struct fib_dump_filter filter = {}; |
---|
| 2495 | + int err; |
---|
| 2496 | + |
---|
| 2497 | + if (cb->strict_check) { |
---|
| 2498 | + err = ip_valid_fib_dump_req(sock_net(skb->sk), nlh, |
---|
| 2499 | + &filter, cb); |
---|
| 2500 | + if (err < 0) |
---|
| 2501 | + return err; |
---|
| 2502 | + } |
---|
| 2503 | + |
---|
| 2504 | + if (filter.table_id) { |
---|
| 2505 | + struct mr_table *mrt; |
---|
| 2506 | + |
---|
| 2507 | + mrt = ip6mr_get_table(sock_net(skb->sk), filter.table_id); |
---|
| 2508 | + if (!mrt) { |
---|
| 2509 | + if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IP6MR) |
---|
| 2510 | + return skb->len; |
---|
| 2511 | + |
---|
| 2512 | + NL_SET_ERR_MSG_MOD(cb->extack, "MR table does not exist"); |
---|
| 2513 | + return -ENOENT; |
---|
| 2514 | + } |
---|
| 2515 | + err = mr_table_dump(mrt, skb, cb, _ip6mr_fill_mroute, |
---|
| 2516 | + &mfc_unres_lock, &filter); |
---|
| 2517 | + return skb->len ? : err; |
---|
| 2518 | + } |
---|
| 2519 | + |
---|
2446 | 2520 | return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter, |
---|
2447 | | - _ip6mr_fill_mroute, &mfc_unres_lock); |
---|
| 2521 | + _ip6mr_fill_mroute, &mfc_unres_lock, &filter); |
---|
2448 | 2522 | } |
---|