Merge tag 'xfs-5.9-merge-8' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[linux-2.6-microblaze.git] / net / l2tp / l2tp_netlink.c
index ebb381c..def78ee 100644 (file)
@@ -1,6 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/*
- * L2TP netlink layer, for management
+/* L2TP netlink layer, for management
  *
  * Copyright (c) 2008,2009,2010 Katalix Systems Ltd
  *
@@ -27,7 +26,6 @@
 
 #include "l2tp_core.h"
 
-
 static struct genl_family l2tp_nl_family;
 
 static const struct genl_multicast_group l2tp_multicast_group[] = {
@@ -157,81 +155,82 @@ 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;
        struct net *net = genl_info_net(info);
+       struct nlattr **attrs = info->attrs;
 
-       if (!info->attrs[L2TP_ATTR_CONN_ID]) {
+       if (!attrs[L2TP_ATTR_CONN_ID]) {
                ret = -EINVAL;
                goto out;
        }
-       tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
+       tunnel_id = nla_get_u32(attrs[L2TP_ATTR_CONN_ID]);
 
-       if (!info->attrs[L2TP_ATTR_PEER_CONN_ID]) {
+       if (!attrs[L2TP_ATTR_PEER_CONN_ID]) {
                ret = -EINVAL;
                goto out;
        }
-       peer_tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_PEER_CONN_ID]);
+       peer_tunnel_id = nla_get_u32(attrs[L2TP_ATTR_PEER_CONN_ID]);
 
-       if (!info->attrs[L2TP_ATTR_PROTO_VERSION]) {
+       if (!attrs[L2TP_ATTR_PROTO_VERSION]) {
                ret = -EINVAL;
                goto out;
        }
-       proto_version = nla_get_u8(info->attrs[L2TP_ATTR_PROTO_VERSION]);
+       proto_version = nla_get_u8(attrs[L2TP_ATTR_PROTO_VERSION]);
 
-       if (!info->attrs[L2TP_ATTR_ENCAP_TYPE]) {
+       if (!attrs[L2TP_ATTR_ENCAP_TYPE]) {
                ret = -EINVAL;
                goto out;
        }
-       cfg.encap = nla_get_u16(info->attrs[L2TP_ATTR_ENCAP_TYPE]);
-
-       fd = -1;
-       if (info->attrs[L2TP_ATTR_FD]) {
-               fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]);
+       cfg.encap = nla_get_u16(attrs[L2TP_ATTR_ENCAP_TYPE]);
+
+       /* 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 (info->attrs[L2TP_ATTR_IP6_SADDR] &&
-                   info->attrs[L2TP_ATTR_IP6_DADDR]) {
-                       cfg.local_ip6 = nla_data(
-                               info->attrs[L2TP_ATTR_IP6_SADDR]);
-                       cfg.peer_ip6 = nla_data(
-                               info->attrs[L2TP_ATTR_IP6_DADDR]);
-               } else
-#endif
-               if (info->attrs[L2TP_ATTR_IP_SADDR] &&
-                   info->attrs[L2TP_ATTR_IP_DADDR]) {
-                       cfg.local_ip.s_addr = nla_get_in_addr(
-                               info->attrs[L2TP_ATTR_IP_SADDR]);
-                       cfg.peer_ip.s_addr = nla_get_in_addr(
-                               info->attrs[L2TP_ATTR_IP_DADDR]);
-               } else {
-                       ret = -EINVAL;
+               ret = l2tp_nl_cmd_tunnel_create_get_addr(attrs, &cfg);
+               if (ret < 0)
                        goto out;
-               }
-               if (info->attrs[L2TP_ATTR_UDP_SPORT])
-                       cfg.local_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_SPORT]);
-               if (info->attrs[L2TP_ATTR_UDP_DPORT])
-                       cfg.peer_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_DPORT]);
-               cfg.use_udp_checksums = nla_get_flag(
-                       info->attrs[L2TP_ATTR_UDP_CSUM]);
-
-#if IS_ENABLED(CONFIG_IPV6)
-               cfg.udp6_zero_tx_checksums = nla_get_flag(
-                       info->attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX]);
-               cfg.udp6_zero_rx_checksums = nla_get_flag(
-                       info->attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX]);
-#endif
        }
 
-       if (info->attrs[L2TP_ATTR_DEBUG])
-               cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);
+       if (attrs[L2TP_ATTR_DEBUG])
+               cfg.debug = nla_get_u32(attrs[L2TP_ATTR_DEBUG]);
 
        ret = -EINVAL;
        switch (cfg.encap) {
@@ -320,16 +319,79 @@ out:
        return ret;
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
+static int l2tp_nl_tunnel_send_addr6(struct sk_buff *skb, struct sock *sk,
+                                    enum l2tp_encap_type encap)
+{
+       struct inet_sock *inet = inet_sk(sk);
+       struct ipv6_pinfo *np = inet6_sk(sk);
+
+       switch (encap) {
+       case L2TP_ENCAPTYPE_UDP:
+               if (udp_get_no_check6_tx(sk) &&
+                   nla_put_flag(skb, L2TP_ATTR_UDP_ZERO_CSUM6_TX))
+                       return -1;
+               if (udp_get_no_check6_rx(sk) &&
+                   nla_put_flag(skb, L2TP_ATTR_UDP_ZERO_CSUM6_RX))
+                       return -1;
+               if (nla_put_u16(skb, L2TP_ATTR_UDP_SPORT, ntohs(inet->inet_sport)) ||
+                   nla_put_u16(skb, L2TP_ATTR_UDP_DPORT, ntohs(inet->inet_dport)))
+                       return -1;
+               fallthrough;
+       case L2TP_ENCAPTYPE_IP:
+               if (nla_put_in6_addr(skb, L2TP_ATTR_IP6_SADDR, &np->saddr) ||
+                   nla_put_in6_addr(skb, L2TP_ATTR_IP6_DADDR, &sk->sk_v6_daddr))
+                       return -1;
+               break;
+       }
+       return 0;
+}
+#endif
+
+static int l2tp_nl_tunnel_send_addr4(struct sk_buff *skb, struct sock *sk,
+                                    enum l2tp_encap_type encap)
+{
+       struct inet_sock *inet = inet_sk(sk);
+
+       switch (encap) {
+       case L2TP_ENCAPTYPE_UDP:
+               if (nla_put_u8(skb, L2TP_ATTR_UDP_CSUM, !sk->sk_no_check_tx) ||
+                   nla_put_u16(skb, L2TP_ATTR_UDP_SPORT, ntohs(inet->inet_sport)) ||
+                   nla_put_u16(skb, L2TP_ATTR_UDP_DPORT, ntohs(inet->inet_dport)))
+                       return -1;
+               fallthrough;
+       case L2TP_ENCAPTYPE_IP:
+               if (nla_put_in_addr(skb, L2TP_ATTR_IP_SADDR, inet->inet_saddr) ||
+                   nla_put_in_addr(skb, L2TP_ATTR_IP_DADDR, inet->inet_daddr))
+                       return -1;
+               break;
+       }
+
+       return 0;
+}
+
+/* Append attributes for the tunnel address, handling the different attribute types
+ * used for different tunnel encapsulation and AF_INET v.s. AF_INET6.
+ */
+static int l2tp_nl_tunnel_send_addr(struct sk_buff *skb, struct l2tp_tunnel *tunnel)
+{
+       struct sock *sk = tunnel->sock;
+
+       if (!sk)
+               return 0;
+
+#if IS_ENABLED(CONFIG_IPV6)
+       if (sk->sk_family == AF_INET6)
+               return l2tp_nl_tunnel_send_addr6(skb, sk, tunnel->encap);
+#endif
+       return l2tp_nl_tunnel_send_addr4(skb, sk, tunnel->encap);
+}
+
 static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int flags,
                               struct l2tp_tunnel *tunnel, u8 cmd)
 {
        void *hdr;
        struct nlattr *nest;
-       struct sock *sk = NULL;
-       struct inet_sock *inet;
-#if IS_ENABLED(CONFIG_IPV6)
-       struct ipv6_pinfo *np = NULL;
-#endif
 
        hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags, cmd);
        if (!hdr)
@@ -343,7 +405,7 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla
                goto nla_put_failure;
 
        nest = nla_nest_start_noflag(skb, L2TP_ATTR_STATS);
-       if (nest == NULL)
+       if (!nest)
                goto nla_put_failure;
 
        if (nla_put_u64_64bit(skb, L2TP_ATTR_TX_PACKETS,
@@ -373,58 +435,9 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla
                goto nla_put_failure;
        nla_nest_end(skb, nest);
 
-       sk = tunnel->sock;
-       if (!sk)
-               goto out;
-
-#if IS_ENABLED(CONFIG_IPV6)
-       if (sk->sk_family == AF_INET6)
-               np = inet6_sk(sk);
-#endif
-
-       inet = inet_sk(sk);
-
-       switch (tunnel->encap) {
-       case L2TP_ENCAPTYPE_UDP:
-               switch (sk->sk_family) {
-               case AF_INET:
-                       if (nla_put_u8(skb, L2TP_ATTR_UDP_CSUM, !sk->sk_no_check_tx))
-                               goto nla_put_failure;
-                       break;
-#if IS_ENABLED(CONFIG_IPV6)
-               case AF_INET6:
-                       if (udp_get_no_check6_tx(sk) &&
-                           nla_put_flag(skb, L2TP_ATTR_UDP_ZERO_CSUM6_TX))
-                               goto nla_put_failure;
-                       if (udp_get_no_check6_rx(sk) &&
-                           nla_put_flag(skb, L2TP_ATTR_UDP_ZERO_CSUM6_RX))
-                               goto nla_put_failure;
-                       break;
-#endif
-               }
-               if (nla_put_u16(skb, L2TP_ATTR_UDP_SPORT, ntohs(inet->inet_sport)) ||
-                   nla_put_u16(skb, L2TP_ATTR_UDP_DPORT, ntohs(inet->inet_dport)))
-                       goto nla_put_failure;
-               /* fall through  */
-       case L2TP_ENCAPTYPE_IP:
-#if IS_ENABLED(CONFIG_IPV6)
-               if (np) {
-                       if (nla_put_in6_addr(skb, L2TP_ATTR_IP6_SADDR,
-                                            &np->saddr) ||
-                           nla_put_in6_addr(skb, L2TP_ATTR_IP6_DADDR,
-                                            &sk->sk_v6_daddr))
-                               goto nla_put_failure;
-               } else
-#endif
-               if (nla_put_in_addr(skb, L2TP_ATTR_IP_SADDR,
-                                   inet->inet_saddr) ||
-                   nla_put_in_addr(skb, L2TP_ATTR_IP_DADDR,
-                                   inet->inet_daddr))
-                       goto nla_put_failure;
-               break;
-       }
+       if (l2tp_nl_tunnel_send_addr(skb, tunnel))
+               goto nla_put_failure;
 
-out:
        genlmsg_end(skb, hdr);
        return 0;
 
@@ -485,7 +498,7 @@ static int l2tp_nl_cmd_tunnel_dump(struct sk_buff *skb, struct netlink_callback
 
        for (;;) {
                tunnel = l2tp_tunnel_get_nth(net, ti);
-               if (tunnel == NULL)
+               if (!tunnel)
                        goto out;
 
                if (l2tp_nl_tunnel_send(skb, NETLINK_CB(cb->skb).portid,
@@ -570,6 +583,7 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
 
                if (info->attrs[L2TP_ATTR_COOKIE]) {
                        u16 len = nla_len(info->attrs[L2TP_ATTR_COOKIE]);
+
                        if (len > 8) {
                                ret = -EINVAL;
                                goto out_tunnel;
@@ -579,6 +593,7 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
                }
                if (info->attrs[L2TP_ATTR_PEER_COOKIE]) {
                        u16 len = nla_len(info->attrs[L2TP_ATTR_PEER_COOKIE]);
+
                        if (len > 8) {
                                ret = -EINVAL;
                                goto out_tunnel;
@@ -606,14 +621,13 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
                cfg.reorder_timeout = nla_get_msecs(info->attrs[L2TP_ATTR_RECV_TIMEOUT]);
 
 #ifdef CONFIG_MODULES
-       if (l2tp_nl_cmd_ops[cfg.pw_type] == NULL) {
+       if (!l2tp_nl_cmd_ops[cfg.pw_type]) {
                genl_unlock();
                request_module("net-l2tp-type-%u", cfg.pw_type);
                genl_lock();
        }
 #endif
-       if ((l2tp_nl_cmd_ops[cfg.pw_type] == NULL) ||
-           (l2tp_nl_cmd_ops[cfg.pw_type]->session_create == NULL)) {
+       if (!l2tp_nl_cmd_ops[cfg.pw_type] || !l2tp_nl_cmd_ops[cfg.pw_type]->session_create) {
                ret = -EPROTONOSUPPORT;
                goto out_tunnel;
        }
@@ -645,7 +659,7 @@ static int l2tp_nl_cmd_session_delete(struct sk_buff *skb, struct genl_info *inf
        u16 pw_type;
 
        session = l2tp_nl_session_get(info);
-       if (session == NULL) {
+       if (!session) {
                ret = -ENODEV;
                goto out;
        }
@@ -656,7 +670,7 @@ static int l2tp_nl_cmd_session_delete(struct sk_buff *skb, struct genl_info *inf
        pw_type = session->pwtype;
        if (pw_type < __L2TP_PWTYPE_MAX)
                if (l2tp_nl_cmd_ops[pw_type] && l2tp_nl_cmd_ops[pw_type]->session_delete)
-                       ret = (*l2tp_nl_cmd_ops[pw_type]->session_delete)(session);
+                       l2tp_nl_cmd_ops[pw_type]->session_delete(session);
 
        l2tp_session_dec_refcount(session);
 
@@ -670,7 +684,7 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf
        struct l2tp_session *session;
 
        session = l2tp_nl_session_get(info);
-       if (session == NULL) {
+       if (!session) {
                ret = -ENODEV;
                goto out;
        }
@@ -715,8 +729,7 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl
        if (nla_put_u32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id) ||
            nla_put_u32(skb, L2TP_ATTR_SESSION_ID, session->session_id) ||
            nla_put_u32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id) ||
-           nla_put_u32(skb, L2TP_ATTR_PEER_SESSION_ID,
-                       session->peer_session_id) ||
+           nla_put_u32(skb, L2TP_ATTR_PEER_SESSION_ID, session->peer_session_id) ||
            nla_put_u32(skb, L2TP_ATTR_DEBUG, session->debug) ||
            nla_put_u16(skb, L2TP_ATTR_PW_TYPE, session->pwtype))
                goto nla_put_failure;
@@ -724,11 +737,9 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl
        if ((session->ifname[0] &&
             nla_put_string(skb, L2TP_ATTR_IFNAME, session->ifname)) ||
            (session->cookie_len &&
-            nla_put(skb, L2TP_ATTR_COOKIE, session->cookie_len,
-                    &session->cookie[0])) ||
+            nla_put(skb, L2TP_ATTR_COOKIE, session->cookie_len, session->cookie)) ||
            (session->peer_cookie_len &&
-            nla_put(skb, L2TP_ATTR_PEER_COOKIE, session->peer_cookie_len,
-                    &session->peer_cookie[0])) ||
+            nla_put(skb, L2TP_ATTR_PEER_COOKIE, session->peer_cookie_len, session->peer_cookie)) ||
            nla_put_u8(skb, L2TP_ATTR_RECV_SEQ, session->recv_seq) ||
            nla_put_u8(skb, L2TP_ATTR_SEND_SEQ, session->send_seq) ||
            nla_put_u8(skb, L2TP_ATTR_LNS_MODE, session->lns_mode) ||
@@ -740,7 +751,7 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl
                goto nla_put_failure;
 
        nest = nla_nest_start_noflag(skb, L2TP_ATTR_STATS);
-       if (nest == NULL)
+       if (!nest)
                goto nla_put_failure;
 
        if (nla_put_u64_64bit(skb, L2TP_ATTR_TX_PACKETS,
@@ -785,7 +796,7 @@ static int l2tp_nl_cmd_session_get(struct sk_buff *skb, struct genl_info *info)
        int ret;
 
        session = l2tp_nl_session_get(info);
-       if (session == NULL) {
+       if (!session) {
                ret = -ENODEV;
                goto err;
        }
@@ -824,14 +835,14 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback
        int si = cb->args[1];
 
        for (;;) {
-               if (tunnel == NULL) {
+               if (!tunnel) {
                        tunnel = l2tp_tunnel_get_nth(net, ti);
-                       if (tunnel == NULL)
+                       if (!tunnel)
                                goto out;
                }
 
                session = l2tp_session_get_nth(tunnel, si);
-               if (session == NULL) {
+               if (!session) {
                        ti++;
                        l2tp_tunnel_dec_refcount(tunnel);
                        tunnel = NULL;