l2tp: cleanup netlink tunnel create address handling
authorTom Parkin <tparkin@katalix.com>
Thu, 23 Jul 2020 11:29:54 +0000 (12:29 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 23 Jul 2020 18:54:40 +0000 (11:54 -0700)
When creating an L2TP tunnel using the netlink API, userspace must
either pass a socket FD for the tunnel to use (for managed tunnels),
or specify the tunnel source/destination address (for unmanaged
tunnels).

Since source/destination addresses may be AF_INET or AF_INET6, the l2tp
netlink code has conditionally compiled blocks to support IPv6.

Rather than embedding these directly into l2tp_nl_cmd_tunnel_create
(where it makes the code difficult to read and confuses checkpatch to
boot) split the handling of address-related attributes into a separate
function.

Signed-off-by: Tom Parkin <tparkin@katalix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/l2tp/l2tp_netlink.c

index 0021cc0..35716a6 100644 (file)
@@ -155,12 +155,38 @@ static int l2tp_session_notify(struct genl_family *family,
        return ret;
 }
 
+static int l2tp_nl_cmd_tunnel_create_get_addr(struct nlattr **attrs, struct l2tp_tunnel_cfg *cfg)
+{
+       if (attrs[L2TP_ATTR_UDP_SPORT])
+               cfg->local_udp_port = nla_get_u16(attrs[L2TP_ATTR_UDP_SPORT]);
+       if (attrs[L2TP_ATTR_UDP_DPORT])
+               cfg->peer_udp_port = nla_get_u16(attrs[L2TP_ATTR_UDP_DPORT]);
+       cfg->use_udp_checksums = nla_get_flag(attrs[L2TP_ATTR_UDP_CSUM]);
+
+       /* Must have either AF_INET or AF_INET6 address for source and destination */
+#if IS_ENABLED(CONFIG_IPV6)
+       if (attrs[L2TP_ATTR_IP6_SADDR] && attrs[L2TP_ATTR_IP6_DADDR]) {
+               cfg->local_ip6 = nla_data(attrs[L2TP_ATTR_IP6_SADDR]);
+               cfg->peer_ip6 = nla_data(attrs[L2TP_ATTR_IP6_DADDR]);
+               cfg->udp6_zero_tx_checksums = nla_get_flag(attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX]);
+               cfg->udp6_zero_rx_checksums = nla_get_flag(attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX]);
+               return 0;
+       }
+#endif
+       if (attrs[L2TP_ATTR_IP_SADDR] && attrs[L2TP_ATTR_IP_DADDR]) {
+               cfg->local_ip.s_addr = nla_get_in_addr(attrs[L2TP_ATTR_IP_SADDR]);
+               cfg->peer_ip.s_addr = nla_get_in_addr(attrs[L2TP_ATTR_IP_DADDR]);
+               return 0;
+       }
+       return -EINVAL;
+}
+
 static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info)
 {
        u32 tunnel_id;
        u32 peer_tunnel_id;
        int proto_version;
-       int fd;
+       int fd = -1;
        int ret = 0;
        struct l2tp_tunnel_cfg cfg = { 0, };
        struct l2tp_tunnel *tunnel;
@@ -191,33 +217,16 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info
        }
        cfg.encap = nla_get_u16(attrs[L2TP_ATTR_ENCAP_TYPE]);
 
-       fd = -1;
+       /* Managed tunnels take the tunnel socket from userspace.
+        * Unmanaged tunnels must call out the source and destination addresses
+        * for the kernel to create the tunnel socket itself.
+        */
        if (attrs[L2TP_ATTR_FD]) {
                fd = nla_get_u32(attrs[L2TP_ATTR_FD]);
        } else {
-#if IS_ENABLED(CONFIG_IPV6)
-               if (attrs[L2TP_ATTR_IP6_SADDR] && attrs[L2TP_ATTR_IP6_DADDR]) {
-                       cfg.local_ip6 = nla_data(attrs[L2TP_ATTR_IP6_SADDR]);
-                       cfg.peer_ip6 = nla_data(attrs[L2TP_ATTR_IP6_DADDR]);
-               } else
-#endif
-               if (attrs[L2TP_ATTR_IP_SADDR] && attrs[L2TP_ATTR_IP_DADDR]) {
-                       cfg.local_ip.s_addr = nla_get_in_addr(attrs[L2TP_ATTR_IP_SADDR]);
-                       cfg.peer_ip.s_addr = nla_get_in_addr(attrs[L2TP_ATTR_IP_DADDR]);
-               } else {
-                       ret = -EINVAL;
+               ret = l2tp_nl_cmd_tunnel_create_get_addr(attrs, &cfg);
+               if (ret < 0)
                        goto out;
-               }
-               if (attrs[L2TP_ATTR_UDP_SPORT])
-                       cfg.local_udp_port = nla_get_u16(attrs[L2TP_ATTR_UDP_SPORT]);
-               if (attrs[L2TP_ATTR_UDP_DPORT])
-                       cfg.peer_udp_port = nla_get_u16(attrs[L2TP_ATTR_UDP_DPORT]);
-               cfg.use_udp_checksums = nla_get_flag(attrs[L2TP_ATTR_UDP_CSUM]);
-
-#if IS_ENABLED(CONFIG_IPV6)
-               cfg.udp6_zero_tx_checksums = nla_get_flag(attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX]);
-               cfg.udp6_zero_rx_checksums = nla_get_flag(attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX]);
-#endif
        }
 
        if (attrs[L2TP_ATTR_DEBUG])