Similar to HSR, add a netlink socket interface code re-using the common functions from hsr_prp_netlink.c. Use wrapper functions for hsr_dev_setup() and prp_dev_setup() to setup HSR/PRP interface by calling common hsr_prp_dev_setup(). Signed-off-by: Murali Karicheri <m-karicheri2@xxxxxx> --- net/hsr-prp/Makefile | 2 +- net/hsr-prp/hsr_netlink.c | 11 ++- net/hsr-prp/hsr_netlink.h | 1 + net/hsr-prp/hsr_prp_device.c | 34 +++++--- net/hsr-prp/hsr_prp_device.h | 3 +- net/hsr-prp/hsr_prp_framereg.c | 6 +- net/hsr-prp/hsr_prp_main.c | 51 ++++++++++-- net/hsr-prp/hsr_prp_main.h | 5 ++ net/hsr-prp/hsr_prp_netlink.c | 80 +++++++++---------- net/hsr-prp/hsr_prp_netlink.h | 5 +- net/hsr-prp/prp_netlink.c | 141 +++++++++++++++++++++++++++++++++ net/hsr-prp/prp_netlink.h | 27 +++++++ 12 files changed, 302 insertions(+), 64 deletions(-) create mode 100644 net/hsr-prp/prp_netlink.c create mode 100644 net/hsr-prp/prp_netlink.h diff --git a/net/hsr-prp/Makefile b/net/hsr-prp/Makefile index 76f266cd1976..9b84b0d813c2 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_netlink.o + hsr_prp_forward.o hsr_prp_netlink.o 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 6bdb369ced36..f14ed521dcb2 100644 --- a/net/hsr-prp/hsr_netlink.c +++ b/net/hsr-prp/hsr_netlink.c @@ -32,7 +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) { - return hsr_prp_newlink(src_net, dev, tb, data, extack); + return hsr_prp_newlink(HSR, src_net, dev, tb, data, extack); } static struct rtnl_link_ops hsr_link_ops __read_mostly = { @@ -40,7 +40,7 @@ static struct rtnl_link_ops hsr_link_ops __read_mostly = { .maxtype = IFLA_HSR_PRP_MAX, .policy = hsr_policy, .priv_size = sizeof(struct hsr_prp_priv), - .setup = hsr_prp_dev_setup, + .setup = hsr_dev_setup, .newlink = hsr_newlink, .fill_info = hsr_prp_fill_info, }; @@ -188,10 +188,15 @@ int __init hsr_netlink_init(void) return rc; } -void __exit hsr_netlink_exit(void) +void hsr_nl_cleanup(void) { genl_unregister_family(&hsr_genl_family); rtnl_link_unregister(&hsr_link_ops); } +void __exit hsr_netlink_exit(void) +{ + hsr_nl_cleanup(); +} + MODULE_ALIAS_RTNL_LINK("hsr"); diff --git a/net/hsr-prp/hsr_netlink.h b/net/hsr-prp/hsr_netlink.h index df3d1acb08e0..b0e96193b09f 100644 --- a/net/hsr-prp/hsr_netlink.h +++ b/net/hsr-prp/hsr_netlink.h @@ -18,6 +18,7 @@ struct hsr_prp_port; int __init hsr_netlink_init(void); void __exit hsr_netlink_exit(void); +void hsr_nl_cleanup(void); void hsr_nl_ringerror(struct hsr_prp_priv *priv, unsigned char addr[ETH_ALEN], struct hsr_prp_port *port); diff --git a/net/hsr-prp/hsr_prp_device.c b/net/hsr-prp/hsr_prp_device.c index 43269c204445..501de23a97f5 100644 --- a/net/hsr-prp/hsr_prp_device.c +++ b/net/hsr-prp/hsr_prp_device.c @@ -321,7 +321,7 @@ static void hsr_prp_announce(struct timer_list *t) rcu_read_lock(); master = hsr_prp_get_port(priv, HSR_PRP_PT_MASTER); - if (priv->announce_count < 3 && priv->prot_version == 0) { + if (priv->announce_count < 3 && priv->prot_version == HSR_V0) { send_hsr_prp_supervision_frame(master, HSR_TLV_ANNOUNCE, priv->prot_version); priv->announce_count++; @@ -384,11 +384,7 @@ static const struct net_device_ops hsr_prp_device_ops = { .ndo_uninit = hsr_prp_dev_destroy, }; -static struct device_type hsr_type = { - .name = "hsr", -}; - -void hsr_prp_dev_setup(struct net_device *dev) +static void hsr_prp_dev_setup(struct net_device *dev, struct device_type *type) { eth_hw_addr_random(dev); @@ -396,7 +392,7 @@ void hsr_prp_dev_setup(struct net_device *dev) dev->min_mtu = 0; dev->header_ops = &hsr_prp_header_ops; dev->netdev_ops = &hsr_prp_device_ops; - SET_NETDEV_DEVTYPE(dev, &hsr_type); + SET_NETDEV_DEVTYPE(dev, type); dev->priv_flags |= IFF_NO_QUEUE; dev->needs_free_netdev = true; @@ -419,6 +415,24 @@ void hsr_prp_dev_setup(struct net_device *dev) dev->features |= NETIF_F_NETNS_LOCAL; } +static struct device_type hsr_type = { + .name = "hsr", +}; + +void hsr_dev_setup(struct net_device *dev) +{ + hsr_prp_dev_setup(dev, &hsr_type); +} + +static struct device_type prp_type = { + .name = "prp", +}; + +void prp_dev_setup(struct net_device *dev) +{ + hsr_prp_dev_setup(dev, &prp_type); +} + /* Return true if dev is a HSR master; return false otherwise. */ inline bool is_hsr_prp_master(struct net_device *dev) @@ -439,6 +453,10 @@ int hsr_prp_dev_finalize(struct net_device *hsr_prp_dev, struct hsr_prp_priv *priv; int res; + /* PRP not supported yet */ + if (protocol_version == PRP_V1) + return -EPROTONOSUPPORT; + priv = netdev_priv(hsr_prp_dev); INIT_LIST_HEAD(&priv->ports); INIT_LIST_HEAD(&priv->node_db); @@ -464,8 +482,6 @@ int hsr_prp_dev_finalize(struct net_device *hsr_prp_dev, ether_addr_copy(priv->sup_multicast_addr, def_multicast_addr); priv->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec; - priv->prot_version = protocol_version; - /* FIXME: should I modify the value of these? * * - hsr_ptp_dev->flags - i.e. diff --git a/net/hsr-prp/hsr_prp_device.h b/net/hsr-prp/hsr_prp_device.h index 4f734a36b2d6..107f1c498442 100644 --- a/net/hsr-prp/hsr_prp_device.h +++ b/net/hsr-prp/hsr_prp_device.h @@ -11,7 +11,8 @@ #include <linux/netdevice.h> #include "hsr_prp_main.h" -void hsr_prp_dev_setup(struct net_device *dev); +void hsr_dev_setup(struct net_device *dev); +void prp_dev_setup(struct net_device *dev); int hsr_prp_dev_finalize(struct net_device *dev, struct net_device *slave[2], unsigned char multicast_spec, u8 protocol_version, struct netlink_ext_ack *extack); diff --git a/net/hsr-prp/hsr_prp_framereg.c b/net/hsr-prp/hsr_prp_framereg.c index d78d32d513ca..42c673befe2c 100644 --- a/net/hsr-prp/hsr_prp_framereg.c +++ b/net/hsr-prp/hsr_prp_framereg.c @@ -17,6 +17,7 @@ #include "hsr_prp_main.h" #include "hsr_prp_framereg.h" #include "hsr_netlink.h" +#include "prp_netlink.h" /* TODO: use hash lists for mac addresses (linux/jhash.h)? */ @@ -443,7 +444,10 @@ void hsr_prp_prune_nodes(struct timer_list *t) /* Prune old entries */ if (time_is_before_jiffies(timestamp + msecs_to_jiffies(HSR_PRP_NODE_FORGET_TIME))) { - hsr_nl_nodedown(priv, node->macaddress_A); + if (priv->prot_version <= HSR_V1) + hsr_nl_nodedown(priv, node->macaddress_A); + else + prp_nl_nodedown(priv, node->macaddress_A); list_del_rcu(&node->mac_list); /* Note that we need to free this entry later: */ kfree_rcu(node, rcu_head); diff --git a/net/hsr-prp/hsr_prp_main.c b/net/hsr-prp/hsr_prp_main.c index 4565744ce1a1..e7e5ca537456 100644 --- a/net/hsr-prp/hsr_prp_main.c +++ b/net/hsr-prp/hsr_prp_main.c @@ -12,6 +12,7 @@ #include "hsr_prp_main.h" #include "hsr_prp_device.h" #include "hsr_netlink.h" +#include "prp_netlink.h" #include "hsr_prp_framereg.h" #include "hsr_prp_slave.h" @@ -25,6 +26,17 @@ static bool hsr_prp_slave_empty(struct hsr_prp_priv *priv) return true; } +static int hsr_prp_netdev_notify(struct notifier_block *nb, unsigned long event, + void *ptr); + +static struct notifier_block hsr_nb = { + .notifier_call = hsr_prp_netdev_notify, /* Slave event notifications */ +}; + +static struct notifier_block prp_nb = { + .notifier_call = hsr_prp_netdev_notify, /* Slave event notifications */ +}; + static int hsr_prp_netdev_notify(struct notifier_block *nb, unsigned long event, void *ptr) { @@ -50,6 +62,11 @@ static int hsr_prp_netdev_notify(struct notifier_block *nb, unsigned long event, priv = port->priv; } + if (priv->prot_version <= HSR_V1 && nb != &hsr_nb) + return NOTIFY_DONE; + else if (priv->prot_version == PRP_V1 && nb != &prp_nb) + return NOTIFY_DONE; + switch (event) { case NETDEV_UP: /* Administrative state DOWN */ case NETDEV_DOWN: /* Administrative state UP */ @@ -127,18 +144,38 @@ struct hsr_prp_port *hsr_prp_get_port(struct hsr_prp_priv *priv, return NULL; } -static struct notifier_block hsr_nb = { - .notifier_call = hsr_prp_netdev_notify, /* Slave event notifications */ -}; - static int __init hsr_prp_init(void) { int res; BUILD_BUG_ON(sizeof(struct hsr_tag) != HSR_PRP_HLEN); - register_netdevice_notifier(&hsr_nb); - res = hsr_netlink_init(); + res = register_netdevice_notifier(&hsr_nb); + if (!res) + res = hsr_netlink_init(); + else + return res; + + if (res) + goto cleanup_hsr_notify; + + res = register_netdevice_notifier(&prp_nb); + if (!res) + res = prp_netlink_init(); + else + goto cleanup_hsr_link; + + if (res) + goto cleanup_prp_notify; + + return res; + +cleanup_prp_notify: + unregister_netdevice_notifier(&prp_nb); +cleanup_hsr_link: + hsr_nl_cleanup(); +cleanup_hsr_notify: + unregister_netdevice_notifier(&hsr_nb); return res; } @@ -146,7 +183,9 @@ static int __init hsr_prp_init(void) static void __exit hsr_prp_exit(void) { unregister_netdevice_notifier(&hsr_nb); + unregister_netdevice_notifier(&prp_nb); hsr_netlink_exit(); + prp_netlink_exit(); hsr_prp_debugfs_remove_root(); } diff --git a/net/hsr-prp/hsr_prp_main.h b/net/hsr-prp/hsr_prp_main.h index 7d9a3e009a2d..00c312e5189f 100644 --- a/net/hsr-prp/hsr_prp_main.h +++ b/net/hsr-prp/hsr_prp_main.h @@ -132,6 +132,8 @@ struct hsr_prp_port { enum hsr_prp_port_type type; }; +#define HSR 0 +#define PRP 1 struct hsr_prp_priv { struct rcu_head rcu_head; struct list_head ports; @@ -145,6 +147,9 @@ struct hsr_prp_priv { u8 prot_version; /* Indicate if HSRv0 or HSRv1. */ spinlock_t seqnr_lock; /* locking for sequence_nr */ spinlock_t list_lock; /* locking for node list */ +#define HSR_V0 0 +#define HSR_V1 1 +#define PRP_V1 2 unsigned char sup_multicast_addr[ETH_ALEN]; #ifdef CONFIG_DEBUG_FS struct dentry *node_tbl_root; diff --git a/net/hsr-prp/hsr_prp_netlink.c b/net/hsr-prp/hsr_prp_netlink.c index 04d51cd97496..865df1dbe621 100644 --- a/net/hsr-prp/hsr_prp_netlink.c +++ b/net/hsr-prp/hsr_prp_netlink.c @@ -12,12 +12,13 @@ #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[], +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 multicast_spec, hsr_version; + unsigned char mc_lsb, version = 0; if (!data) { NL_SET_ERR_MSG_MOD(extack, "No slave devices specified"); @@ -50,23 +51,22 @@ int hsr_prp_newlink(struct net *src_net, struct net_device *dev, } if (!data[IFLA_HSR_PRP_SF_MC_ADDR_LSB]) - multicast_spec = 0; + mc_lsb = 0; else - multicast_spec = nla_get_u8(data[IFLA_HSR_PRP_SF_MC_ADDR_LSB]); + mc_lsb = nla_get_u8(data[IFLA_HSR_PRP_SF_MC_ADDR_LSB]); - if (!data[IFLA_HSR_PRP_VERSION]) { - hsr_version = 0; + if (proto == PRP) { + version = PRP_V1; } else { - hsr_version = nla_get_u8(data[IFLA_HSR_PRP_VERSION]); - if (hsr_version > 1) { + version = nla_get_u8(data[IFLA_HSR_PRP_VERSION]); + if (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); + return hsr_prp_dev_finalize(dev, link, mc_lsb, version, extack); } int hsr_prp_fill_info(struct sk_buff *skb, const struct net_device *dev) @@ -133,7 +133,7 @@ void hsr_prp_nl_nodedown(struct hsr_prp_priv *priv, 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"); + netdev_warn(master->dev, "Could not send HSR/PRP node down\n"); rcu_read_unlock(); } @@ -142,7 +142,7 @@ int hsr_prp_get_node_status(struct genl_family *genl_family, { /* For receiving */ struct nlattr *na; - struct net_device *hsr_dev; + struct net_device *ndev; /* For sending */ struct sk_buff *skb_out; @@ -150,10 +150,10 @@ int hsr_prp_get_node_status(struct genl_family *genl_family, 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 node_if1_age; + u16 node_if1_seq; + int node_if2_age; + u16 node_if2_seq; int addr_b_ifindex; int res; @@ -168,12 +168,11 @@ int hsr_prp_get_node_status(struct genl_family *genl_family, 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) + ndev = __dev_get_by_index(genl_info_net(info), + nla_get_u32(info->attrs[HSR_PRP_A_IFINDEX])); + if (!ndev) goto rcu_unlock; - if (!is_hsr_prp_master(hsr_dev)) + if (!is_hsr_prp_master(ndev)) goto rcu_unlock; /* Send reply */ @@ -191,20 +190,20 @@ int hsr_prp_get_node_status(struct genl_family *genl_family, goto nla_put_failure; } - res = nla_put_u32(skb_out, HSR_PRP_A_IFINDEX, hsr_dev->ifindex); + res = nla_put_u32(skb_out, HSR_PRP_A_IFINDEX, ndev->ifindex); if (res < 0) goto nla_put_failure; - priv = netdev_priv(hsr_dev); + priv = netdev_priv(ndev); 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); + &node_if1_age, + &node_if1_seq, + &node_if2_age, + &node_if2_seq); if (res < 0) goto nla_put_failure; @@ -225,10 +224,10 @@ int hsr_prp_get_node_status(struct genl_family *genl_family, goto nla_put_failure; } - res = nla_put_u32(skb_out, HSR_PRP_A_IF1_AGE, hsr_node_if1_age); + res = nla_put_u32(skb_out, HSR_PRP_A_IF1_AGE, 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); + res = nla_put_u16(skb_out, HSR_PRP_A_IF1_SEQ, node_if1_seq); if (res < 0) goto nla_put_failure; port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_A); @@ -238,10 +237,10 @@ int hsr_prp_get_node_status(struct genl_family *genl_family, if (res < 0) goto nla_put_failure; - res = nla_put_u32(skb_out, HSR_PRP_A_IF2_AGE, hsr_node_if2_age); + res = nla_put_u32(skb_out, HSR_PRP_A_IF2_AGE, 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); + res = nla_put_u16(skb_out, HSR_PRP_A_IF2_SEQ, node_if2_seq); if (res < 0) goto nla_put_failure; port = hsr_prp_get_port(priv, HSR_PRP_PT_SLAVE_B); @@ -273,14 +272,14 @@ int hsr_prp_get_node_status(struct genl_family *genl_family, return res; } -/* Get a list of MacAddressA of all nodes known to this node (including self). +/* 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) { unsigned char addr[ETH_ALEN]; - struct net_device *hsr_dev; struct hsr_prp_priv *priv; + struct net_device *ndev; struct sk_buff *skb_out; bool restart = false; struct nlattr *na; @@ -296,12 +295,11 @@ int hsr_prp_get_node_list(struct genl_family *genl_family, 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) + ndev = __dev_get_by_index(genl_info_net(info), + nla_get_u32(info->attrs[HSR_PRP_A_IFINDEX])); + if (!ndev) goto rcu_unlock; - if (!is_hsr_prp_master(hsr_dev)) + if (!is_hsr_prp_master(ndev)) goto rcu_unlock; restart: @@ -321,12 +319,12 @@ int hsr_prp_get_node_list(struct genl_family *genl_family, } if (!restart) { - res = nla_put_u32(skb_out, HSR_PRP_A_IFINDEX, hsr_dev->ifindex); + res = nla_put_u32(skb_out, HSR_PRP_A_IFINDEX, ndev->ifindex); if (res < 0) goto nla_put_failure; } - priv = netdev_priv(hsr_dev); + priv = netdev_priv(ndev); if (!pos) pos = hsr_prp_get_next_node(priv, NULL, addr); diff --git a/net/hsr-prp/hsr_prp_netlink.h b/net/hsr-prp/hsr_prp_netlink.h index a3a4e6252e45..5bd0f8cf2644 100644 --- a/net/hsr-prp/hsr_prp_netlink.h +++ b/net/hsr-prp/hsr_prp_netlink.h @@ -13,8 +13,9 @@ #include "hsr_prp_main.h" -int hsr_prp_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[], +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, diff --git a/net/hsr-prp/prp_netlink.c b/net/hsr-prp/prp_netlink.c new file mode 100644 index 000000000000..d6c0a64e0a84 --- /dev/null +++ b/net/hsr-prp/prp_netlink.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0 +/* This is based on hsr_netlink.c from Arvid Brodin, arvid.brodin@xxxxxxxx + * + * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com + * + * Author(s): + * Murali Karicheri <m-karicheri2@xxxxxx> + * Routines for handling Netlink messages for PRP + */ + +#include <linux/kernel.h> +#include <net/genetlink.h> +#include <net/rtnetlink.h> + +#include "prp_netlink.h" +#include "hsr_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_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) +{ + 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_HSR_PRP_MAX, + .policy = prp_policy, + .priv_size = sizeof(struct hsr_prp_priv), + .setup = prp_dev_setup, + .newlink = prp_newlink, + .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[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; + +static const struct genl_multicast_group prp_mcgrps[] = { + { .name = "prp-network", }, +}; + +/* 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 prp_nl_nodedown(struct hsr_prp_priv *priv, unsigned char addr[ETH_ALEN]) +{ + hsr_prp_nl_nodedown(priv, &prp_genl_family, addr); +} + +static int prp_get_node_status(struct sk_buff *skb_in, struct genl_info *info) +{ + return hsr_prp_get_node_status(&prp_genl_family, skb_in, info); +} + +static int prp_get_node_list(struct sk_buff *skb_in, struct genl_info *info) +{ + return hsr_prp_get_node_list(&prp_genl_family, skb_in, info); +} + +static const struct genl_ops prp_ops[] = { + { + .cmd = HSR_PRP_C_GET_NODE_STATUS, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = 0, + .doit = prp_get_node_status, + .dumpit = NULL, + }, + { + .cmd = HSR_PRP_C_GET_NODE_LIST, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = 0, + .doit = prp_get_node_list, + .dumpit = NULL, + }, +}; + +static struct genl_family prp_genl_family __ro_after_init = { + .hdrsize = 0, + .name = "PRP", + .version = 1, + .maxattr = HSR_PRP_A_MAX, + .policy = prp_genl_policy, + .module = THIS_MODULE, + .ops = prp_ops, + .n_ops = ARRAY_SIZE(prp_ops), + .mcgrps = prp_mcgrps, + .n_mcgrps = ARRAY_SIZE(prp_mcgrps), +}; + +int __init prp_netlink_init(void) +{ + int rc; + + rc = rtnl_link_register(&prp_link_ops); + if (rc) + goto fail_rtnl_link_register; + + rc = genl_register_family(&prp_genl_family); + if (rc) + goto fail_genl_register_family; + + return 0; + +fail_genl_register_family: + rtnl_link_unregister(&prp_link_ops); +fail_rtnl_link_register: + + return rc; +} + +void __exit prp_netlink_exit(void) +{ + genl_unregister_family(&prp_genl_family); + rtnl_link_unregister(&prp_link_ops); +} + +MODULE_ALIAS_RTNL_LINK("prp"); diff --git a/net/hsr-prp/prp_netlink.h b/net/hsr-prp/prp_netlink.h new file mode 100644 index 000000000000..ad43b33b5bfb --- /dev/null +++ b/net/hsr-prp/prp_netlink.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* prp_netlink.h: + * This is based on hsr_netlink.h from Arvid Brodin, arvid.brodin@xxxxxxxx + * + * Copyright (C) 2017-2020 Texas Instruments Incorporated - http://www.ti.com + * + * Author(s): + * Murali Karicheri <m-karicheri2@xxxxxx> + */ + +#ifndef __PRP_NETLINK_H +#define __PRP_NETLINK_H + +#include <linux/if_ether.h> +#include <linux/module.h> + +#include <uapi/linux/hsr_prp_netlink.h> + +struct hsr_prp_priv; +struct hsr_prp_port; + +int __init prp_netlink_init(void); +void __exit prp_netlink_exit(void); + +void prp_nl_nodedown(struct hsr_prp_priv *priv, unsigned char addr[ETH_ALEN]); + +#endif /* __PRP_NETLINK_H */ -- 2.17.1