|
|
@@ -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),
|