浏览代码

net: hsr/prp: unify netlink socket interface

From the user interface point of view, hsr/prp device configuration
is similar. It accepts a pair of ethernet link and other parameters.
To help re-use the code, rename existing uapi inlcude file,
include/uapi/linux/hsr_netlink.h to include/uapi/linux/hsr_prp_netlink.h
and prefix the definitions with HSR_PRP to indicate they are applicable
for both. Also remove include/uapi/linux/prp_netlink.h in favour of the
above. While doing so, clean up the names used in include/uapi/linux/
if_link.h as well . For example, IFLA_HSR_MULTICAST_SPEC actually is
Least Significant Byte (LSB) of the Multicast address used for Supervision
frames and is configurable. So call it IFLA_HSR_PRP_SF_MC_ADDR_LSB instead
to make it explicit. Similarly, change IFLA_PRP_SUPERVISION_ADDR to
IFLA_HSR_PRP_SF_MC_ADDR.

By using the latest definitions, refactor code in hsr_netlink.c to a
common file, hsr_prp_netlink.h and call the functions from hsr_netlink.c
and prp_netlink.c thereby removing duplicate code.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Murali Karicheri 6 年之前
父节点
当前提交
65f4b7706f

+ 0 - 51
include/uapi/linux/hsr_netlink.h

@@ -1,51 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
-/*
- * Copyright 2011-2013 Autronica Fire and Security AS
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * Author(s):
- *	2011-2013 Arvid Brodin, arvid.brodin@xdin.com
- */
-
-#ifndef __UAPI_HSR_NETLINK_H
-#define __UAPI_HSR_NETLINK_H
-
-/* Generic Netlink HSR family definition
- */
-
-/* attributes */
-enum {
-	HSR_A_UNSPEC,
-	HSR_A_NODE_ADDR,
-	HSR_A_IFINDEX,
-	HSR_A_IF1_AGE,
-	HSR_A_IF2_AGE,
-	HSR_A_NODE_ADDR_B,
-	HSR_A_IF1_SEQ,
-	HSR_A_IF2_SEQ,
-	HSR_A_IF1_IFINDEX,
-	HSR_A_IF2_IFINDEX,
-	HSR_A_ADDR_B_IFINDEX,
-	__HSR_A_MAX,
-};
-#define HSR_A_MAX (__HSR_A_MAX - 1)
-
-
-/* commands */
-enum {
-	HSR_C_UNSPEC,
-	HSR_C_RING_ERROR,
-	HSR_C_NODE_DOWN,
-	HSR_C_GET_NODE_STATUS,
-	HSR_C_SET_NODE_STATUS,
-	HSR_C_GET_NODE_LIST,
-	HSR_C_SET_NODE_LIST,
-	__HSR_C_MAX,
-};
-#define HSR_C_MAX (__HSR_C_MAX - 1)
-
-#endif /* __UAPI_HSR_NETLINK_H */

+ 50 - 0
include/uapi/linux/hsr_prp_netlink.h

@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* prp_prp_netlink.h: This is based on hsr_netlink.h from Arvid Brodin,
+ * arvid.brodin@alten.se
+ *
+ * Copyright 2011-2014 Autronica Fire and Security AS
+ * Copyright (C) 2019 Texas Instruments Incorporated
+ *
+ * Author(s):
+ *	2011-2014 Arvid Brodin, arvid.brodin@alten.se
+ *	2019 Murali Karicheri <m-karicheri2@ti.com>
+ */
+
+#ifndef __UAPI_HSR_PRP_NETLINK_H
+#define __UAPI_HSR_PRP_NETLINK_H
+
+/* Generic Netlink HSR/PRP family definition
+ */
+
+/* attributes */
+enum {
+	HSR_PRP_A_UNSPEC,
+	HSR_PRP_A_NODE_ADDR,
+	HSR_PRP_A_IFINDEX,
+	HSR_PRP_A_IF1_AGE,
+	HSR_PRP_A_IF2_AGE,
+	HSR_PRP_A_NODE_ADDR_B,
+	HSR_PRP_A_IF1_SEQ,
+	HSR_PRP_A_IF2_SEQ,
+	HSR_PRP_A_IF1_IFINDEX,
+	HSR_PRP_A_IF2_IFINDEX,
+	HSR_PRP_A_ADDR_B_IFINDEX,
+	__HSR_PRP_A_MAX,
+};
+#define HSR_PRP_A_MAX (__HSR_PRP_A_MAX - 1)
+
+
+/* commands */
+enum {
+	HSR_PRP_C_UNSPEC,
+	HSR_C_RING_ERROR, /* only for HSR for now */
+	HSR_PRP_C_NODE_DOWN,
+	HSR_PRP_C_GET_NODE_STATUS,
+	HSR_PRP_C_SET_NODE_STATUS,
+	HSR_PRP_C_GET_NODE_LIST,
+	HSR_PRP_C_SET_NODE_LIST,
+	__HSR_PRP_C_MAX,
+};
+#define HSR_PRP_C_MAX (__HSR_PRP_C_MAX - 1)
+
+#endif /* __UAPI_HSR_PRP_NETLINK_H */

+ 9 - 26
include/uapi/linux/if_link.h

@@ -852,22 +852,6 @@ enum {
 
 #define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1)
 
-
-/* HSR section */
-
-enum {
-	IFLA_HSR_UNSPEC,
-	IFLA_HSR_SLAVE1,
-	IFLA_HSR_SLAVE2,
-	IFLA_HSR_MULTICAST_SPEC,	/* Last byte of supervision addr */
-	IFLA_HSR_SUPERVISION_ADDR,	/* Supervision frame multicast addr */
-	IFLA_HSR_SEQ_NR,
-	IFLA_HSR_VERSION,		/* HSR version */
-	__IFLA_HSR_MAX,
-};
-
-#define IFLA_HSR_MAX (__IFLA_HSR_MAX - 1)
-
 /* STATS section */
 
 struct if_stats_msg {
@@ -999,18 +983,17 @@ struct ifla_rmnet_flags {
 	__u32	mask;
 };
 
-/* PRP section */
-
 enum {
-	IFLA_PRP_UNSPEC,
-	IFLA_PRP_SLAVE1,
-	IFLA_PRP_SLAVE2,
-	IFLA_PRP_MULTICAST_SPEC,        /* Last byte of supervision addr */
-	IFLA_PRP_SUPERVISION_ADDR,      /* Supervision frame multicast addr */
-	IFLA_PRP_SEQ_NR,
-	__IFLA_PRP_MAX,
+	IFLA_HSR_PRP_UNSPEC,
+	IFLA_HSR_PRP_SLAVE1,
+	IFLA_HSR_PRP_SLAVE2,
+	IFLA_HSR_PRP_SF_MC_ADDR_LSB,  /* Last byte of supervision addr */
+	IFLA_HSR_PRP_SF_MC_ADDR,      /* Supervision frame multicast addr */
+	IFLA_HSR_PRP_SEQ_NR,
+	IFLA_HSR_VERSION,		/* HSR version */
+	__IFLA_HSR_PRP_MAX,
 };
 
-#define IFLA_PRP_MAX (__IFLA_PRP_MAX - 1)
+#define IFLA_HSR_PRP_MAX (__IFLA_HSR_PRP_MAX - 1)
 
 #endif /* _UAPI_LINUX_IF_LINK_H */

+ 0 - 48
include/uapi/linux/prp_netlink.h

@@ -1,48 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * prp_netlink.h: This is based on hsr_netlink.h from Arvid Brodin,
- * arvid.brodin@alten.se
- *
- * Copyright (C) 2017 Texas Instruments Incorporated
- *
- * Author(s):
- *	2017 Murali Karicheri <m-karicheri2@ti.com>
- */
-
-#ifndef __UAPI_PRP_NETLINK_H
-#define __UAPI_PRP_NETLINK_H
-
-/* Generic Netlink PRP family definition
- */
-
-/* attributes */
-enum {
-	PRP_A_UNSPEC,
-	PRP_A_NODE_ADDR,
-	PRP_A_IFINDEX,
-	PRP_A_IF1_AGE,
-	PRP_A_IF2_AGE,
-	PRP_A_NODE_ADDR_B,
-	PRP_A_IF1_SEQ,
-	PRP_A_IF2_SEQ,
-	PRP_A_IF1_IFINDEX,
-	PRP_A_IF2_IFINDEX,
-	PRP_A_ADDR_B_IFINDEX,
-	__PRP_A_MAX,
-};
-#define PRP_A_MAX (__PRP_A_MAX - 1)
-
-
-/* commands */
-enum {
-	PRP_C_UNSPEC,
-	PRP_C_NODE_DOWN,
-	PRP_C_GET_NODE_STATUS,
-	PRP_C_SET_NODE_STATUS,
-	PRP_C_GET_NODE_LIST,
-	PRP_C_SET_NODE_LIST,
-	__PRP_C_MAX,
-};
-#define PRP_C_MAX (__PRP_C_MAX - 1)
-
-#endif /* __UAPI_PRP_NETLINK_H */

+ 3 - 2
net/hsr-prp/Makefile

@@ -5,6 +5,7 @@
 obj-$(CONFIG_HSR_PRP)	+= hsr-prp.o
 
 hsr-prp-y		:= hsr_prp_main.o hsr_main.o prp_main.o \
-			   hsr_prp_framereg.o hsr_prp_device.o hsr_netlink.o \
-			   prp_netlink.o hsr_prp_slave.o hsr_prp_forward.o
+			   hsr_prp_framereg.o hsr_prp_device.o \
+			   hsr_prp_netlink.o hsr_netlink.o prp_netlink.o \
+			   hsr_prp_slave.o hsr_prp_forward.o
 hsr-prp-$(CONFIG_DEBUG_FS) += hsr_prp_debugfs.o

+ 30 - 332
net/hsr-prp/hsr_netlink.c

@@ -8,123 +8,50 @@
  */
 
 #include <linux/kernel.h>
-#include <net/rtnetlink.h>
 #include <net/genetlink.h>
+#include <net/rtnetlink.h>
+
 #include "hsr_netlink.h"
-#include "hsr_prp_main.h"
 #include "hsr_prp_device.h"
 #include "hsr_prp_framereg.h"
+#include "hsr_prp_main.h"
+#include "hsr_prp_netlink.h"
 
-static const struct nla_policy hsr_policy[IFLA_HSR_MAX + 1] = {
-	[IFLA_HSR_SLAVE1]		= { .type = NLA_U32 },
-	[IFLA_HSR_SLAVE2]		= { .type = NLA_U32 },
-	[IFLA_HSR_MULTICAST_SPEC]	= { .type = NLA_U8 },
+static const struct nla_policy hsr_policy[IFLA_HSR_PRP_MAX + 1] = {
+	[IFLA_HSR_PRP_SLAVE1]		= { .type = NLA_U32 },
+	[IFLA_HSR_PRP_SLAVE2]		= { .type = NLA_U32 },
+	[IFLA_HSR_PRP_SF_MC_ADDR_LSB]	= { .type = NLA_U8 },
 	[IFLA_HSR_VERSION]	= { .type = NLA_U8 },
-	[IFLA_HSR_SUPERVISION_ADDR]	= { .len = ETH_ALEN },
-	[IFLA_HSR_SEQ_NR]		= { .type = NLA_U16 },
+	[IFLA_HSR_PRP_SF_MC_ADDR]	= { .len = ETH_ALEN },
+	[IFLA_HSR_PRP_SEQ_NR]		= { .type = NLA_U16 },
 };
 
-/* Here, it seems a netdevice has already been allocated for us, and the
- * hsr_prp_dev_setup routine has been executed. Nice!
- */
 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) {
-		netdev_info(dev, "HSR: No slave devices specified\n");
-		return -EINVAL;
-	}
-	if (!data[IFLA_HSR_SLAVE1]) {
-		netdev_info(dev, "HSR: Slave1 device not specified\n");
-		return -EINVAL;
-	}
-	link[0] = __dev_get_by_index(src_net,
-				     nla_get_u32(data[IFLA_HSR_SLAVE1]));
-	if (!data[IFLA_HSR_SLAVE2]) {
-		netdev_info(dev, "HSR: Slave2 device not specified\n");
-		return -EINVAL;
-	}
-	link[1] = __dev_get_by_index(src_net,
-				     nla_get_u32(data[IFLA_HSR_SLAVE2]));
-
-	if (!link[0] || !link[1])
-		return -ENODEV;
-	if (link[0] == link[1])
-		return -EINVAL;
-
-	if (!data[IFLA_HSR_MULTICAST_SPEC])
-		multicast_spec = 0;
-	else
-		multicast_spec = nla_get_u8(data[IFLA_HSR_MULTICAST_SPEC]);
-
-	if (!data[IFLA_HSR_VERSION])
-		hsr_version = 0;
-	else
-		hsr_version = nla_get_u8(data[IFLA_HSR_VERSION]);
-
-	return hsr_prp_dev_finalize(dev, link, multicast_spec, hsr_version);
-}
-
-static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev)
-{
-	struct hsr_prp_priv *priv;
-	struct hsr_prp_port *port;
-	int res;
-
-	priv = netdev_priv(dev);
-
-	res = 0;
-
-	rcu_read_lock();
-	port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A);
-	if (port)
-		res = nla_put_u32(skb, IFLA_HSR_SLAVE1, port->dev->ifindex);
-	rcu_read_unlock();
-	if (res)
-		goto nla_put_failure;
-
-	rcu_read_lock();
-	port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_B);
-	if (port)
-		res = nla_put_u32(skb, IFLA_HSR_SLAVE2, port->dev->ifindex);
-	rcu_read_unlock();
-	if (res)
-		goto nla_put_failure;
-
-	if (nla_put(skb, IFLA_HSR_SUPERVISION_ADDR, ETH_ALEN,
-		    priv->sup_multicast_addr) ||
-	    nla_put_u16(skb, IFLA_HSR_SEQ_NR, priv->sequence_nr))
-		goto nla_put_failure;
-
-	return 0;
-
-nla_put_failure:
-	return -EMSGSIZE;
+	return hsr_prp_newlink(HSR, src_net, dev, tb, data, extack);
 }
 
 static struct rtnl_link_ops hsr_link_ops __read_mostly = {
 	.kind		= "hsr",
-	.maxtype	= IFLA_HSR_MAX,
+	.maxtype	= IFLA_HSR_PRP_MAX,
 	.policy		= hsr_policy,
 	.priv_size	= sizeof(struct hsr_prp_priv),
 	.setup		= hsr_dev_setup,
 	.newlink	= hsr_newlink,
-	.fill_info	= hsr_fill_info,
+	.fill_info	= hsr_prp_fill_info,
 };
 
 /* attribute policy */
-static const struct nla_policy hsr_genl_policy[HSR_A_MAX + 1] = {
-	[HSR_A_NODE_ADDR] = { .len = ETH_ALEN },
-	[HSR_A_NODE_ADDR_B] = { .len = ETH_ALEN },
-	[HSR_A_IFINDEX] = { .type = NLA_U32 },
-	[HSR_A_IF1_AGE] = { .type = NLA_U32 },
-	[HSR_A_IF2_AGE] = { .type = NLA_U32 },
-	[HSR_A_IF1_SEQ] = { .type = NLA_U16 },
-	[HSR_A_IF2_SEQ] = { .type = NLA_U16 },
+static const struct nla_policy hsr_genl_policy[HSR_PRP_A_MAX + 1] = {
+	[HSR_PRP_A_NODE_ADDR] = { .len = ETH_ALEN },
+	[HSR_PRP_A_NODE_ADDR_B] = { .len = ETH_ALEN },
+	[HSR_PRP_A_IFINDEX] = { .type = NLA_U32 },
+	[HSR_PRP_A_IF1_AGE] = { .type = NLA_U32 },
+	[HSR_PRP_A_IF2_AGE] = { .type = NLA_U32 },
+	[HSR_PRP_A_IF1_SEQ] = { .type = NLA_U16 },
+	[HSR_PRP_A_IF2_SEQ] = { .type = NLA_U16 },
 };
 
 static struct genl_family hsr_genl_family;
@@ -155,11 +82,11 @@ void hsr_prp_nl_ringerror(struct hsr_prp_priv *priv,
 	if (!msg_head)
 		goto nla_put_failure;
 
-	res = nla_put(skb, HSR_A_NODE_ADDR, ETH_ALEN, addr);
+	res = nla_put(skb, HSR_PRP_A_NODE_ADDR, ETH_ALEN, addr);
 	if (res < 0)
 		goto nla_put_failure;
 
-	res = nla_put_u32(skb, HSR_A_IFINDEX, port->dev->ifindex);
+	res = nla_put_u32(skb, HSR_PRP_A_IFINDEX, port->dev->ifindex);
 	if (res < 0)
 		goto nla_put_failure;
 
@@ -181,39 +108,9 @@ fail:
 /* 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_C_NODE_DOWN);
-	if (!msg_head)
-		goto nla_put_failure;
-
-	res = nla_put(skb, HSR_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_C_GET_NODE_STATUS lets userspace query the internal HSR node table
@@ -226,225 +123,26 @@ fail:
  */
 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_A_IFINDEX];
-	if (!na)
-		goto invalid;
-	na = info->attrs[HSR_A_NODE_ADDR];
-	if (!na)
-		goto invalid;
-
-	hsr_dev = __dev_get_by_index(genl_info_net(info),
-				     nla_get_u32(info->attrs[HSR_A_IFINDEX]));
-	if (!hsr_dev)
-		goto invalid;
-	if (!is_hsr_prp_master(hsr_dev))
-		goto invalid;
-
-	/* Send reply */
-	skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-	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_C_SET_NODE_STATUS);
-	if (!msg_head) {
-		res = -ENOMEM;
-		goto nla_put_failure;
-	}
-
-	res = nla_put_u32(skb_out, HSR_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_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_A_NODE_ADDR, ETH_ALEN,
-		      nla_data(info->attrs[HSR_A_NODE_ADDR]));
-	if (res < 0)
-		goto nla_put_failure;
-
-	if (addr_b_ifindex > -1) {
-		res = nla_put(skb_out, HSR_A_NODE_ADDR_B, ETH_ALEN,
-			      node_addr_b);
-		if (res < 0)
-			goto nla_put_failure;
-
-		res = nla_put_u32(skb_out, HSR_A_ADDR_B_IFINDEX,
-				  addr_b_ifindex);
-		if (res < 0)
-			goto nla_put_failure;
-	}
-
-	res = nla_put_u32(skb_out, HSR_A_IF1_AGE, hsr_node_if1_age);
-	if (res < 0)
-		goto nla_put_failure;
-	res = nla_put_u16(skb_out, HSR_A_IF1_SEQ, hsr_node_if1_seq);
-	if (res < 0)
-		goto nla_put_failure;
-	rcu_read_lock();
-	port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A);
-	if (port)
-		res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX,
-				  port->dev->ifindex);
-	rcu_read_unlock();
-	if (res < 0)
-		goto nla_put_failure;
-
-	res = nla_put_u32(skb_out, HSR_A_IF2_AGE, hsr_node_if2_age);
-	if (res < 0)
-		goto nla_put_failure;
-	res = nla_put_u16(skb_out, HSR_A_IF2_SEQ, hsr_node_if2_seq);
-	if (res < 0)
-		goto nla_put_failure;
-	rcu_read_lock();
-	port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_B);
-	if (port)
-		res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX,
-				  port->dev->ifindex);
-	rcu_read_unlock();
-	if (res < 0)
-		goto nla_put_failure;
-
-	genlmsg_end(skb_out, msg_head);
-	genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid);
-
-	return 0;
-
-invalid:
-	netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
-	return 0;
-
-nla_put_failure:
-	kfree_skb(skb_out);
-	/* Fall through */
-
-fail:
-	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)
 {
-	/* 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;
-	void *pos;
-	unsigned char addr[ETH_ALEN];
-	int res;
-
-	if (!info)
-		goto invalid;
-
-	na = info->attrs[HSR_A_IFINDEX];
-	if (!na)
-		goto invalid;
-
-	hsr_dev = __dev_get_by_index(genl_info_net(info),
-				     nla_get_u32(info->attrs[HSR_A_IFINDEX]));
-	if (!hsr_dev)
-		goto invalid;
-	if (!is_hsr_prp_master(hsr_dev))
-		goto invalid;
-
-	/* Send reply */
-	skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-	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_C_SET_NODE_LIST);
-	if (!msg_head) {
-		res = -ENOMEM;
-		goto nla_put_failure;
-	}
-
-	res = nla_put_u32(skb_out, HSR_A_IFINDEX, hsr_dev->ifindex);
-	if (res < 0)
-		goto nla_put_failure;
-
-	priv = netdev_priv(hsr_dev);
-
-	rcu_read_lock();
-	pos = hsr_prp_get_next_node(priv, NULL, addr);
-	while (pos) {
-		if (!hsr_prp_addr_is_self(priv, addr)) {
-			res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, addr);
-			if (res < 0) {
-				rcu_read_unlock();
-				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;
-
-invalid:
-	netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
-	return 0;
-
-nla_put_failure:
-	kfree_skb(skb_out);
-	/* Fall through */
-
-fail:
-	return res;
+	return hsr_prp_get_node_list(&hsr_genl_family, skb_in, info);
 }
 
 static const struct genl_ops hsr_ops[] = {
 	{
-		.cmd = HSR_C_GET_NODE_STATUS,
+		.cmd = HSR_PRP_C_GET_NODE_STATUS,
 		.flags = 0,
 		.policy = hsr_genl_policy,
 		.doit = hsr_get_node_status,
 		.dumpit = NULL,
 	},
 	{
-		.cmd = HSR_C_GET_NODE_LIST,
+		.cmd = HSR_PRP_C_GET_NODE_LIST,
 		.flags = 0,
 		.policy = hsr_genl_policy,
 		.doit = hsr_get_node_list,
@@ -456,7 +154,7 @@ static struct genl_family hsr_genl_family __ro_after_init = {
 	.hdrsize = 0,
 	.name = "HSR",
 	.version = 1,
-	.maxattr = HSR_A_MAX,
+	.maxattr = HSR_PRP_A_MAX,
 	.module = THIS_MODULE,
 	.ops = hsr_ops,
 	.n_ops = ARRAY_SIZE(hsr_ops),

+ 1 - 1
net/hsr-prp/hsr_netlink.h

@@ -10,7 +10,7 @@
 
 #include <linux/if_ether.h>
 #include <linux/module.h>
-#include <uapi/linux/hsr_netlink.h>
+#include <uapi/linux/hsr_prp_netlink.h>
 
 struct hsr_prp_priv;
 struct hsr_prp_port;

+ 369 - 0
net/hsr-prp/hsr_prp_netlink.c

@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2011-2014 Autronica Fire and Security AS
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author(s):
+ *	2011-2014 Arvid Brodin, arvid.brodin@alten.se
+ *
+ * This file contains device methods for creating, using and destroying
+ * virtual HSR devices.
+ */
+
+#include <linux/kernel.h>
+#include <net/rtnetlink.h>
+#include <net/genetlink.h>
+
+#include "hsr_prp_main.h"
+#include "hsr_prp_netlink.h"
+#include "hsr_prp_device.h"
+#include "hsr_prp_framereg.h"
+
+/* Here, it seems a netdevice has already been allocated for us, and the
+ * hsr_prp_dev_setup routine has been executed. Nice!
+ */
+int hsr_prp_newlink(int proto, 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 mc_lsb, version = 0;
+	char *sproto = (proto == PRP) ? "PRP" : "HSR";
+
+	if (!data) {
+		netdev_info(dev, "%s: No slave devices specified\n", sproto);
+		return -EINVAL;
+	}
+	if (!data[IFLA_HSR_PRP_SLAVE1]) {
+		netdev_info(dev, "%s: Slave1 device not specified\n", sproto);
+		return -EINVAL;
+	}
+	link[0] = __dev_get_by_index(src_net,
+				     nla_get_u32(data[IFLA_HSR_PRP_SLAVE1]));
+	if (!data[IFLA_HSR_PRP_SLAVE2]) {
+		netdev_info(dev, "%s: Slave2 device not specified\n", sproto);
+		return -EINVAL;
+	}
+	link[1] = __dev_get_by_index(src_net,
+				     nla_get_u32(data[IFLA_HSR_PRP_SLAVE2]));
+
+	if (!link[0] || !link[1])
+		return -ENODEV;
+	if (link[0] == link[1])
+		return -EINVAL;
+
+	if (!data[IFLA_HSR_PRP_SF_MC_ADDR_LSB])
+		mc_lsb = 0;
+	else
+		mc_lsb = nla_get_u8(data[IFLA_HSR_PRP_SF_MC_ADDR_LSB]);
+
+	if (proto == PRP) {
+		version = PRP_V1;
+	} else {
+		if (!data[IFLA_HSR_VERSION])
+			version = 0;
+		else
+			version = nla_get_u8(data[IFLA_HSR_VERSION]);
+	}
+
+	return hsr_prp_dev_finalize(dev, link, mc_lsb, version);
+}
+
+int hsr_prp_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+	struct hsr_prp_priv *priv;
+	struct hsr_prp_port *port;
+	int res;
+
+	priv = netdev_priv(dev);
+
+	res = 0;
+
+	rcu_read_lock();
+	port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A);
+	if (port)
+		res = nla_put_u32(skb, IFLA_HSR_PRP_SLAVE1, port->dev->ifindex);
+	rcu_read_unlock();
+	if (res)
+		goto nla_put_failure;
+
+	rcu_read_lock();
+	port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_B);
+	if (port)
+		res = nla_put_u32(skb, IFLA_HSR_PRP_SLAVE2, port->dev->ifindex);
+	rcu_read_unlock();
+	if (res)
+		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 PRP node down\n");
+	rcu_read_unlock();
+}
+
+/* PRP_C_GET_NODE_STATUS lets userspace query the internal PRP node table
+ * about the status of a specific node in the network, defined by its MAC
+ * address.
+ *
+ * Input: hsr ifindex, node mac address
+ * Output: hsr ifindex, node mac address (copied from request),
+ *	   age of latest frame from node over slave 1, slave 2 [ms]
+ */
+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 *ndev;
+
+	/* For sending */
+	struct sk_buff *skb_out;
+	void *msg_head;
+	struct hsr_prp_priv *priv;
+	struct hsr_prp_port *port;
+	unsigned char hsr_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;
+
+	ndev = __dev_get_by_index(genl_info_net(info),
+				  nla_get_u32(info->attrs[HSR_PRP_A_IFINDEX]));
+	if (!ndev)
+		goto invalid;
+	if (!is_hsr_prp_master(ndev))
+		goto invalid;
+
+	/* Send reply */
+	skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	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, ndev->ifindex);
+	if (res < 0)
+		goto nla_put_failure;
+
+	priv = netdev_priv(ndev);
+	res = hsr_prp_get_node_data(priv,
+				    (unsigned char *)
+				    nla_data(info->attrs[HSR_PRP_A_NODE_ADDR]),
+				    hsr_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,
+			      hsr_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;
+	rcu_read_lock();
+	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);
+	rcu_read_unlock();
+	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;
+	rcu_read_lock();
+	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);
+	rcu_read_unlock();
+	if (res < 0)
+		goto nla_put_failure;
+
+	genlmsg_end(skb_out, msg_head);
+	genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid);
+
+	return 0;
+
+invalid:
+	netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
+	return 0;
+
+nla_put_failure:
+	kfree_skb(skb_out);
+	/* Fall through */
+
+fail:
+	return res;
+}
+
+/* Get a list of mac_address_a 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)
+{
+	/* For receiving */
+	struct nlattr *na;
+	struct net_device *ndev;
+
+	/* For sending */
+	struct sk_buff *skb_out;
+	void *msg_head;
+	struct hsr_prp_priv *priv;
+	void *pos;
+	unsigned char addr[ETH_ALEN];
+	int res;
+
+	if (!info)
+		goto invalid;
+
+	na = info->attrs[HSR_PRP_A_IFINDEX];
+	if (!na)
+		goto invalid;
+
+	ndev = __dev_get_by_index(genl_info_net(info),
+				  nla_get_u32(info->attrs[HSR_PRP_A_IFINDEX]));
+	if (!ndev)
+		goto invalid;
+	if (!is_hsr_prp_master(ndev))
+		goto invalid;
+
+	/* Send reply */
+	skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	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;
+	}
+
+	res = nla_put_u32(skb_out, HSR_PRP_A_IFINDEX, ndev->ifindex);
+	if (res < 0)
+		goto nla_put_failure;
+
+	priv = netdev_priv(ndev);
+
+	rcu_read_lock();
+	pos = hsr_prp_get_next_node(priv, NULL, addr);
+	while (pos) {
+		if (!hsr_prp_addr_is_self(priv, addr)) {
+			res = nla_put(skb_out, HSR_PRP_A_NODE_ADDR,
+				      ETH_ALEN, addr);
+			if (res < 0) {
+				rcu_read_unlock();
+				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;
+
+invalid:
+	netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
+	return 0;
+
+nla_put_failure:
+	kfree_skb(skb_out);
+	/* Fall through */
+
+fail:
+	return res;
+}

+ 26 - 0
net/hsr-prp/hsr_prp_netlink.h

@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright 2011-2014 Autronica Fire and Security AS
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author(s):
+ *	2011-2014 Arvid Brodin, arvid.brodin@alten.se
+ *
+ * This file contains device methods for creating, using and destroying
+ * virtual HSR devices.
+ */
+
+#include <uapi/linux/hsr_prp_netlink.h>
+
+int hsr_prp_newlink(int proto, 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 *gen_family,
+			 unsigned char addr[ETH_ALEN]);
+int hsr_prp_get_node_status(struct genl_family *gen_family,
+			    struct sk_buff *skb_in,
+			    struct genl_info *info);
+int hsr_prp_get_node_list(struct genl_family *gen_family,
+			  struct sk_buff *skb_in, struct genl_info *info);

+ 27 - 334
net/hsr-prp/prp_netlink.c

@@ -10,118 +10,49 @@
  */
 
 #include <linux/kernel.h>
-#include <net/rtnetlink.h>
 #include <net/genetlink.h>
+#include <net/rtnetlink.h>
 
 #include "prp_netlink.h"
-#include "hsr_prp_main.h"
 #include "hsr_prp_device.h"
 #include "hsr_prp_framereg.h"
-
-static const struct nla_policy prp_policy[IFLA_PRP_MAX + 1] = {
-	[IFLA_PRP_SLAVE1]		= { .type = NLA_U32 },
-	[IFLA_PRP_SLAVE2]		= { .type = NLA_U32 },
-	[IFLA_PRP_MULTICAST_SPEC]	= { .type = NLA_U8 },
-	[IFLA_PRP_SUPERVISION_ADDR]	= { .len = ETH_ALEN },
-	[IFLA_PRP_SEQ_NR]		= { .type = NLA_U16 },
+#include "hsr_prp_main.h"
+#include "hsr_prp_netlink.h"
+
+static const struct nla_policy prp_policy[IFLA_HSR_PRP_MAX + 1] = {
+	[IFLA_HSR_PRP_SLAVE1]		= { .type = NLA_U32 },
+	[IFLA_HSR_PRP_SLAVE2]		= { .type = NLA_U32 },
+	[IFLA_HSR_PRP_SF_MC_ADDR_LSB]	= { .type = NLA_U8 },
+	[IFLA_HSR_PRP_SF_MC_ADDR]	= { .len = ETH_ALEN },
+	[IFLA_HSR_PRP_SEQ_NR]		= { .type = NLA_U16 },
 };
 
-/* Here, it seems a netdevice has already been allocated for us, and the
- * hsr_prp_dev_setup routine has been executed. Nice!
- */
 static int 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;
-
-	if (!data) {
-		netdev_info(dev, "PRP: No slave devices specified\n");
-		return -EINVAL;
-	}
-	if (!data[IFLA_PRP_SLAVE1]) {
-		netdev_info(dev, "PRP: Slave1 device not specified\n");
-		return -EINVAL;
-	}
-	link[0] = __dev_get_by_index(src_net,
-				     nla_get_u32(data[IFLA_PRP_SLAVE1]));
-	if (!data[IFLA_PRP_SLAVE2]) {
-		netdev_info(dev, "PRP: Slave2 device not specified\n");
-		return -EINVAL;
-	}
-	link[1] = __dev_get_by_index(src_net,
-				     nla_get_u32(data[IFLA_PRP_SLAVE2]));
-
-	if (!link[0] || !link[1])
-		return -ENODEV;
-	if (link[0] == link[1])
-		return -EINVAL;
-
-	if (!data[IFLA_PRP_MULTICAST_SPEC])
-		multicast_spec = 0;
-	else
-		multicast_spec = nla_get_u8(data[IFLA_PRP_MULTICAST_SPEC]);
-
-	return hsr_prp_dev_finalize(dev, link, multicast_spec, PRP_V1);
-}
-
-static int prp_fill_info(struct sk_buff *skb, const struct net_device *dev)
-{
-	struct hsr_prp_priv *priv;
-	struct hsr_prp_port *port;
-	int res;
-
-	priv = netdev_priv(dev);
-
-	res = 0;
-
-	rcu_read_lock();
-	port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A);
-	if (port)
-		res = nla_put_u32(skb, IFLA_PRP_SLAVE1, port->dev->ifindex);
-	rcu_read_unlock();
-	if (res)
-		goto nla_put_failure;
-
-	rcu_read_lock();
-	port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_B);
-	if (port)
-		res = nla_put_u32(skb, IFLA_PRP_SLAVE2, port->dev->ifindex);
-	rcu_read_unlock();
-	if (res)
-		goto nla_put_failure;
-
-	if (nla_put(skb, IFLA_PRP_SUPERVISION_ADDR, ETH_ALEN,
-		    priv->sup_multicast_addr) ||
-	    nla_put_u16(skb, IFLA_PRP_SEQ_NR, priv->sequence_nr))
-		goto nla_put_failure;
-
-	return 0;
-
-nla_put_failure:
-	return -EMSGSIZE;
+	return hsr_prp_newlink(PRP, src_net, dev, tb, data, extack);
 }
 
 static struct rtnl_link_ops prp_link_ops __read_mostly = {
 	.kind		= "prp",
-	.maxtype	= IFLA_PRP_MAX,
+	.maxtype	= IFLA_HSR_PRP_MAX,
 	.policy		= prp_policy,
 	.priv_size	= sizeof(struct hsr_prp_priv),
 	.setup		= prp_dev_setup,
 	.newlink	= prp_newlink,
-	.fill_info	= prp_fill_info,
+	.fill_info	= hsr_prp_fill_info,
 };
 
 /* NLA_BINARY missing in libnl; use NLA_UNSPEC in userspace instead. */
-static const struct nla_policy prp_genl_policy[PRP_A_MAX + 1] = {
-	[PRP_A_NODE_ADDR] = { .type = NLA_BINARY, .len = ETH_ALEN },
-	[PRP_A_NODE_ADDR_B] = { .type = NLA_BINARY, .len = ETH_ALEN },
-	[PRP_A_IFINDEX] = { .type = NLA_U32 },
-	[PRP_A_IF1_AGE] = { .type = NLA_U32 },
-	[PRP_A_IF2_AGE] = { .type = NLA_U32 },
-	[PRP_A_IF1_SEQ] = { .type = NLA_U16 },
-	[PRP_A_IF2_SEQ] = { .type = NLA_U16 },
+static const struct nla_policy prp_genl_policy[HSR_PRP_A_MAX + 1] = {
+	[HSR_PRP_A_NODE_ADDR] = { .type = NLA_BINARY, .len = ETH_ALEN },
+	[HSR_PRP_A_NODE_ADDR_B] = { .type = NLA_BINARY, .len = ETH_ALEN },
+	[HSR_PRP_A_IFINDEX] = { .type = NLA_U32 },
+	[HSR_PRP_A_IF1_AGE] = { .type = NLA_U32 },
+	[HSR_PRP_A_IF2_AGE] = { .type = NLA_U32 },
+	[HSR_PRP_A_IF1_SEQ] = { .type = NLA_U16 },
+	[HSR_PRP_A_IF2_SEQ] = { .type = NLA_U16 },
 };
 
 static struct genl_family prp_genl_family;
@@ -135,267 +66,29 @@ static const struct genl_multicast_group prp_mcgrps[] = {
  */
 void prp_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, &prp_genl_family, 0, PRP_C_NODE_DOWN);
-	if (!msg_head)
-		goto nla_put_failure;
-
-	res = nla_put(skb, PRP_A_NODE_ADDR, ETH_ALEN, addr);
-	if (res < 0)
-		goto nla_put_failure;
-
-	genlmsg_end(skb, msg_head);
-	genlmsg_multicast(&prp_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 PRP node down\n");
-	rcu_read_unlock();
+	hsr_prp_nl_nodedown(priv, &prp_genl_family, addr);
 }
 
-/* PRP_C_GET_NODE_STATUS lets userspace query the internal PRP node table
- * about the status of a specific node in the network, defined by its MAC
- * address.
- *
- * Input: hsr ifindex, node mac address
- * Output: hsr ifindex, node mac address (copied from request),
- *	   age of latest frame from node over slave 1, slave 2 [ms]
- */
 static int prp_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 hsr_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[PRP_A_IFINDEX];
-	if (!na)
-		goto invalid;
-	na = info->attrs[PRP_A_NODE_ADDR];
-	if (!na)
-		goto invalid;
-
-	hsr_dev = __dev_get_by_index(genl_info_net(info),
-				     nla_get_u32(info->attrs[PRP_A_IFINDEX]));
-	if (!hsr_dev)
-		goto invalid;
-	if (!is_hsr_prp_master(hsr_dev))
-		goto invalid;
-
-	/* Send reply */
-	skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-	if (!skb_out) {
-		res = -ENOMEM;
-		goto fail;
-	}
-
-	msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid,
-			       info->snd_seq, &prp_genl_family, 0,
-			       PRP_C_SET_NODE_STATUS);
-	if (!msg_head) {
-		res = -ENOMEM;
-		goto nla_put_failure;
-	}
-
-	res = nla_put_u32(skb_out, 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[PRP_A_NODE_ADDR]),
-				    hsr_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, PRP_A_NODE_ADDR, ETH_ALEN,
-		      nla_data(info->attrs[PRP_A_NODE_ADDR]));
-	if (res < 0)
-		goto nla_put_failure;
-
-	if (addr_b_ifindex > -1) {
-		res = nla_put(skb_out, PRP_A_NODE_ADDR_B, ETH_ALEN,
-			      hsr_node_addr_b);
-		if (res < 0)
-			goto nla_put_failure;
-
-		res = nla_put_u32(skb_out, PRP_A_ADDR_B_IFINDEX,
-				  addr_b_ifindex);
-		if (res < 0)
-			goto nla_put_failure;
-	}
-
-	res = nla_put_u32(skb_out, PRP_A_IF1_AGE, hsr_node_if1_age);
-	if (res < 0)
-		goto nla_put_failure;
-	res = nla_put_u16(skb_out, PRP_A_IF1_SEQ, hsr_node_if1_seq);
-	if (res < 0)
-		goto nla_put_failure;
-	rcu_read_lock();
-	port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A);
-	if (port)
-		res = nla_put_u32(skb_out, PRP_A_IF1_IFINDEX,
-				  port->dev->ifindex);
-	rcu_read_unlock();
-	if (res < 0)
-		goto nla_put_failure;
-
-	res = nla_put_u32(skb_out, PRP_A_IF2_AGE, hsr_node_if2_age);
-	if (res < 0)
-		goto nla_put_failure;
-	res = nla_put_u16(skb_out, PRP_A_IF2_SEQ, hsr_node_if2_seq);
-	if (res < 0)
-		goto nla_put_failure;
-	rcu_read_lock();
-	port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_B);
-	if (port)
-		res = nla_put_u32(skb_out, PRP_A_IF2_IFINDEX,
-				  port->dev->ifindex);
-	rcu_read_unlock();
-	if (res < 0)
-		goto nla_put_failure;
-
-	genlmsg_end(skb_out, msg_head);
-	genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid);
-
-	return 0;
-
-invalid:
-	netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
-	return 0;
-
-nla_put_failure:
-	kfree_skb(skb_out);
-	/* Fall through */
-
-fail:
-	return res;
+	return hsr_prp_get_node_status(&prp_genl_family, skb_in, info);
 }
 
-/* Get a list of mac_address_a of all nodes known to this node (including self).
- */
 static int prp_get_node_list(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;
-	void *pos;
-	unsigned char addr[ETH_ALEN];
-	int res;
-
-	if (!info)
-		goto invalid;
-
-	na = info->attrs[PRP_A_IFINDEX];
-	if (!na)
-		goto invalid;
-
-	hsr_dev = __dev_get_by_index(genl_info_net(info),
-				     nla_get_u32(info->attrs[PRP_A_IFINDEX]));
-	if (!hsr_dev)
-		goto invalid;
-	if (!is_hsr_prp_master(hsr_dev))
-		goto invalid;
-
-	/* Send reply */
-	skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-	if (!skb_out) {
-		res = -ENOMEM;
-		goto fail;
-	}
-
-	msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid,
-			       info->snd_seq, &prp_genl_family, 0,
-			       PRP_C_SET_NODE_LIST);
-	if (!msg_head) {
-		res = -ENOMEM;
-		goto nla_put_failure;
-	}
-
-	res = nla_put_u32(skb_out, PRP_A_IFINDEX, hsr_dev->ifindex);
-	if (res < 0)
-		goto nla_put_failure;
-
-	priv = netdev_priv(hsr_dev);
-
-	rcu_read_lock();
-	pos = hsr_prp_get_next_node(priv, NULL, addr);
-	while (pos) {
-		if (!hsr_prp_addr_is_self(priv, addr)) {
-			res = nla_put(skb_out, PRP_A_NODE_ADDR, ETH_ALEN, addr);
-			if (res < 0) {
-				rcu_read_unlock();
-				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;
-
-invalid:
-	netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
-	return 0;
-
-nla_put_failure:
-	kfree_skb(skb_out);
-	/* Fall through */
-
-fail:
-	return res;
+	return hsr_prp_get_node_list(&prp_genl_family, skb_in, info);
 }
 
 static const struct genl_ops prp_ops[] = {
 	{
-		.cmd = PRP_C_GET_NODE_STATUS,
+		.cmd = HSR_PRP_C_GET_NODE_STATUS,
 		.flags = 0,
 		.policy = prp_genl_policy,
 		.doit = prp_get_node_status,
 		.dumpit = NULL,
 	},
 	{
-		.cmd = PRP_C_GET_NODE_LIST,
+		.cmd = HSR_PRP_C_GET_NODE_LIST,
 		.flags = 0,
 		.policy = prp_genl_policy,
 		.doit = prp_get_node_list,
@@ -407,7 +100,7 @@ static struct genl_family prp_genl_family __ro_after_init = {
 	.hdrsize = 0,
 	.name = "PRP",
 	.version = 1,
-	.maxattr = PRP_A_MAX,
+	.maxattr = HSR_PRP_A_MAX,
 	.module = THIS_MODULE,
 	.ops = prp_ops,
 	.n_ops = ARRAY_SIZE(prp_ops),

+ 1 - 1
net/hsr-prp/prp_netlink.h

@@ -14,7 +14,7 @@
 
 #include <linux/if_ether.h>
 #include <linux/module.h>
-#include <uapi/linux/prp_netlink.h>
+#include <uapi/linux/hsr_prp_netlink.h>
 
 struct hsr_prp_priv;
 struct hsr_prp_port;