xref: /openbmc/linux/net/hsr/hsr_netlink.c (revision ee1c2797)
170ebe4a4SArvid Brodin /* Copyright 2011-2014 Autronica Fire and Security AS
2f421436aSArvid Brodin  *
3f421436aSArvid Brodin  * This program is free software; you can redistribute it and/or modify it
4f421436aSArvid Brodin  * under the terms of the GNU General Public License as published by the Free
5f421436aSArvid Brodin  * Software Foundation; either version 2 of the License, or (at your option)
6f421436aSArvid Brodin  * any later version.
7f421436aSArvid Brodin  *
8f421436aSArvid Brodin  * Author(s):
970ebe4a4SArvid Brodin  *	2011-2014 Arvid Brodin, arvid.brodin@alten.se
10f421436aSArvid Brodin  *
11f421436aSArvid Brodin  * Routines for handling Netlink messages for HSR.
12f421436aSArvid Brodin  */
13f421436aSArvid Brodin 
14f421436aSArvid Brodin #include "hsr_netlink.h"
15f421436aSArvid Brodin #include <linux/kernel.h>
16f421436aSArvid Brodin #include <net/rtnetlink.h>
17f421436aSArvid Brodin #include <net/genetlink.h>
18f421436aSArvid Brodin #include "hsr_main.h"
19f421436aSArvid Brodin #include "hsr_device.h"
20f421436aSArvid Brodin #include "hsr_framereg.h"
21f421436aSArvid Brodin 
22f421436aSArvid Brodin static const struct nla_policy hsr_policy[IFLA_HSR_MAX + 1] = {
23f421436aSArvid Brodin 	[IFLA_HSR_SLAVE1]		= { .type = NLA_U32 },
24f421436aSArvid Brodin 	[IFLA_HSR_SLAVE2]		= { .type = NLA_U32 },
25f421436aSArvid Brodin 	[IFLA_HSR_MULTICAST_SPEC]	= { .type = NLA_U8 },
26ee1c2797SPeter Heise 	[IFLA_HSR_VERSION]	= { .type = NLA_U8 },
2798bf8362SArvid Brodin 	[IFLA_HSR_SUPERVISION_ADDR]	= { .type = NLA_BINARY, .len = ETH_ALEN },
2898bf8362SArvid Brodin 	[IFLA_HSR_SEQ_NR]		= { .type = NLA_U16 },
29f421436aSArvid Brodin };
30f421436aSArvid Brodin 
31f421436aSArvid Brodin 
32f421436aSArvid Brodin /* Here, it seems a netdevice has already been allocated for us, and the
33f421436aSArvid Brodin  * hsr_dev_setup routine has been executed. Nice!
34f421436aSArvid Brodin  */
35f421436aSArvid Brodin static int hsr_newlink(struct net *src_net, struct net_device *dev,
36f421436aSArvid Brodin 		       struct nlattr *tb[], struct nlattr *data[])
37f421436aSArvid Brodin {
38f421436aSArvid Brodin 	struct net_device *link[2];
39ee1c2797SPeter Heise 	unsigned char multicast_spec, hsr_version;
40f421436aSArvid Brodin 
41a718dcc5SArvid Brodin 	if (!data) {
42a718dcc5SArvid Brodin 		netdev_info(dev, "HSR: No slave devices specified\n");
43a718dcc5SArvid Brodin 		return -EINVAL;
44a718dcc5SArvid Brodin 	}
45f421436aSArvid Brodin 	if (!data[IFLA_HSR_SLAVE1]) {
46a718dcc5SArvid Brodin 		netdev_info(dev, "HSR: Slave1 device not specified\n");
47f421436aSArvid Brodin 		return -EINVAL;
48f421436aSArvid Brodin 	}
49f421436aSArvid Brodin 	link[0] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE1]));
50f421436aSArvid Brodin 	if (!data[IFLA_HSR_SLAVE2]) {
51a718dcc5SArvid Brodin 		netdev_info(dev, "HSR: Slave2 device not specified\n");
52f421436aSArvid Brodin 		return -EINVAL;
53f421436aSArvid Brodin 	}
54f421436aSArvid Brodin 	link[1] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE2]));
55f421436aSArvid Brodin 
56f421436aSArvid Brodin 	if (!link[0] || !link[1])
57f421436aSArvid Brodin 		return -ENODEV;
58f421436aSArvid Brodin 	if (link[0] == link[1])
59f421436aSArvid Brodin 		return -EINVAL;
60f421436aSArvid Brodin 
61f421436aSArvid Brodin 	if (!data[IFLA_HSR_MULTICAST_SPEC])
62f421436aSArvid Brodin 		multicast_spec = 0;
63f421436aSArvid Brodin 	else
64f421436aSArvid Brodin 		multicast_spec = nla_get_u8(data[IFLA_HSR_MULTICAST_SPEC]);
65f421436aSArvid Brodin 
66ee1c2797SPeter Heise 	if (!data[IFLA_HSR_VERSION])
67ee1c2797SPeter Heise 		hsr_version = 0;
68ee1c2797SPeter Heise 	else
69ee1c2797SPeter Heise 		hsr_version = nla_get_u8(data[IFLA_HSR_VERSION]);
70ee1c2797SPeter Heise 
71ee1c2797SPeter Heise 	return hsr_dev_finalize(dev, link, multicast_spec, hsr_version);
72f421436aSArvid Brodin }
73f421436aSArvid Brodin 
7498bf8362SArvid Brodin static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev)
7598bf8362SArvid Brodin {
7670ebe4a4SArvid Brodin 	struct hsr_priv *hsr;
77c5a75911SArvid Brodin 	struct hsr_port *port;
7851f3c605SArvid Brodin 	int res;
7998bf8362SArvid Brodin 
8070ebe4a4SArvid Brodin 	hsr = netdev_priv(dev);
8198bf8362SArvid Brodin 
8251f3c605SArvid Brodin 	res = 0;
8351f3c605SArvid Brodin 
8451f3c605SArvid Brodin 	rcu_read_lock();
85c5a75911SArvid Brodin 	port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A);
86c5a75911SArvid Brodin 	if (port)
87c5a75911SArvid Brodin 		res = nla_put_u32(skb, IFLA_HSR_SLAVE1, port->dev->ifindex);
8851f3c605SArvid Brodin 	rcu_read_unlock();
8951f3c605SArvid Brodin 	if (res)
9098bf8362SArvid Brodin 		goto nla_put_failure;
9198bf8362SArvid Brodin 
9251f3c605SArvid Brodin 	rcu_read_lock();
93c5a75911SArvid Brodin 	port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B);
94c5a75911SArvid Brodin 	if (port)
95c5a75911SArvid Brodin 		res = nla_put_u32(skb, IFLA_HSR_SLAVE2, port->dev->ifindex);
9651f3c605SArvid Brodin 	rcu_read_unlock();
9751f3c605SArvid Brodin 	if (res)
9898bf8362SArvid Brodin 		goto nla_put_failure;
9998bf8362SArvid Brodin 
10098bf8362SArvid Brodin 	if (nla_put(skb, IFLA_HSR_SUPERVISION_ADDR, ETH_ALEN,
10170ebe4a4SArvid Brodin 		    hsr->sup_multicast_addr) ||
10270ebe4a4SArvid Brodin 	    nla_put_u16(skb, IFLA_HSR_SEQ_NR, hsr->sequence_nr))
10398bf8362SArvid Brodin 		goto nla_put_failure;
10498bf8362SArvid Brodin 
10598bf8362SArvid Brodin 	return 0;
10698bf8362SArvid Brodin 
10798bf8362SArvid Brodin nla_put_failure:
10898bf8362SArvid Brodin 	return -EMSGSIZE;
10998bf8362SArvid Brodin }
11098bf8362SArvid Brodin 
111f421436aSArvid Brodin static struct rtnl_link_ops hsr_link_ops __read_mostly = {
112f421436aSArvid Brodin 	.kind		= "hsr",
113f421436aSArvid Brodin 	.maxtype	= IFLA_HSR_MAX,
114f421436aSArvid Brodin 	.policy		= hsr_policy,
115f421436aSArvid Brodin 	.priv_size	= sizeof(struct hsr_priv),
116f421436aSArvid Brodin 	.setup		= hsr_dev_setup,
117f421436aSArvid Brodin 	.newlink	= hsr_newlink,
11898bf8362SArvid Brodin 	.fill_info	= hsr_fill_info,
119f421436aSArvid Brodin };
120f421436aSArvid Brodin 
121f421436aSArvid Brodin 
122f421436aSArvid Brodin 
123f421436aSArvid Brodin /* attribute policy */
124f421436aSArvid Brodin /* NLA_BINARY missing in libnl; use NLA_UNSPEC in userspace instead. */
125f421436aSArvid Brodin static const struct nla_policy hsr_genl_policy[HSR_A_MAX + 1] = {
126f421436aSArvid Brodin 	[HSR_A_NODE_ADDR] = { .type = NLA_BINARY, .len = ETH_ALEN },
127f421436aSArvid Brodin 	[HSR_A_NODE_ADDR_B] = { .type = NLA_BINARY, .len = ETH_ALEN },
128f421436aSArvid Brodin 	[HSR_A_IFINDEX] = { .type = NLA_U32 },
129f421436aSArvid Brodin 	[HSR_A_IF1_AGE] = { .type = NLA_U32 },
130f421436aSArvid Brodin 	[HSR_A_IF2_AGE] = { .type = NLA_U32 },
131f421436aSArvid Brodin 	[HSR_A_IF1_SEQ] = { .type = NLA_U16 },
132f421436aSArvid Brodin 	[HSR_A_IF2_SEQ] = { .type = NLA_U16 },
133f421436aSArvid Brodin };
134f421436aSArvid Brodin 
135f421436aSArvid Brodin static struct genl_family hsr_genl_family = {
136f421436aSArvid Brodin 	.id = GENL_ID_GENERATE,
137f421436aSArvid Brodin 	.hdrsize = 0,
138f421436aSArvid Brodin 	.name = "HSR",
139f421436aSArvid Brodin 	.version = 1,
140f421436aSArvid Brodin 	.maxattr = HSR_A_MAX,
141f421436aSArvid Brodin };
142f421436aSArvid Brodin 
1432a94fe48SJohannes Berg static const struct genl_multicast_group hsr_mcgrps[] = {
1442a94fe48SJohannes Berg 	{ .name = "hsr-network", },
145f421436aSArvid Brodin };
146f421436aSArvid Brodin 
147f421436aSArvid Brodin 
148f421436aSArvid Brodin 
149f421436aSArvid Brodin /* This is called if for some node with MAC address addr, we only get frames
150f421436aSArvid Brodin  * over one of the slave interfaces. This would indicate an open network ring
151f421436aSArvid Brodin  * (i.e. a link has failed somewhere).
152f421436aSArvid Brodin  */
15370ebe4a4SArvid Brodin void hsr_nl_ringerror(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN],
154c5a75911SArvid Brodin 		      struct hsr_port *port)
155f421436aSArvid Brodin {
156f421436aSArvid Brodin 	struct sk_buff *skb;
157f421436aSArvid Brodin 	void *msg_head;
158c5a75911SArvid Brodin 	struct hsr_port *master;
159f421436aSArvid Brodin 	int res;
160f421436aSArvid Brodin 
161f421436aSArvid Brodin 	skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
162f421436aSArvid Brodin 	if (!skb)
163f421436aSArvid Brodin 		goto fail;
164f421436aSArvid Brodin 
165f421436aSArvid Brodin 	msg_head = genlmsg_put(skb, 0, 0, &hsr_genl_family, 0, HSR_C_RING_ERROR);
166f421436aSArvid Brodin 	if (!msg_head)
167f421436aSArvid Brodin 		goto nla_put_failure;
168f421436aSArvid Brodin 
169f421436aSArvid Brodin 	res = nla_put(skb, HSR_A_NODE_ADDR, ETH_ALEN, addr);
170f421436aSArvid Brodin 	if (res < 0)
171f421436aSArvid Brodin 		goto nla_put_failure;
172f421436aSArvid Brodin 
173c5a75911SArvid Brodin 	res = nla_put_u32(skb, HSR_A_IFINDEX, port->dev->ifindex);
174f421436aSArvid Brodin 	if (res < 0)
175f421436aSArvid Brodin 		goto nla_put_failure;
176f421436aSArvid Brodin 
177f421436aSArvid Brodin 	genlmsg_end(skb, msg_head);
1782a94fe48SJohannes Berg 	genlmsg_multicast(&hsr_genl_family, skb, 0, 0, GFP_ATOMIC);
179f421436aSArvid Brodin 
180f421436aSArvid Brodin 	return;
181f421436aSArvid Brodin 
182f421436aSArvid Brodin nla_put_failure:
183f421436aSArvid Brodin 	kfree_skb(skb);
184f421436aSArvid Brodin 
185f421436aSArvid Brodin fail:
186c5a75911SArvid Brodin 	rcu_read_lock();
187c5a75911SArvid Brodin 	master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
188c5a75911SArvid Brodin 	netdev_warn(master->dev, "Could not send HSR ring error message\n");
189c5a75911SArvid Brodin 	rcu_read_unlock();
190f421436aSArvid Brodin }
191f421436aSArvid Brodin 
192f421436aSArvid Brodin /* This is called when we haven't heard from the node with MAC address addr for
193f421436aSArvid Brodin  * some time (just before the node is removed from the node table/list).
194f421436aSArvid Brodin  */
19570ebe4a4SArvid Brodin void hsr_nl_nodedown(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN])
196f421436aSArvid Brodin {
197f421436aSArvid Brodin 	struct sk_buff *skb;
198f421436aSArvid Brodin 	void *msg_head;
199c5a75911SArvid Brodin 	struct hsr_port *master;
200f421436aSArvid Brodin 	int res;
201f421436aSArvid Brodin 
202f421436aSArvid Brodin 	skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
203f421436aSArvid Brodin 	if (!skb)
204f421436aSArvid Brodin 		goto fail;
205f421436aSArvid Brodin 
206f421436aSArvid Brodin 	msg_head = genlmsg_put(skb, 0, 0, &hsr_genl_family, 0, HSR_C_NODE_DOWN);
207f421436aSArvid Brodin 	if (!msg_head)
208f421436aSArvid Brodin 		goto nla_put_failure;
209f421436aSArvid Brodin 
210f421436aSArvid Brodin 
211f421436aSArvid Brodin 	res = nla_put(skb, HSR_A_NODE_ADDR, ETH_ALEN, addr);
212f421436aSArvid Brodin 	if (res < 0)
213f421436aSArvid Brodin 		goto nla_put_failure;
214f421436aSArvid Brodin 
215f421436aSArvid Brodin 	genlmsg_end(skb, msg_head);
2162a94fe48SJohannes Berg 	genlmsg_multicast(&hsr_genl_family, skb, 0, 0, GFP_ATOMIC);
217f421436aSArvid Brodin 
218f421436aSArvid Brodin 	return;
219f421436aSArvid Brodin 
220f421436aSArvid Brodin nla_put_failure:
221f421436aSArvid Brodin 	kfree_skb(skb);
222f421436aSArvid Brodin 
223f421436aSArvid Brodin fail:
224c5a75911SArvid Brodin 	rcu_read_lock();
225c5a75911SArvid Brodin 	master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
226c5a75911SArvid Brodin 	netdev_warn(master->dev, "Could not send HSR node down\n");
227c5a75911SArvid Brodin 	rcu_read_unlock();
228f421436aSArvid Brodin }
229f421436aSArvid Brodin 
230f421436aSArvid Brodin 
231f421436aSArvid Brodin /* HSR_C_GET_NODE_STATUS lets userspace query the internal HSR node table
232f421436aSArvid Brodin  * about the status of a specific node in the network, defined by its MAC
233f421436aSArvid Brodin  * address.
234f421436aSArvid Brodin  *
235f421436aSArvid Brodin  * Input: hsr ifindex, node mac address
236f421436aSArvid Brodin  * Output: hsr ifindex, node mac address (copied from request),
237f421436aSArvid Brodin  *	   age of latest frame from node over slave 1, slave 2 [ms]
238f421436aSArvid Brodin  */
239f421436aSArvid Brodin static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
240f421436aSArvid Brodin {
241f421436aSArvid Brodin 	/* For receiving */
242f421436aSArvid Brodin 	struct nlattr *na;
243c5a75911SArvid Brodin 	struct net_device *hsr_dev;
244f421436aSArvid Brodin 
245f421436aSArvid Brodin 	/* For sending */
246f421436aSArvid Brodin 	struct sk_buff *skb_out;
247f421436aSArvid Brodin 	void *msg_head;
24870ebe4a4SArvid Brodin 	struct hsr_priv *hsr;
249c5a75911SArvid Brodin 	struct hsr_port *port;
250f421436aSArvid Brodin 	unsigned char hsr_node_addr_b[ETH_ALEN];
251f421436aSArvid Brodin 	int hsr_node_if1_age;
252f421436aSArvid Brodin 	u16 hsr_node_if1_seq;
253f421436aSArvid Brodin 	int hsr_node_if2_age;
254f421436aSArvid Brodin 	u16 hsr_node_if2_seq;
255f421436aSArvid Brodin 	int addr_b_ifindex;
256f421436aSArvid Brodin 	int res;
257f421436aSArvid Brodin 
258f421436aSArvid Brodin 	if (!info)
259f421436aSArvid Brodin 		goto invalid;
260f421436aSArvid Brodin 
261f421436aSArvid Brodin 	na = info->attrs[HSR_A_IFINDEX];
262f421436aSArvid Brodin 	if (!na)
263f421436aSArvid Brodin 		goto invalid;
264f421436aSArvid Brodin 	na = info->attrs[HSR_A_NODE_ADDR];
265f421436aSArvid Brodin 	if (!na)
266f421436aSArvid Brodin 		goto invalid;
267f421436aSArvid Brodin 
268f421436aSArvid Brodin 	hsr_dev = __dev_get_by_index(genl_info_net(info),
269f421436aSArvid Brodin 					nla_get_u32(info->attrs[HSR_A_IFINDEX]));
270f421436aSArvid Brodin 	if (!hsr_dev)
271f421436aSArvid Brodin 		goto invalid;
272f421436aSArvid Brodin 	if (!is_hsr_master(hsr_dev))
273f421436aSArvid Brodin 		goto invalid;
274f421436aSArvid Brodin 
275f421436aSArvid Brodin 
276f421436aSArvid Brodin 	/* Send reply */
277f421436aSArvid Brodin 
278f421436aSArvid Brodin 	skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
279f421436aSArvid Brodin 	if (!skb_out) {
280f421436aSArvid Brodin 		res = -ENOMEM;
281f421436aSArvid Brodin 		goto fail;
282f421436aSArvid Brodin 	}
283f421436aSArvid Brodin 
284f421436aSArvid Brodin 	msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid,
285f421436aSArvid Brodin 				info->snd_seq, &hsr_genl_family, 0,
286f421436aSArvid Brodin 				HSR_C_SET_NODE_STATUS);
287f421436aSArvid Brodin 	if (!msg_head) {
288f421436aSArvid Brodin 		res = -ENOMEM;
289f421436aSArvid Brodin 		goto nla_put_failure;
290f421436aSArvid Brodin 	}
291f421436aSArvid Brodin 
292f421436aSArvid Brodin 	res = nla_put_u32(skb_out, HSR_A_IFINDEX, hsr_dev->ifindex);
293f421436aSArvid Brodin 	if (res < 0)
294f421436aSArvid Brodin 		goto nla_put_failure;
295f421436aSArvid Brodin 
29670ebe4a4SArvid Brodin 	hsr = netdev_priv(hsr_dev);
29770ebe4a4SArvid Brodin 	res = hsr_get_node_data(hsr,
298f421436aSArvid Brodin 			(unsigned char *) nla_data(info->attrs[HSR_A_NODE_ADDR]),
299f421436aSArvid Brodin 			hsr_node_addr_b,
300f421436aSArvid Brodin 			&addr_b_ifindex,
301f421436aSArvid Brodin 			&hsr_node_if1_age,
302f421436aSArvid Brodin 			&hsr_node_if1_seq,
303f421436aSArvid Brodin 			&hsr_node_if2_age,
304f421436aSArvid Brodin 			&hsr_node_if2_seq);
305f421436aSArvid Brodin 	if (res < 0)
30684a035f6SGeyslan G. Bem 		goto nla_put_failure;
307f421436aSArvid Brodin 
308f421436aSArvid Brodin 	res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN,
309f421436aSArvid Brodin 					nla_data(info->attrs[HSR_A_NODE_ADDR]));
310f421436aSArvid Brodin 	if (res < 0)
311f421436aSArvid Brodin 		goto nla_put_failure;
312f421436aSArvid Brodin 
313f421436aSArvid Brodin 	if (addr_b_ifindex > -1) {
314f421436aSArvid Brodin 		res = nla_put(skb_out, HSR_A_NODE_ADDR_B, ETH_ALEN,
315f421436aSArvid Brodin 								hsr_node_addr_b);
316f421436aSArvid Brodin 		if (res < 0)
317f421436aSArvid Brodin 			goto nla_put_failure;
318f421436aSArvid Brodin 
319f421436aSArvid Brodin 		res = nla_put_u32(skb_out, HSR_A_ADDR_B_IFINDEX, addr_b_ifindex);
320f421436aSArvid Brodin 		if (res < 0)
321f421436aSArvid Brodin 			goto nla_put_failure;
322f421436aSArvid Brodin 	}
323f421436aSArvid Brodin 
324f421436aSArvid Brodin 	res = nla_put_u32(skb_out, HSR_A_IF1_AGE, hsr_node_if1_age);
325f421436aSArvid Brodin 	if (res < 0)
326f421436aSArvid Brodin 		goto nla_put_failure;
327f421436aSArvid Brodin 	res = nla_put_u16(skb_out, HSR_A_IF1_SEQ, hsr_node_if1_seq);
328f421436aSArvid Brodin 	if (res < 0)
329f421436aSArvid Brodin 		goto nla_put_failure;
33051f3c605SArvid Brodin 	rcu_read_lock();
331c5a75911SArvid Brodin 	port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A);
332c5a75911SArvid Brodin 	if (port)
333c5a75911SArvid Brodin 		res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX,
334c5a75911SArvid Brodin 				  port->dev->ifindex);
33551f3c605SArvid Brodin 	rcu_read_unlock();
336f421436aSArvid Brodin 	if (res < 0)
337f421436aSArvid Brodin 		goto nla_put_failure;
338f421436aSArvid Brodin 
339f421436aSArvid Brodin 	res = nla_put_u32(skb_out, HSR_A_IF2_AGE, hsr_node_if2_age);
340f421436aSArvid Brodin 	if (res < 0)
341f421436aSArvid Brodin 		goto nla_put_failure;
342f421436aSArvid Brodin 	res = nla_put_u16(skb_out, HSR_A_IF2_SEQ, hsr_node_if2_seq);
343f421436aSArvid Brodin 	if (res < 0)
344f421436aSArvid Brodin 		goto nla_put_failure;
34551f3c605SArvid Brodin 	rcu_read_lock();
346c5a75911SArvid Brodin 	port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B);
347c5a75911SArvid Brodin 	if (port)
348c5a75911SArvid Brodin 		res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX,
349c5a75911SArvid Brodin 				  port->dev->ifindex);
35051f3c605SArvid Brodin 	rcu_read_unlock();
35151f3c605SArvid Brodin 	if (res < 0)
35251f3c605SArvid Brodin 		goto nla_put_failure;
353f421436aSArvid Brodin 
354f421436aSArvid Brodin 	genlmsg_end(skb_out, msg_head);
355f421436aSArvid Brodin 	genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid);
356f421436aSArvid Brodin 
357f421436aSArvid Brodin 	return 0;
358f421436aSArvid Brodin 
359f421436aSArvid Brodin invalid:
360f421436aSArvid Brodin 	netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL);
361f421436aSArvid Brodin 	return 0;
362f421436aSArvid Brodin 
363f421436aSArvid Brodin nla_put_failure:
364f421436aSArvid Brodin 	kfree_skb(skb_out);
365f421436aSArvid Brodin 	/* Fall through */
366f421436aSArvid Brodin 
367f421436aSArvid Brodin fail:
368f421436aSArvid Brodin 	return res;
369f421436aSArvid Brodin }
370f421436aSArvid Brodin 
371f266a683SArvid Brodin /* Get a list of MacAddressA of all nodes known to this node (including self).
372f421436aSArvid Brodin  */
373f421436aSArvid Brodin static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
374f421436aSArvid Brodin {
375f421436aSArvid Brodin 	/* For receiving */
376f421436aSArvid Brodin 	struct nlattr *na;
377f421436aSArvid Brodin 	struct net_device *hsr_dev;
378f421436aSArvid Brodin 
379f421436aSArvid Brodin 	/* For sending */
380f421436aSArvid Brodin 	struct sk_buff *skb_out;
381f421436aSArvid Brodin 	void *msg_head;
38270ebe4a4SArvid Brodin 	struct hsr_priv *hsr;
383f421436aSArvid Brodin 	void *pos;
384f421436aSArvid Brodin 	unsigned char addr[ETH_ALEN];
385f421436aSArvid Brodin 	int res;
386f421436aSArvid Brodin 
387f421436aSArvid Brodin 	if (!info)
388f421436aSArvid Brodin 		goto invalid;
389f421436aSArvid Brodin 
390f421436aSArvid Brodin 	na = info->attrs[HSR_A_IFINDEX];
391f421436aSArvid Brodin 	if (!na)
392f421436aSArvid Brodin 		goto invalid;
393f421436aSArvid Brodin 
394f421436aSArvid Brodin 	hsr_dev = __dev_get_by_index(genl_info_net(info),
395f421436aSArvid Brodin 				     nla_get_u32(info->attrs[HSR_A_IFINDEX]));
396f421436aSArvid Brodin 	if (!hsr_dev)
397f421436aSArvid Brodin 		goto invalid;
398f421436aSArvid Brodin 	if (!is_hsr_master(hsr_dev))
399f421436aSArvid Brodin 		goto invalid;
400f421436aSArvid Brodin 
401f421436aSArvid Brodin 
402f421436aSArvid Brodin 	/* Send reply */
403f421436aSArvid Brodin 
404f421436aSArvid Brodin 	skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
405f421436aSArvid Brodin 	if (!skb_out) {
406f421436aSArvid Brodin 		res = -ENOMEM;
407f421436aSArvid Brodin 		goto fail;
408f421436aSArvid Brodin 	}
409f421436aSArvid Brodin 
410f421436aSArvid Brodin 	msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid,
411f421436aSArvid Brodin 				info->snd_seq, &hsr_genl_family, 0,
412f421436aSArvid Brodin 				HSR_C_SET_NODE_LIST);
413f421436aSArvid Brodin 	if (!msg_head) {
414f421436aSArvid Brodin 		res = -ENOMEM;
415f421436aSArvid Brodin 		goto nla_put_failure;
416f421436aSArvid Brodin 	}
417f421436aSArvid Brodin 
418f421436aSArvid Brodin 	res = nla_put_u32(skb_out, HSR_A_IFINDEX, hsr_dev->ifindex);
419f421436aSArvid Brodin 	if (res < 0)
420f421436aSArvid Brodin 		goto nla_put_failure;
421f421436aSArvid Brodin 
42270ebe4a4SArvid Brodin 	hsr = netdev_priv(hsr_dev);
423f421436aSArvid Brodin 
424f421436aSArvid Brodin 	rcu_read_lock();
42570ebe4a4SArvid Brodin 	pos = hsr_get_next_node(hsr, NULL, addr);
426f421436aSArvid Brodin 	while (pos) {
427f421436aSArvid Brodin 		res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, addr);
428f421436aSArvid Brodin 		if (res < 0) {
429f421436aSArvid Brodin 			rcu_read_unlock();
430f421436aSArvid Brodin 			goto nla_put_failure;
431f421436aSArvid Brodin 		}
43270ebe4a4SArvid Brodin 		pos = hsr_get_next_node(hsr, pos, addr);
433f421436aSArvid Brodin 	}
434f421436aSArvid Brodin 	rcu_read_unlock();
435f421436aSArvid Brodin 
436f421436aSArvid Brodin 	genlmsg_end(skb_out, msg_head);
437f421436aSArvid Brodin 	genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid);
438f421436aSArvid Brodin 
439f421436aSArvid Brodin 	return 0;
440f421436aSArvid Brodin 
441f421436aSArvid Brodin invalid:
442f421436aSArvid Brodin 	netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL);
443f421436aSArvid Brodin 	return 0;
444f421436aSArvid Brodin 
445f421436aSArvid Brodin nla_put_failure:
446f421436aSArvid Brodin 	kfree_skb(skb_out);
447f421436aSArvid Brodin 	/* Fall through */
448f421436aSArvid Brodin 
449f421436aSArvid Brodin fail:
450f421436aSArvid Brodin 	return res;
451f421436aSArvid Brodin }
452f421436aSArvid Brodin 
453f421436aSArvid Brodin 
4544534de83SJohannes Berg static const struct genl_ops hsr_ops[] = {
4559504b3eeSJohannes Berg 	{
4569504b3eeSJohannes Berg 		.cmd = HSR_C_GET_NODE_STATUS,
4579504b3eeSJohannes Berg 		.flags = 0,
4589504b3eeSJohannes Berg 		.policy = hsr_genl_policy,
4599504b3eeSJohannes Berg 		.doit = hsr_get_node_status,
4609504b3eeSJohannes Berg 		.dumpit = NULL,
4619504b3eeSJohannes Berg 	},
4629504b3eeSJohannes Berg 	{
463f421436aSArvid Brodin 		.cmd = HSR_C_GET_NODE_LIST,
464f421436aSArvid Brodin 		.flags = 0,
465f421436aSArvid Brodin 		.policy = hsr_genl_policy,
466f421436aSArvid Brodin 		.doit = hsr_get_node_list,
467f421436aSArvid Brodin 		.dumpit = NULL,
4689504b3eeSJohannes Berg 	},
469f421436aSArvid Brodin };
470f421436aSArvid Brodin 
471f421436aSArvid Brodin int __init hsr_netlink_init(void)
472f421436aSArvid Brodin {
473f421436aSArvid Brodin 	int rc;
474f421436aSArvid Brodin 
475f421436aSArvid Brodin 	rc = rtnl_link_register(&hsr_link_ops);
476f421436aSArvid Brodin 	if (rc)
477f421436aSArvid Brodin 		goto fail_rtnl_link_register;
478f421436aSArvid Brodin 
4792a94fe48SJohannes Berg 	rc = genl_register_family_with_ops_groups(&hsr_genl_family, hsr_ops,
4802a94fe48SJohannes Berg 						  hsr_mcgrps);
481f421436aSArvid Brodin 	if (rc)
482f421436aSArvid Brodin 		goto fail_genl_register_family;
483f421436aSArvid Brodin 
484f421436aSArvid Brodin 	return 0;
485f421436aSArvid Brodin 
486f421436aSArvid Brodin fail_genl_register_family:
487f421436aSArvid Brodin 	rtnl_link_unregister(&hsr_link_ops);
488f421436aSArvid Brodin fail_rtnl_link_register:
489f421436aSArvid Brodin 
490f421436aSArvid Brodin 	return rc;
491f421436aSArvid Brodin }
492f421436aSArvid Brodin 
493f421436aSArvid Brodin void __exit hsr_netlink_exit(void)
494f421436aSArvid Brodin {
495f421436aSArvid Brodin 	genl_unregister_family(&hsr_genl_family);
496f421436aSArvid Brodin 	rtnl_link_unregister(&hsr_link_ops);
497f421436aSArvid Brodin }
498f421436aSArvid Brodin 
499f421436aSArvid Brodin MODULE_ALIAS_RTNL_LINK("hsr");
500