From: Antonio Quartulli <[email protected]>

ovpn_mp_alloc() tried to disable SEND_REDIRECTS on a multipeer
interface, but it runs from ovpn_net_init() (->ndo_init), which
register_netdevice() invokes before the NETDEV_REGISTER notifier
chain. The IPv4 in_device is only created when that notifier reaches
inetdev_event() -> inetdev_init(), so __in_dev_get_rtnl() always
returned NULL at ndo_init time and the whole redirect-disabling block
(both the per-device and the per-netns IPV4_DEVCONF_ALL write) was
dead. MP interfaces therefore kept emitting ICMP redirects.

Move the redirect-disabling to ovpn_newlink(), right after a
successful register_netdevice(): at that point the NETDEV_REGISTER
notifier has run and the in_device exists, and RTNL is held by the
newlink path so __in_dev_get_rtnl() is safe. A successful
register_netdevice() guarantees the in_device was created (otherwise
the notifier would have failed and registration rolled back), so the
in_device check is now a real guard rather than dead code.

The peer-table allocation stays in ovpn_mp_alloc()/->ndo_init, where
it belongs (it does not depend on the in_device and is freed in
->ndo_uninit).

Fixes: 05003b408c20 ("ovpn: implement multi-peer support")
Signed-off-by: Antonio Quartulli <[email protected]>
---
 drivers/net/ovpn/main.c | 41 ++++++++++++++++++++++++++---------------
 1 file changed, 26 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
index 9993c1dfe471..a881510aaac0 100644
--- a/drivers/net/ovpn/main.c
+++ b/drivers/net/ovpn/main.c
@@ -35,25 +35,11 @@ static void ovpn_priv_free(struct net_device *net)
 
 static int ovpn_mp_alloc(struct ovpn_priv *ovpn)
 {
-       struct in_device *dev_v4;
        int i;
 
        if (ovpn->mode != OVPN_MODE_MP)
                return 0;
 
-       dev_v4 = __in_dev_get_rtnl(ovpn->dev);
-       if (dev_v4) {
-               /* disable redirects as Linux gets confused by ovpn
-                * handling same-LAN routing.
-                * This happens because a multipeer interface is used as
-                * relay point between hosts in the same subnet, while
-                * in a classic LAN this would not be needed because the
-                * two hosts would be able to talk directly.
-                */
-               IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
-               IPV4_DEVCONF_ALL(dev_net(ovpn->dev), SEND_REDIRECTS) = false;
-       }
-
        /* the peer container is fairly large, therefore we allocate it only in
         * MP mode
         */
@@ -183,6 +169,8 @@ static int ovpn_newlink(struct net_device *dev,
        struct ovpn_priv *ovpn = netdev_priv(dev);
        struct nlattr **data = params->data;
        enum ovpn_mode mode = OVPN_MODE_P2P;
+       struct in_device *dev_v4;
+       int ret;
 
        if (data && data[IFLA_OVPN_MODE]) {
                mode = nla_get_u8(data[IFLA_OVPN_MODE]);
@@ -207,7 +195,30 @@ static int ovpn_newlink(struct net_device *dev,
        else
                netif_carrier_off(dev);
 
-       return register_netdevice(dev);
+       ret = register_netdevice(dev);
+       if (ret < 0)
+               return ret;
+
+       /* The IPv4 in_device is created by the NETDEV_REGISTER notifier, which
+        * fires inside register_netdevice() above, so this cannot be done
+        * earlier (e.g. in ndo_init). RTNL is held by the newlink path.
+        */
+       if (ovpn->mode == OVPN_MODE_MP) {
+               dev_v4 = __in_dev_get_rtnl(dev);
+               if (dev_v4) {
+                       /* disable redirects as Linux gets confused by ovpn
+                        * handling same-LAN routing.
+                        * This happens because a multipeer interface is used as
+                        * relay point between hosts in the same subnet, while
+                        * in a classic LAN this would not be needed because the
+                        * two hosts would be able to talk directly.
+                        */
+                       IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
+                       IPV4_DEVCONF_ALL(dev_net(dev), SEND_REDIRECTS) = false;
+               }
+       }
+
+       return 0;
 }
 
 static int ovpn_fill_info(struct sk_buff *skb, const struct net_device *dev)
-- 
2.53.0



_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to