Before introducing PRP netlink code, move the re-usable code to a
common hsr_prp_netlink.c.

Signed-off-by: Murali Karicheri <[email protected]>
---
 net/hsr-prp/Makefile          |   2 +-
 net/hsr-prp/hsr_netlink.c     | 337 +------------------------------
 net/hsr-prp/hsr_prp_netlink.c | 367 ++++++++++++++++++++++++++++++++++
 net/hsr-prp/hsr_prp_netlink.h |  27 +++
 4 files changed, 402 insertions(+), 331 deletions(-)
 create mode 100644 net/hsr-prp/hsr_prp_netlink.c
 create mode 100644 net/hsr-prp/hsr_prp_netlink.h

diff --git a/net/hsr-prp/Makefile b/net/hsr-prp/Makefile
index 608045f088a4..76f266cd1976 100644
--- a/net/hsr-prp/Makefile
+++ b/net/hsr-prp/Makefile
@@ -7,5 +7,5 @@ obj-$(CONFIG_HSR_PRP)   += hsr-prp.o
 
 hsr-prp-y              := hsr_prp_main.o hsr_prp_framereg.o \
                           hsr_prp_device.o hsr_netlink.o hsr_prp_slave.o \
-                          hsr_prp_forward.o
+                          hsr_prp_forward.o hsr_prp_netlink.o
 hsr-prp-$(CONFIG_DEBUG_FS) += hsr_prp_debugfs.o
diff --git a/net/hsr-prp/hsr_netlink.c b/net/hsr-prp/hsr_netlink.c
index 1f7c3be8d96e..6bdb369ced36 100644
--- a/net/hsr-prp/hsr_netlink.c
+++ b/net/hsr-prp/hsr_netlink.c
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <net/rtnetlink.h>
 #include <net/genetlink.h>
+#include "hsr_prp_netlink.h"
 #include "hsr_prp_main.h"
 #include "hsr_prp_device.h"
 #include "hsr_prp_framereg.h"
@@ -31,85 +32,7 @@ static int hsr_newlink(struct net *src_net, struct 
net_device *dev,
                       struct nlattr *tb[], struct nlattr *data[],
                       struct netlink_ext_ack *extack)
 {
-       struct net_device *link[2];
-       unsigned char multicast_spec, hsr_version;
-
-       if (!data) {
-               NL_SET_ERR_MSG_MOD(extack, "No slave devices specified");
-               return -EINVAL;
-       }
-       if (!data[IFLA_HSR_PRP_SLAVE1]) {
-               NL_SET_ERR_MSG_MOD(extack, "Slave1 device not specified");
-               return -EINVAL;
-       }
-       link[0] = __dev_get_by_index(src_net,
-                                    nla_get_u32(data[IFLA_HSR_PRP_SLAVE1]));
-       if (!link[0]) {
-               NL_SET_ERR_MSG_MOD(extack, "Slave1 does not exist");
-               return -EINVAL;
-       }
-       if (!data[IFLA_HSR_PRP_SLAVE2]) {
-               NL_SET_ERR_MSG_MOD(extack, "Slave2 device not specified");
-               return -EINVAL;
-       }
-       link[1] = __dev_get_by_index(src_net,
-                                    nla_get_u32(data[IFLA_HSR_PRP_SLAVE2]));
-       if (!link[1]) {
-               NL_SET_ERR_MSG_MOD(extack, "Slave2 does not exist");
-               return -EINVAL;
-       }
-
-       if (link[0] == link[1]) {
-               NL_SET_ERR_MSG_MOD(extack, "Slave1 and Slave2 are same");
-               return -EINVAL;
-       }
-
-       if (!data[IFLA_HSR_PRP_SF_MC_ADDR_LSB])
-               multicast_spec = 0;
-       else
-               multicast_spec = nla_get_u8(data[IFLA_HSR_PRP_SF_MC_ADDR_LSB]);
-
-       if (!data[IFLA_HSR_PRP_VERSION]) {
-               hsr_version = 0;
-       } else {
-               hsr_version = nla_get_u8(data[IFLA_HSR_PRP_VERSION]);
-               if (hsr_version > 1) {
-                       NL_SET_ERR_MSG_MOD(extack,
-                                          "Only versions 0..1 are supported");
-                       return -EINVAL;
-               }
-       }
-
-       return hsr_prp_dev_finalize(dev, link, multicast_spec, hsr_version,
-                                   extack);
-}
-
-static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev)
-{
-       struct hsr_prp_priv *priv = netdev_priv(dev);
-       struct hsr_prp_port *port;
-
-       port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A);
-       if (port) {
-               if (nla_put_u32(skb, IFLA_HSR_PRP_SLAVE1, port->dev->ifindex))
-                       goto nla_put_failure;
-       }
-
-       port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_B);
-       if (port) {
-               if (nla_put_u32(skb, IFLA_HSR_PRP_SLAVE2, port->dev->ifindex))
-                       goto nla_put_failure;
-       }
-
-       if (nla_put(skb, IFLA_HSR_PRP_SF_MC_ADDR, ETH_ALEN,
-                   priv->sup_multicast_addr) ||
-           nla_put_u16(skb, IFLA_HSR_PRP_SEQ_NR, priv->sequence_nr))
-               goto nla_put_failure;
-
-       return 0;
-
-nla_put_failure:
-       return -EMSGSIZE;
+       return hsr_prp_newlink(src_net, dev, tb, data, extack);
 }
 
 static struct rtnl_link_ops hsr_link_ops __read_mostly = {
@@ -119,7 +42,7 @@ static struct rtnl_link_ops hsr_link_ops __read_mostly = {
        .priv_size      = sizeof(struct hsr_prp_priv),
        .setup          = hsr_prp_dev_setup,
        .newlink        = hsr_newlink,
-       .fill_info      = hsr_fill_info,
+       .fill_info      = hsr_prp_fill_info,
 };
 
 /* attribute policy */
@@ -187,40 +110,9 @@ void hsr_nl_ringerror(struct hsr_prp_priv *priv,
 /* This is called when we haven't heard from the node with MAC address addr for
  * some time (just before the node is removed from the node table/list).
  */
-void hsr_nl_nodedown(struct hsr_prp_priv *priv,
-                    unsigned char addr[ETH_ALEN])
+void hsr_nl_nodedown(struct hsr_prp_priv *priv, unsigned char addr[ETH_ALEN])
 {
-       struct sk_buff *skb;
-       void *msg_head;
-       struct hsr_prp_port *master;
-       int res;
-
-       skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
-       if (!skb)
-               goto fail;
-
-       msg_head = genlmsg_put(skb, 0, 0, &hsr_genl_family, 0,
-                              HSR_PRP_C_NODE_DOWN);
-       if (!msg_head)
-               goto nla_put_failure;
-
-       res = nla_put(skb, HSR_PRP_A_NODE_ADDR, ETH_ALEN, addr);
-       if (res < 0)
-               goto nla_put_failure;
-
-       genlmsg_end(skb, msg_head);
-       genlmsg_multicast(&hsr_genl_family, skb, 0, 0, GFP_ATOMIC);
-
-       return;
-
-nla_put_failure:
-       kfree_skb(skb);
-
-fail:
-       rcu_read_lock();
-       master = hsr_prp_get_port(priv, HSR_PRP_PT_MASTER);
-       netdev_warn(master->dev, "Could not send HSR node down\n");
-       rcu_read_unlock();
+       hsr_prp_nl_nodedown(priv, &hsr_genl_family, addr);
 }
 
 /* HSR_PRP_C_GET_NODE_STATUS lets userspace query the internal HSR node table
@@ -233,229 +125,14 @@ void hsr_nl_nodedown(struct hsr_prp_priv *priv,
  */
 static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
 {
-       /* For receiving */
-       struct nlattr *na;
-       struct net_device *hsr_dev;
-
-       /* For sending */
-       struct sk_buff *skb_out;
-       void *msg_head;
-       struct hsr_prp_priv *priv;
-       struct hsr_prp_port *port;
-       unsigned char node_addr_b[ETH_ALEN];
-       int hsr_node_if1_age;
-       u16 hsr_node_if1_seq;
-       int hsr_node_if2_age;
-       u16 hsr_node_if2_seq;
-       int addr_b_ifindex;
-       int res;
-
-       if (!info)
-               goto invalid;
-
-       na = info->attrs[HSR_PRP_A_IFINDEX];
-       if (!na)
-               goto invalid;
-       na = info->attrs[HSR_PRP_A_NODE_ADDR];
-       if (!na)
-               goto invalid;
-
-       rcu_read_lock();
-       hsr_dev =
-       dev_get_by_index_rcu(genl_info_net(info),
-                            nla_get_u32(info->attrs[HSR_PRP_A_IFINDEX]));
-       if (!hsr_dev)
-               goto rcu_unlock;
-       if (!is_hsr_prp_master(hsr_dev))
-               goto rcu_unlock;
-
-       /* Send reply */
-       skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
-       if (!skb_out) {
-               res = -ENOMEM;
-               goto fail;
-       }
-
-       msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid,
-                              info->snd_seq, &hsr_genl_family, 0,
-                              HSR_PRP_C_SET_NODE_STATUS);
-       if (!msg_head) {
-               res = -ENOMEM;
-               goto nla_put_failure;
-       }
-
-       res = nla_put_u32(skb_out, HSR_PRP_A_IFINDEX, hsr_dev->ifindex);
-       if (res < 0)
-               goto nla_put_failure;
-
-       priv = netdev_priv(hsr_dev);
-       res = hsr_prp_get_node_data(priv,
-                                   (unsigned char *)
-                                   nla_data(info->attrs[HSR_PRP_A_NODE_ADDR]),
-                                            node_addr_b,
-                                            &addr_b_ifindex,
-                                            &hsr_node_if1_age,
-                                            &hsr_node_if1_seq,
-                                            &hsr_node_if2_age,
-                                            &hsr_node_if2_seq);
-       if (res < 0)
-               goto nla_put_failure;
-
-       res = nla_put(skb_out, HSR_PRP_A_NODE_ADDR, ETH_ALEN,
-                     nla_data(info->attrs[HSR_PRP_A_NODE_ADDR]));
-       if (res < 0)
-               goto nla_put_failure;
-
-       if (addr_b_ifindex > -1) {
-               res = nla_put(skb_out, HSR_PRP_A_NODE_ADDR_B, ETH_ALEN,
-                             node_addr_b);
-               if (res < 0)
-                       goto nla_put_failure;
-
-               res = nla_put_u32(skb_out, HSR_PRP_A_ADDR_B_IFINDEX,
-                                 addr_b_ifindex);
-               if (res < 0)
-                       goto nla_put_failure;
-       }
-
-       res = nla_put_u32(skb_out, HSR_PRP_A_IF1_AGE, hsr_node_if1_age);
-       if (res < 0)
-               goto nla_put_failure;
-       res = nla_put_u16(skb_out, HSR_PRP_A_IF1_SEQ, hsr_node_if1_seq);
-       if (res < 0)
-               goto nla_put_failure;
-       port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A);
-       if (port)
-               res = nla_put_u32(skb_out, HSR_PRP_A_IF1_IFINDEX,
-                                 port->dev->ifindex);
-       if (res < 0)
-               goto nla_put_failure;
-
-       res = nla_put_u32(skb_out, HSR_PRP_A_IF2_AGE, hsr_node_if2_age);
-       if (res < 0)
-               goto nla_put_failure;
-       res = nla_put_u16(skb_out, HSR_PRP_A_IF2_SEQ, hsr_node_if2_seq);
-       if (res < 0)
-               goto nla_put_failure;
-       port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_B);
-       if (port)
-               res = nla_put_u32(skb_out, HSR_PRP_A_IF2_IFINDEX,
-                                 port->dev->ifindex);
-       if (res < 0)
-               goto nla_put_failure;
-
-       rcu_read_unlock();
-
-       genlmsg_end(skb_out, msg_head);
-       genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid);
-
-       return 0;
-
-rcu_unlock:
-       rcu_read_unlock();
-invalid:
-       netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
-       return 0;
-
-nla_put_failure:
-       kfree_skb(skb_out);
-       /* Fall through */
-
-fail:
-       rcu_read_unlock();
-       return res;
+       return hsr_prp_get_node_status(&hsr_genl_family, skb_in, info);
 }
 
 /* Get a list of MacAddressA of all nodes known to this node (including self).
  */
 static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
 {
-       unsigned char addr[ETH_ALEN];
-       struct net_device *hsr_dev;
-       struct hsr_prp_priv *priv;
-       struct sk_buff *skb_out;
-       bool restart = false;
-       struct nlattr *na;
-       void *pos = NULL;
-       void *msg_head;
-       int res;
-
-       if (!info)
-               goto invalid;
-
-       na = info->attrs[HSR_PRP_A_IFINDEX];
-       if (!na)
-               goto invalid;
-
-       rcu_read_lock();
-       hsr_dev =
-       dev_get_by_index_rcu(genl_info_net(info),
-                            nla_get_u32(info->attrs[HSR_PRP_A_IFINDEX]));
-       if (!hsr_dev)
-               goto rcu_unlock;
-       if (!is_hsr_prp_master(hsr_dev))
-               goto rcu_unlock;
-
-restart:
-       /* Send reply */
-       skb_out = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC);
-       if (!skb_out) {
-               res = -ENOMEM;
-               goto fail;
-       }
-
-       msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid,
-                              info->snd_seq, &hsr_genl_family, 0,
-                              HSR_PRP_C_SET_NODE_LIST);
-       if (!msg_head) {
-               res = -ENOMEM;
-               goto nla_put_failure;
-       }
-
-       if (!restart) {
-               res = nla_put_u32(skb_out, HSR_PRP_A_IFINDEX, hsr_dev->ifindex);
-               if (res < 0)
-                       goto nla_put_failure;
-       }
-
-       priv = netdev_priv(hsr_dev);
-
-       if (!pos)
-               pos = hsr_prp_get_next_node(priv, NULL, addr);
-       while (pos) {
-               res = nla_put(skb_out, HSR_PRP_A_NODE_ADDR, ETH_ALEN, addr);
-               if (res < 0) {
-                       if (res == -EMSGSIZE) {
-                               genlmsg_end(skb_out, msg_head);
-                               genlmsg_unicast(genl_info_net(info), skb_out,
-                                               info->snd_portid);
-                               restart = true;
-                               goto restart;
-                       }
-                       goto nla_put_failure;
-               }
-               pos = hsr_prp_get_next_node(priv, pos, addr);
-       }
-       rcu_read_unlock();
-
-       genlmsg_end(skb_out, msg_head);
-       genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid);
-
-       return 0;
-
-rcu_unlock:
-       rcu_read_unlock();
-invalid:
-       netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
-       return 0;
-
-nla_put_failure:
-       nlmsg_free(skb_out);
-       /* Fall through */
-
-fail:
-       rcu_read_unlock();
-       return res;
+       return hsr_prp_get_node_list(&hsr_genl_family, skb_in, info);
 }
 
 static const struct genl_ops hsr_ops[] = {
diff --git a/net/hsr-prp/hsr_prp_netlink.c b/net/hsr-prp/hsr_prp_netlink.c
new file mode 100644
index 000000000000..04d51cd97496
--- /dev/null
+++ b/net/hsr-prp/hsr_prp_netlink.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2011-2014 Autronica Fire and Security AS
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Based on Code by Arvid Brodin, [email protected]
+ *
+ * Common routines for handling Netlink messages for HSR and PRP
+ */
+
+#include "hsr_prp_netlink.h"
+#include "hsr_prp_main.h"
+#include "hsr_prp_device.h"
+#include "hsr_prp_framereg.h"
+
+int hsr_prp_newlink(struct net *src_net, struct net_device *dev,
+                   struct nlattr *tb[], struct nlattr *data[],
+                   struct netlink_ext_ack *extack)
+{
+       struct net_device *link[2];
+       unsigned char multicast_spec, hsr_version;
+
+       if (!data) {
+               NL_SET_ERR_MSG_MOD(extack, "No slave devices specified");
+               return -EINVAL;
+       }
+       if (!data[IFLA_HSR_PRP_SLAVE1]) {
+               NL_SET_ERR_MSG_MOD(extack, "Slave1 device not specified");
+               return -EINVAL;
+       }
+       link[0] = __dev_get_by_index(src_net,
+                                    nla_get_u32(data[IFLA_HSR_PRP_SLAVE1]));
+       if (!link[0]) {
+               NL_SET_ERR_MSG_MOD(extack, "Slave1 does not exist");
+               return -EINVAL;
+       }
+       if (!data[IFLA_HSR_PRP_SLAVE2]) {
+               NL_SET_ERR_MSG_MOD(extack, "Slave2 device not specified");
+               return -EINVAL;
+       }
+       link[1] = __dev_get_by_index(src_net,
+                                    nla_get_u32(data[IFLA_HSR_PRP_SLAVE2]));
+       if (!link[1]) {
+               NL_SET_ERR_MSG_MOD(extack, "Slave2 does not exist");
+               return -EINVAL;
+       }
+
+       if (link[0] == link[1]) {
+               NL_SET_ERR_MSG_MOD(extack, "Slave1 and Slave2 are same");
+               return -EINVAL;
+       }
+
+       if (!data[IFLA_HSR_PRP_SF_MC_ADDR_LSB])
+               multicast_spec = 0;
+       else
+               multicast_spec = nla_get_u8(data[IFLA_HSR_PRP_SF_MC_ADDR_LSB]);
+
+       if (!data[IFLA_HSR_PRP_VERSION]) {
+               hsr_version = 0;
+       } else {
+               hsr_version = nla_get_u8(data[IFLA_HSR_PRP_VERSION]);
+               if (hsr_version > 1) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "Only versions 0..1 are supported");
+                       return -EINVAL;
+               }
+       }
+
+       return hsr_prp_dev_finalize(dev, link, multicast_spec, hsr_version,
+                                   extack);
+}
+
+int hsr_prp_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+       struct hsr_prp_priv *priv = netdev_priv(dev);
+       struct hsr_prp_port *port;
+
+       port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A);
+       if (port) {
+               if (nla_put_u32(skb, IFLA_HSR_PRP_SLAVE1, port->dev->ifindex))
+                       goto nla_put_failure;
+       }
+
+       port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_B);
+       if (port) {
+               if (nla_put_u32(skb, IFLA_HSR_PRP_SLAVE2, port->dev->ifindex))
+                       goto nla_put_failure;
+       }
+
+       if (nla_put(skb, IFLA_HSR_PRP_SF_MC_ADDR, ETH_ALEN,
+                   priv->sup_multicast_addr) ||
+           nla_put_u16(skb, IFLA_HSR_PRP_SEQ_NR, priv->sequence_nr))
+               goto nla_put_failure;
+
+       return 0;
+
+nla_put_failure:
+       return -EMSGSIZE;
+}
+
+/* This is called when we haven't heard from the node with MAC address addr for
+ * some time (just before the node is removed from the node table/list).
+ */
+void hsr_prp_nl_nodedown(struct hsr_prp_priv *priv,
+                        struct genl_family *genl_family,
+                        unsigned char addr[ETH_ALEN])
+{
+       struct sk_buff *skb;
+       void *msg_head;
+       struct hsr_prp_port *master;
+       int res;
+
+       skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
+       if (!skb)
+               goto fail;
+
+       msg_head = genlmsg_put(skb, 0, 0, genl_family, 0,
+                              HSR_PRP_C_NODE_DOWN);
+       if (!msg_head)
+               goto nla_put_failure;
+
+       res = nla_put(skb, HSR_PRP_A_NODE_ADDR, ETH_ALEN, addr);
+       if (res < 0)
+               goto nla_put_failure;
+
+       genlmsg_end(skb, msg_head);
+       genlmsg_multicast(genl_family, skb, 0, 0, GFP_ATOMIC);
+
+       return;
+
+nla_put_failure:
+       kfree_skb(skb);
+
+fail:
+       rcu_read_lock();
+       master = hsr_prp_get_port(priv, HSR_PRP_PT_MASTER);
+       netdev_warn(master->dev, "Could not send HSR node down\n");
+       rcu_read_unlock();
+}
+
+int hsr_prp_get_node_status(struct genl_family *genl_family,
+                           struct sk_buff *skb_in, struct genl_info *info)
+{
+       /* For receiving */
+       struct nlattr *na;
+       struct net_device *hsr_dev;
+
+       /* For sending */
+       struct sk_buff *skb_out;
+       void *msg_head;
+       struct hsr_prp_priv *priv;
+       struct hsr_prp_port *port;
+       unsigned char node_addr_b[ETH_ALEN];
+       int hsr_node_if1_age;
+       u16 hsr_node_if1_seq;
+       int hsr_node_if2_age;
+       u16 hsr_node_if2_seq;
+       int addr_b_ifindex;
+       int res;
+
+       if (!info)
+               goto invalid;
+
+       na = info->attrs[HSR_PRP_A_IFINDEX];
+       if (!na)
+               goto invalid;
+       na = info->attrs[HSR_PRP_A_NODE_ADDR];
+       if (!na)
+               goto invalid;
+
+       rcu_read_lock();
+       hsr_dev =
+       dev_get_by_index_rcu(genl_info_net(info),
+                            nla_get_u32(info->attrs[HSR_PRP_A_IFINDEX]));
+       if (!hsr_dev)
+               goto rcu_unlock;
+       if (!is_hsr_prp_master(hsr_dev))
+               goto rcu_unlock;
+
+       /* Send reply */
+       skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
+       if (!skb_out) {
+               res = -ENOMEM;
+               goto fail;
+       }
+
+       msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid,
+                              info->snd_seq, genl_family, 0,
+                              HSR_PRP_C_SET_NODE_STATUS);
+       if (!msg_head) {
+               res = -ENOMEM;
+               goto nla_put_failure;
+       }
+
+       res = nla_put_u32(skb_out, HSR_PRP_A_IFINDEX, hsr_dev->ifindex);
+       if (res < 0)
+               goto nla_put_failure;
+
+       priv = netdev_priv(hsr_dev);
+       res = hsr_prp_get_node_data(priv,
+                                   (unsigned char *)
+                                   nla_data(info->attrs[HSR_PRP_A_NODE_ADDR]),
+                                            node_addr_b,
+                                            &addr_b_ifindex,
+                                            &hsr_node_if1_age,
+                                            &hsr_node_if1_seq,
+                                            &hsr_node_if2_age,
+                                            &hsr_node_if2_seq);
+       if (res < 0)
+               goto nla_put_failure;
+
+       res = nla_put(skb_out, HSR_PRP_A_NODE_ADDR, ETH_ALEN,
+                     nla_data(info->attrs[HSR_PRP_A_NODE_ADDR]));
+       if (res < 0)
+               goto nla_put_failure;
+
+       if (addr_b_ifindex > -1) {
+               res = nla_put(skb_out, HSR_PRP_A_NODE_ADDR_B, ETH_ALEN,
+                             node_addr_b);
+               if (res < 0)
+                       goto nla_put_failure;
+
+               res = nla_put_u32(skb_out, HSR_PRP_A_ADDR_B_IFINDEX,
+                                 addr_b_ifindex);
+               if (res < 0)
+                       goto nla_put_failure;
+       }
+
+       res = nla_put_u32(skb_out, HSR_PRP_A_IF1_AGE, hsr_node_if1_age);
+       if (res < 0)
+               goto nla_put_failure;
+       res = nla_put_u16(skb_out, HSR_PRP_A_IF1_SEQ, hsr_node_if1_seq);
+       if (res < 0)
+               goto nla_put_failure;
+       port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A);
+       if (port)
+               res = nla_put_u32(skb_out, HSR_PRP_A_IF1_IFINDEX,
+                                 port->dev->ifindex);
+       if (res < 0)
+               goto nla_put_failure;
+
+       res = nla_put_u32(skb_out, HSR_PRP_A_IF2_AGE, hsr_node_if2_age);
+       if (res < 0)
+               goto nla_put_failure;
+       res = nla_put_u16(skb_out, HSR_PRP_A_IF2_SEQ, hsr_node_if2_seq);
+       if (res < 0)
+               goto nla_put_failure;
+       port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_B);
+       if (port)
+               res = nla_put_u32(skb_out, HSR_PRP_A_IF2_IFINDEX,
+                                 port->dev->ifindex);
+       if (res < 0)
+               goto nla_put_failure;
+
+       rcu_read_unlock();
+
+       genlmsg_end(skb_out, msg_head);
+       genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid);
+
+       return 0;
+
+rcu_unlock:
+       rcu_read_unlock();
+invalid:
+       netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
+       return 0;
+
+nla_put_failure:
+       kfree_skb(skb_out);
+       /* Fall through */
+
+fail:
+       rcu_read_unlock();
+       return res;
+}
+
+/* Get a list of MacAddressA of all nodes known to this node (including self).
+ */
+int hsr_prp_get_node_list(struct genl_family *genl_family,
+                         struct sk_buff *skb_in, struct genl_info *info)
+{
+       unsigned char addr[ETH_ALEN];
+       struct net_device *hsr_dev;
+       struct hsr_prp_priv *priv;
+       struct sk_buff *skb_out;
+       bool restart = false;
+       struct nlattr *na;
+       void *pos = NULL;
+       void *msg_head;
+       int res;
+
+       if (!info)
+               goto invalid;
+
+       na = info->attrs[HSR_PRP_A_IFINDEX];
+       if (!na)
+               goto invalid;
+
+       rcu_read_lock();
+       hsr_dev =
+       dev_get_by_index_rcu(genl_info_net(info),
+                            nla_get_u32(info->attrs[HSR_PRP_A_IFINDEX]));
+       if (!hsr_dev)
+               goto rcu_unlock;
+       if (!is_hsr_prp_master(hsr_dev))
+               goto rcu_unlock;
+
+restart:
+       /* Send reply */
+       skb_out = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+       if (!skb_out) {
+               res = -ENOMEM;
+               goto fail;
+       }
+
+       msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid,
+                              info->snd_seq, genl_family, 0,
+                              HSR_PRP_C_SET_NODE_LIST);
+       if (!msg_head) {
+               res = -ENOMEM;
+               goto nla_put_failure;
+       }
+
+       if (!restart) {
+               res = nla_put_u32(skb_out, HSR_PRP_A_IFINDEX, hsr_dev->ifindex);
+               if (res < 0)
+                       goto nla_put_failure;
+       }
+
+       priv = netdev_priv(hsr_dev);
+
+       if (!pos)
+               pos = hsr_prp_get_next_node(priv, NULL, addr);
+       while (pos) {
+               res = nla_put(skb_out, HSR_PRP_A_NODE_ADDR, ETH_ALEN, addr);
+               if (res < 0) {
+                       if (res == -EMSGSIZE) {
+                               genlmsg_end(skb_out, msg_head);
+                               genlmsg_unicast(genl_info_net(info), skb_out,
+                                               info->snd_portid);
+                               restart = true;
+                               goto restart;
+                       }
+                       goto nla_put_failure;
+               }
+               pos = hsr_prp_get_next_node(priv, pos, addr);
+       }
+       rcu_read_unlock();
+
+       genlmsg_end(skb_out, msg_head);
+       genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid);
+
+       return 0;
+
+rcu_unlock:
+       rcu_read_unlock();
+invalid:
+       netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(skb_out);
+       /* Fall through */
+
+fail:
+       rcu_read_unlock();
+       return res;
+}
diff --git a/net/hsr-prp/hsr_prp_netlink.h b/net/hsr-prp/hsr_prp_netlink.h
new file mode 100644
index 000000000000..a3a4e6252e45
--- /dev/null
+++ b/net/hsr-prp/hsr_prp_netlink.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright 2011-2014 Autronica Fire and Security AS
+ *
+ * Author(s):
+ *     2011-2014 Arvid Brodin, [email protected]
+ */
+
+#ifndef __HSR_PRP_NETLINK_H
+#define __HSR_PRP_NETLINK_H
+
+#include <uapi/linux/hsr_prp_netlink.h>
+#include <net/genetlink.h>
+
+#include "hsr_prp_main.h"
+
+int hsr_prp_newlink(struct net *src_net, struct net_device *dev,
+                   struct nlattr *tb[], struct nlattr *data[],
+                   struct netlink_ext_ack *extack);
+int hsr_prp_fill_info(struct sk_buff *skb, const struct net_device *dev);
+void hsr_prp_nl_nodedown(struct hsr_prp_priv *priv,
+                        struct genl_family *genl_family,
+                        unsigned char addr[ETH_ALEN]);
+int hsr_prp_get_node_status(struct genl_family *genl_family,
+                           struct sk_buff *skb_in, struct genl_info *info);
+int hsr_prp_get_node_list(struct genl_family *genl_family,
+                         struct sk_buff *skb_in, struct genl_info *info);
+#endif /* __HSR_PRP_NETLINK_H */
-- 
2.17.1

Reply via email to