xref: /openbmc/linux/net/hsr/hsr_framereg.c (revision 5ee9cd065836e5934710ca35653bce7905add20b)
10e7623bdSMurali Karicheri // SPDX-License-Identifier: GPL-2.0
270ebe4a4SArvid Brodin /* Copyright 2011-2014 Autronica Fire and Security AS
3f421436aSArvid Brodin  *
4f421436aSArvid Brodin  * Author(s):
570ebe4a4SArvid Brodin  *	2011-2014 Arvid Brodin, arvid.brodin@alten.se
6f421436aSArvid Brodin  *
7f421436aSArvid Brodin  * The HSR spec says never to forward the same frame twice on the same
8f421436aSArvid Brodin  * interface. A frame is identified by its source MAC address and its HSR
9f421436aSArvid Brodin  * sequence number. This code keeps track of senders and their sequence numbers
10f421436aSArvid Brodin  * to allow filtering of duplicate frames, and to detect HSR ring errors.
118f4c0e01SMurali Karicheri  * Same code handles filtering of duplicates for PRP as well.
12f421436aSArvid Brodin  */
13f421436aSArvid Brodin 
14f421436aSArvid Brodin #include <linux/if_ether.h>
15f421436aSArvid Brodin #include <linux/etherdevice.h>
16f421436aSArvid Brodin #include <linux/slab.h>
17f421436aSArvid Brodin #include <linux/rculist.h>
18f421436aSArvid Brodin #include "hsr_main.h"
19f421436aSArvid Brodin #include "hsr_framereg.h"
20f421436aSArvid Brodin #include "hsr_netlink.h"
21f421436aSArvid Brodin 
22f266a683SArvid Brodin /* seq_nr_after(a, b) - return true if a is after (higher in sequence than) b,
23f266a683SArvid Brodin  * false otherwise.
24f266a683SArvid Brodin  */
seq_nr_after(u16 a,u16 b)25f266a683SArvid Brodin static bool seq_nr_after(u16 a, u16 b)
26f266a683SArvid Brodin {
27f266a683SArvid Brodin 	/* Remove inconsistency where
28f266a683SArvid Brodin 	 * seq_nr_after(a, b) == seq_nr_before(a, b)
29f266a683SArvid Brodin 	 */
30f266a683SArvid Brodin 	if ((int)b - a == 32768)
31f266a683SArvid Brodin 		return false;
32f266a683SArvid Brodin 
33f266a683SArvid Brodin 	return (((s16)(b - a)) < 0);
34f266a683SArvid Brodin }
359f73c2bbSMurali Karicheri 
36f266a683SArvid Brodin #define seq_nr_before(a, b)		seq_nr_after((b), (a))
37f266a683SArvid Brodin #define seq_nr_before_or_eq(a, b)	(!seq_nr_after((a), (b)))
38f266a683SArvid Brodin 
hsr_addr_is_self(struct hsr_priv * hsr,unsigned char * addr)39f266a683SArvid Brodin bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr)
40f266a683SArvid Brodin {
4120d3c1e9SSebastian Andrzej Siewior 	struct hsr_self_node *sn;
4220d3c1e9SSebastian Andrzej Siewior 	bool ret = false;
43f266a683SArvid Brodin 
4420d3c1e9SSebastian Andrzej Siewior 	rcu_read_lock();
4520d3c1e9SSebastian Andrzej Siewior 	sn = rcu_dereference(hsr->self_node);
4620d3c1e9SSebastian Andrzej Siewior 	if (!sn) {
47f266a683SArvid Brodin 		WARN_ONCE(1, "HSR: No self node\n");
4820d3c1e9SSebastian Andrzej Siewior 		goto out;
49f266a683SArvid Brodin 	}
50f266a683SArvid Brodin 
5120d3c1e9SSebastian Andrzej Siewior 	if (ether_addr_equal(addr, sn->macaddress_A) ||
5220d3c1e9SSebastian Andrzej Siewior 	    ether_addr_equal(addr, sn->macaddress_B))
5320d3c1e9SSebastian Andrzej Siewior 		ret = true;
5420d3c1e9SSebastian Andrzej Siewior out:
5520d3c1e9SSebastian Andrzej Siewior 	rcu_read_unlock();
5620d3c1e9SSebastian Andrzej Siewior 	return ret;
57f266a683SArvid Brodin }
58f421436aSArvid Brodin 
59f421436aSArvid Brodin /* Search for mac entry. Caller must hold rcu read lock.
60f421436aSArvid Brodin  */
find_node_by_addr_A(struct list_head * node_db,const unsigned char addr[ETH_ALEN])61e012764cSSebastian Andrzej Siewior static struct hsr_node *find_node_by_addr_A(struct list_head *node_db,
62f421436aSArvid Brodin 					    const unsigned char addr[ETH_ALEN])
63f421436aSArvid Brodin {
6470ebe4a4SArvid Brodin 	struct hsr_node *node;
65f421436aSArvid Brodin 
66e012764cSSebastian Andrzej Siewior 	list_for_each_entry_rcu(node, node_db, mac_list) {
67b1b4aa91SMurali Karicheri 		if (ether_addr_equal(node->macaddress_A, addr))
68f421436aSArvid Brodin 			return node;
69f421436aSArvid Brodin 	}
70f421436aSArvid Brodin 
71f421436aSArvid Brodin 	return NULL;
72f421436aSArvid Brodin }
73f421436aSArvid Brodin 
7420d3c1e9SSebastian Andrzej Siewior /* Helper for device init; the self_node is used in hsr_rcv() to recognize
75f421436aSArvid Brodin  * frames from self that's been looped over the HSR ring.
76f421436aSArvid Brodin  */
hsr_create_self_node(struct hsr_priv * hsr,const unsigned char addr_a[ETH_ALEN],const unsigned char addr_b[ETH_ALEN])7792a35678STaehee Yoo int hsr_create_self_node(struct hsr_priv *hsr,
7839c19fb9SJakub Kicinski 			 const unsigned char addr_a[ETH_ALEN],
7939c19fb9SJakub Kicinski 			 const unsigned char addr_b[ETH_ALEN])
80f421436aSArvid Brodin {
8120d3c1e9SSebastian Andrzej Siewior 	struct hsr_self_node *sn, *old;
82f421436aSArvid Brodin 
8320d3c1e9SSebastian Andrzej Siewior 	sn = kmalloc(sizeof(*sn), GFP_KERNEL);
8420d3c1e9SSebastian Andrzej Siewior 	if (!sn)
85f421436aSArvid Brodin 		return -ENOMEM;
86f421436aSArvid Brodin 
8720d3c1e9SSebastian Andrzej Siewior 	ether_addr_copy(sn->macaddress_A, addr_a);
8820d3c1e9SSebastian Andrzej Siewior 	ether_addr_copy(sn->macaddress_B, addr_b);
89f421436aSArvid Brodin 
9092a35678STaehee Yoo 	spin_lock_bh(&hsr->list_lock);
9120d3c1e9SSebastian Andrzej Siewior 	old = rcu_replace_pointer(hsr->self_node, sn,
9220d3c1e9SSebastian Andrzej Siewior 				  lockdep_is_held(&hsr->list_lock));
9392a35678STaehee Yoo 	spin_unlock_bh(&hsr->list_lock);
94f421436aSArvid Brodin 
9520d3c1e9SSebastian Andrzej Siewior 	if (old)
9620d3c1e9SSebastian Andrzej Siewior 		kfree_rcu(old, rcu_head);
97f421436aSArvid Brodin 	return 0;
98f421436aSArvid Brodin }
99f421436aSArvid Brodin 
hsr_del_self_node(struct hsr_priv * hsr)10092a35678STaehee Yoo void hsr_del_self_node(struct hsr_priv *hsr)
1016caabe7fSMao Wenan {
10220d3c1e9SSebastian Andrzej Siewior 	struct hsr_self_node *old;
1036caabe7fSMao Wenan 
10492a35678STaehee Yoo 	spin_lock_bh(&hsr->list_lock);
10520d3c1e9SSebastian Andrzej Siewior 	old = rcu_replace_pointer(hsr->self_node, NULL,
10620d3c1e9SSebastian Andrzej Siewior 				  lockdep_is_held(&hsr->list_lock));
10792a35678STaehee Yoo 	spin_unlock_bh(&hsr->list_lock);
10820d3c1e9SSebastian Andrzej Siewior 	if (old)
10920d3c1e9SSebastian Andrzej Siewior 		kfree_rcu(old, rcu_head);
1106caabe7fSMao Wenan }
111f421436aSArvid Brodin 
hsr_del_nodes(struct list_head * node_db)112e012764cSSebastian Andrzej Siewior void hsr_del_nodes(struct list_head *node_db)
113b9a1e627SCong Wang {
114b9a1e627SCong Wang 	struct hsr_node *node;
115e012764cSSebastian Andrzej Siewior 	struct hsr_node *tmp;
116b9a1e627SCong Wang 
117e012764cSSebastian Andrzej Siewior 	list_for_each_entry_safe(node, tmp, node_db, mac_list)
118e012764cSSebastian Andrzej Siewior 		kfree(node);
119b9a1e627SCong Wang }
120b9a1e627SCong Wang 
prp_handle_san_frame(bool san,enum hsr_port_type port,struct hsr_node * node)121451d8123SMurali Karicheri void prp_handle_san_frame(bool san, enum hsr_port_type port,
122451d8123SMurali Karicheri 			  struct hsr_node *node)
123451d8123SMurali Karicheri {
124451d8123SMurali Karicheri 	/* Mark if the SAN node is over LAN_A or LAN_B */
125451d8123SMurali Karicheri 	if (port == HSR_PT_SLAVE_A) {
126451d8123SMurali Karicheri 		node->san_a = true;
127451d8123SMurali Karicheri 		return;
128451d8123SMurali Karicheri 	}
129451d8123SMurali Karicheri 
130451d8123SMurali Karicheri 	if (port == HSR_PT_SLAVE_B)
131451d8123SMurali Karicheri 		node->san_b = true;
132451d8123SMurali Karicheri }
133451d8123SMurali Karicheri 
134b1b4aa91SMurali Karicheri /* Allocate an hsr_node and add it to node_db. 'addr' is the node's address_A;
135f266a683SArvid Brodin  * seq_out is used to initialize filtering of outgoing duplicate frames
136f266a683SArvid Brodin  * originating from the newly added node.
137f421436aSArvid Brodin  */
hsr_add_node(struct hsr_priv * hsr,struct list_head * node_db,unsigned char addr[],u16 seq_out,bool san,enum hsr_port_type rx_port)13892a35678STaehee Yoo static struct hsr_node *hsr_add_node(struct hsr_priv *hsr,
139e012764cSSebastian Andrzej Siewior 				     struct list_head *node_db,
14092a35678STaehee Yoo 				     unsigned char addr[],
141451d8123SMurali Karicheri 				     u16 seq_out, bool san,
142451d8123SMurali Karicheri 				     enum hsr_port_type rx_port)
143f421436aSArvid Brodin {
14492a35678STaehee Yoo 	struct hsr_node *new_node, *node;
145f421436aSArvid Brodin 	unsigned long now;
146f266a683SArvid Brodin 	int i;
147f421436aSArvid Brodin 
14892a35678STaehee Yoo 	new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC);
14992a35678STaehee Yoo 	if (!new_node)
150f421436aSArvid Brodin 		return NULL;
151f421436aSArvid Brodin 
15292a35678STaehee Yoo 	ether_addr_copy(new_node->macaddress_A, addr);
1535c7aa132SSebastian Andrzej Siewior 	spin_lock_init(&new_node->seq_out_lock);
154f421436aSArvid Brodin 
155f421436aSArvid Brodin 	/* We are only interested in time diffs here, so use current jiffies
156f421436aSArvid Brodin 	 * as initialization. (0 could trigger an spurious ring error warning).
157f421436aSArvid Brodin 	 */
158f421436aSArvid Brodin 	now = jiffies;
159f1764114SMarco Wenzel 	for (i = 0; i < HSR_PT_PORTS; i++) {
16092a35678STaehee Yoo 		new_node->time_in[i] = now;
161f1764114SMarco Wenzel 		new_node->time_out[i] = now;
162f1764114SMarco Wenzel 	}
163c5a75911SArvid Brodin 	for (i = 0; i < HSR_PT_PORTS; i++)
16492a35678STaehee Yoo 		new_node->seq_out[i] = seq_out;
165f421436aSArvid Brodin 
166451d8123SMurali Karicheri 	if (san && hsr->proto_ops->handle_san_frame)
167451d8123SMurali Karicheri 		hsr->proto_ops->handle_san_frame(san, rx_port, new_node);
168451d8123SMurali Karicheri 
16992a35678STaehee Yoo 	spin_lock_bh(&hsr->list_lock);
170e012764cSSebastian Andrzej Siewior 	list_for_each_entry_rcu(node, node_db, mac_list,
171e012764cSSebastian Andrzej Siewior 				lockdep_is_held(&hsr->list_lock)) {
17292a35678STaehee Yoo 		if (ether_addr_equal(node->macaddress_A, addr))
17392a35678STaehee Yoo 			goto out;
17492a35678STaehee Yoo 		if (ether_addr_equal(node->macaddress_B, addr))
17592a35678STaehee Yoo 			goto out;
17692a35678STaehee Yoo 	}
177e012764cSSebastian Andrzej Siewior 	list_add_tail_rcu(&new_node->mac_list, node_db);
17892a35678STaehee Yoo 	spin_unlock_bh(&hsr->list_lock);
17992a35678STaehee Yoo 	return new_node;
18092a35678STaehee Yoo out:
18192a35678STaehee Yoo 	spin_unlock_bh(&hsr->list_lock);
18292a35678STaehee Yoo 	kfree(new_node);
183f421436aSArvid Brodin 	return node;
184f421436aSArvid Brodin }
185f421436aSArvid Brodin 
prp_update_san_info(struct hsr_node * node,bool is_sup)186451d8123SMurali Karicheri void prp_update_san_info(struct hsr_node *node, bool is_sup)
187451d8123SMurali Karicheri {
188451d8123SMurali Karicheri 	if (!is_sup)
189451d8123SMurali Karicheri 		return;
190451d8123SMurali Karicheri 
191451d8123SMurali Karicheri 	node->san_a = false;
192451d8123SMurali Karicheri 	node->san_b = false;
193451d8123SMurali Karicheri }
194451d8123SMurali Karicheri 
195f266a683SArvid Brodin /* Get the hsr_node from which 'skb' was sent.
196f266a683SArvid Brodin  */
hsr_get_node(struct hsr_port * port,struct list_head * node_db,struct sk_buff * skb,bool is_sup,enum hsr_port_type rx_port)197e012764cSSebastian Andrzej Siewior struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db,
198451d8123SMurali Karicheri 			      struct sk_buff *skb, bool is_sup,
199451d8123SMurali Karicheri 			      enum hsr_port_type rx_port)
200f266a683SArvid Brodin {
20192a35678STaehee Yoo 	struct hsr_priv *hsr = port->hsr;
202f266a683SArvid Brodin 	struct hsr_node *node;
203f266a683SArvid Brodin 	struct ethhdr *ethhdr;
204451d8123SMurali Karicheri 	struct prp_rct *rct;
205451d8123SMurali Karicheri 	bool san = false;
206f266a683SArvid Brodin 	u16 seq_out;
207f266a683SArvid Brodin 
208f266a683SArvid Brodin 	if (!skb_mac_header_was_set(skb))
209f266a683SArvid Brodin 		return NULL;
210f266a683SArvid Brodin 
211f266a683SArvid Brodin 	ethhdr = (struct ethhdr *)skb_mac_header(skb);
212f266a683SArvid Brodin 
213e012764cSSebastian Andrzej Siewior 	list_for_each_entry_rcu(node, node_db, mac_list) {
214451d8123SMurali Karicheri 		if (ether_addr_equal(node->macaddress_A, ethhdr->h_source)) {
215451d8123SMurali Karicheri 			if (hsr->proto_ops->update_san_info)
216451d8123SMurali Karicheri 				hsr->proto_ops->update_san_info(node, is_sup);
217f266a683SArvid Brodin 			return node;
218f266a683SArvid Brodin 		}
219451d8123SMurali Karicheri 		if (ether_addr_equal(node->macaddress_B, ethhdr->h_source)) {
220451d8123SMurali Karicheri 			if (hsr->proto_ops->update_san_info)
221451d8123SMurali Karicheri 				hsr->proto_ops->update_san_info(node, is_sup);
222451d8123SMurali Karicheri 			return node;
223451d8123SMurali Karicheri 		}
224451d8123SMurali Karicheri 	}
225f266a683SArvid Brodin 
226451d8123SMurali Karicheri 	/* Everyone may create a node entry, connected node to a HSR/PRP
227451d8123SMurali Karicheri 	 * device.
228451d8123SMurali Karicheri 	 */
22905947783SMurali Karicheri 	if (ethhdr->h_proto == htons(ETH_P_PRP) ||
23005947783SMurali Karicheri 	    ethhdr->h_proto == htons(ETH_P_HSR)) {
231*39cc316fSShigeru Yoshida 		/* Check if skb contains hsr_ethhdr */
232*39cc316fSShigeru Yoshida 		if (skb->mac_len < sizeof(struct hsr_ethhdr))
233*39cc316fSShigeru Yoshida 			return NULL;
234*39cc316fSShigeru Yoshida 
235f266a683SArvid Brodin 		/* Use the existing sequence_nr from the tag as starting point
236f266a683SArvid Brodin 		 * for filtering duplicate frames.
237f266a683SArvid Brodin 		 */
238f266a683SArvid Brodin 		seq_out = hsr_get_skb_sequence_nr(skb) - 1;
239f266a683SArvid Brodin 	} else {
240451d8123SMurali Karicheri 		rct = skb_get_PRP_rct(skb);
241451d8123SMurali Karicheri 		if (rct && prp_check_lsdu_size(skb, rct, is_sup)) {
242451d8123SMurali Karicheri 			seq_out = prp_get_skb_sequence_nr(rct);
243451d8123SMurali Karicheri 		} else {
244451d8123SMurali Karicheri 			if (rx_port != HSR_PT_MASTER)
245451d8123SMurali Karicheri 				san = true;
246ee1c2797SPeter Heise 			seq_out = HSR_SEQNR_START;
247f266a683SArvid Brodin 		}
248451d8123SMurali Karicheri 	}
249f266a683SArvid Brodin 
250451d8123SMurali Karicheri 	return hsr_add_node(hsr, node_db, ethhdr->h_source, seq_out,
251451d8123SMurali Karicheri 			    san, rx_port);
252f266a683SArvid Brodin }
253f266a683SArvid Brodin 
254b1b4aa91SMurali Karicheri /* Use the Supervision frame's info about an eventual macaddress_B for merging
255b1b4aa91SMurali Karicheri  * nodes that has previously had their macaddress_B registered as a separate
256f266a683SArvid Brodin  * node.
257f266a683SArvid Brodin  */
hsr_handle_sup_frame(struct hsr_frame_info * frame)258451d8123SMurali Karicheri void hsr_handle_sup_frame(struct hsr_frame_info *frame)
259f266a683SArvid Brodin {
260451d8123SMurali Karicheri 	struct hsr_node *node_curr = frame->node_src;
261451d8123SMurali Karicheri 	struct hsr_port *port_rcv = frame->port_rcv;
26292a35678STaehee Yoo 	struct hsr_priv *hsr = port_rcv->hsr;
263f266a683SArvid Brodin 	struct hsr_sup_payload *hsr_sp;
264eafaa88bSAndreas Oetken 	struct hsr_sup_tlv *hsr_sup_tlv;
26592a35678STaehee Yoo 	struct hsr_node *node_real;
266451d8123SMurali Karicheri 	struct sk_buff *skb = NULL;
267e012764cSSebastian Andrzej Siewior 	struct list_head *node_db;
26892a35678STaehee Yoo 	struct ethhdr *ethhdr;
269f266a683SArvid Brodin 	int i;
270eafaa88bSAndreas Oetken 	unsigned int pull_size = 0;
271eafaa88bSAndreas Oetken 	unsigned int total_pull_size = 0;
272f266a683SArvid Brodin 
273451d8123SMurali Karicheri 	/* Here either frame->skb_hsr or frame->skb_prp should be
274451d8123SMurali Karicheri 	 * valid as supervision frame always will have protocol
275451d8123SMurali Karicheri 	 * header info.
276451d8123SMurali Karicheri 	 */
277451d8123SMurali Karicheri 	if (frame->skb_hsr)
278451d8123SMurali Karicheri 		skb = frame->skb_hsr;
279451d8123SMurali Karicheri 	else if (frame->skb_prp)
280451d8123SMurali Karicheri 		skb = frame->skb_prp;
281dcf0cd1cSGeorge McCollister 	else if (frame->skb_std)
282dcf0cd1cSGeorge McCollister 		skb = frame->skb_std;
283451d8123SMurali Karicheri 	if (!skb)
284451d8123SMurali Karicheri 		return;
285451d8123SMurali Karicheri 
286eafaa88bSAndreas Oetken 	/* Leave the ethernet header. */
287eafaa88bSAndreas Oetken 	pull_size = sizeof(struct ethhdr);
288eafaa88bSAndreas Oetken 	skb_pull(skb, pull_size);
289eafaa88bSAndreas Oetken 	total_pull_size += pull_size;
290eafaa88bSAndreas Oetken 
291ee1c2797SPeter Heise 	ethhdr = (struct ethhdr *)skb_mac_header(skb);
292f266a683SArvid Brodin 
293ee1c2797SPeter Heise 	/* And leave the HSR tag. */
294eafaa88bSAndreas Oetken 	if (ethhdr->h_proto == htons(ETH_P_HSR)) {
295295de650SLukasz Majewski 		pull_size = sizeof(struct hsr_tag);
296eafaa88bSAndreas Oetken 		skb_pull(skb, pull_size);
297eafaa88bSAndreas Oetken 		total_pull_size += pull_size;
298eafaa88bSAndreas Oetken 	}
299ee1c2797SPeter Heise 
300ee1c2797SPeter Heise 	/* And leave the HSR sup tag. */
301295de650SLukasz Majewski 	pull_size = sizeof(struct hsr_sup_tag);
302eafaa88bSAndreas Oetken 	skb_pull(skb, pull_size);
303eafaa88bSAndreas Oetken 	total_pull_size += pull_size;
304ee1c2797SPeter Heise 
305eafaa88bSAndreas Oetken 	/* get HSR sup payload */
306ee1c2797SPeter Heise 	hsr_sp = (struct hsr_sup_payload *)skb->data;
307f266a683SArvid Brodin 
308b1b4aa91SMurali Karicheri 	/* Merge node_curr (registered on macaddress_B) into node_real */
309e012764cSSebastian Andrzej Siewior 	node_db = &port_rcv->hsr->node_db;
310e012764cSSebastian Andrzej Siewior 	node_real = find_node_by_addr_A(node_db, hsr_sp->macaddress_A);
311f266a683SArvid Brodin 	if (!node_real)
312f266a683SArvid Brodin 		/* No frame received from AddrA of this node yet */
313e012764cSSebastian Andrzej Siewior 		node_real = hsr_add_node(hsr, node_db, hsr_sp->macaddress_A,
314451d8123SMurali Karicheri 					 HSR_SEQNR_START - 1, true,
315451d8123SMurali Karicheri 					 port_rcv->type);
316f266a683SArvid Brodin 	if (!node_real)
317f266a683SArvid Brodin 		goto done; /* No mem */
318f266a683SArvid Brodin 	if (node_real == node_curr)
319f266a683SArvid Brodin 		/* Node has already been merged */
320f266a683SArvid Brodin 		goto done;
321f266a683SArvid Brodin 
322eafaa88bSAndreas Oetken 	/* Leave the first HSR sup payload. */
323eafaa88bSAndreas Oetken 	pull_size = sizeof(struct hsr_sup_payload);
324eafaa88bSAndreas Oetken 	skb_pull(skb, pull_size);
325eafaa88bSAndreas Oetken 	total_pull_size += pull_size;
326eafaa88bSAndreas Oetken 
327eafaa88bSAndreas Oetken 	/* Get second supervision tlv */
328eafaa88bSAndreas Oetken 	hsr_sup_tlv = (struct hsr_sup_tlv *)skb->data;
329eafaa88bSAndreas Oetken 	/* And check if it is a redbox mac TLV */
330eafaa88bSAndreas Oetken 	if (hsr_sup_tlv->HSR_TLV_type == PRP_TLV_REDBOX_MAC) {
331eafaa88bSAndreas Oetken 		/* We could stop here after pushing hsr_sup_payload,
332eafaa88bSAndreas Oetken 		 * or proceed and allow macaddress_B and for redboxes.
333eafaa88bSAndreas Oetken 		 */
334eafaa88bSAndreas Oetken 		/* Sanity check length */
335eafaa88bSAndreas Oetken 		if (hsr_sup_tlv->HSR_TLV_length != 6)
336eafaa88bSAndreas Oetken 			goto done;
337eafaa88bSAndreas Oetken 
338eafaa88bSAndreas Oetken 		/* Leave the second HSR sup tlv. */
339eafaa88bSAndreas Oetken 		pull_size = sizeof(struct hsr_sup_tlv);
340eafaa88bSAndreas Oetken 		skb_pull(skb, pull_size);
341eafaa88bSAndreas Oetken 		total_pull_size += pull_size;
342eafaa88bSAndreas Oetken 
343eafaa88bSAndreas Oetken 		/* Get redbox mac address. */
344eafaa88bSAndreas Oetken 		hsr_sp = (struct hsr_sup_payload *)skb->data;
345eafaa88bSAndreas Oetken 
346eafaa88bSAndreas Oetken 		/* Check if redbox mac and node mac are equal. */
347e012764cSSebastian Andrzej Siewior 		if (!ether_addr_equal(node_real->macaddress_A, hsr_sp->macaddress_A)) {
348eafaa88bSAndreas Oetken 			/* This is a redbox supervision frame for a VDAN! */
349eafaa88bSAndreas Oetken 			goto done;
350eafaa88bSAndreas Oetken 		}
351eafaa88bSAndreas Oetken 	}
352eafaa88bSAndreas Oetken 
353b1b4aa91SMurali Karicheri 	ether_addr_copy(node_real->macaddress_B, ethhdr->h_source);
3545c7aa132SSebastian Andrzej Siewior 	spin_lock_bh(&node_real->seq_out_lock);
355f266a683SArvid Brodin 	for (i = 0; i < HSR_PT_PORTS; i++) {
356f266a683SArvid Brodin 		if (!node_curr->time_in_stale[i] &&
357f266a683SArvid Brodin 		    time_after(node_curr->time_in[i], node_real->time_in[i])) {
358f266a683SArvid Brodin 			node_real->time_in[i] = node_curr->time_in[i];
359d595b85aSMurali Karicheri 			node_real->time_in_stale[i] =
360d595b85aSMurali Karicheri 						node_curr->time_in_stale[i];
361f266a683SArvid Brodin 		}
362f266a683SArvid Brodin 		if (seq_nr_after(node_curr->seq_out[i], node_real->seq_out[i]))
363f266a683SArvid Brodin 			node_real->seq_out[i] = node_curr->seq_out[i];
364f266a683SArvid Brodin 	}
3655c7aa132SSebastian Andrzej Siewior 	spin_unlock_bh(&node_real->seq_out_lock);
366b1b4aa91SMurali Karicheri 	node_real->addr_B_port = port_rcv->type;
367f266a683SArvid Brodin 
36892a35678STaehee Yoo 	spin_lock_bh(&hsr->list_lock);
3690c74d9f7SSebastian Andrzej Siewior 	if (!node_curr->removed) {
370e012764cSSebastian Andrzej Siewior 		list_del_rcu(&node_curr->mac_list);
3710c74d9f7SSebastian Andrzej Siewior 		node_curr->removed = true;
372f266a683SArvid Brodin 		kfree_rcu(node_curr, rcu_head);
3730c74d9f7SSebastian Andrzej Siewior 	}
3740c74d9f7SSebastian Andrzej Siewior 	spin_unlock_bh(&hsr->list_lock);
375f266a683SArvid Brodin 
376f266a683SArvid Brodin done:
377eafaa88bSAndreas Oetken 	/* Push back here */
378eafaa88bSAndreas Oetken 	skb_push(skb, total_pull_size);
379f266a683SArvid Brodin }
380f266a683SArvid Brodin 
381f421436aSArvid Brodin /* 'skb' is a frame meant for this host, that is to be passed to upper layers.
382f421436aSArvid Brodin  *
383f266a683SArvid Brodin  * If the frame was sent by a node's B interface, replace the source
384b1b4aa91SMurali Karicheri  * address with that node's "official" address (macaddress_A) so that upper
385f421436aSArvid Brodin  * layers recognize where it came from.
386f421436aSArvid Brodin  */
hsr_addr_subst_source(struct hsr_node * node,struct sk_buff * skb)387f266a683SArvid Brodin void hsr_addr_subst_source(struct hsr_node *node, struct sk_buff *skb)
388f421436aSArvid Brodin {
389f421436aSArvid Brodin 	if (!skb_mac_header_was_set(skb)) {
390f421436aSArvid Brodin 		WARN_ONCE(1, "%s: Mac header not set\n", __func__);
391f421436aSArvid Brodin 		return;
392f421436aSArvid Brodin 	}
393f421436aSArvid Brodin 
394b1b4aa91SMurali Karicheri 	memcpy(&eth_hdr(skb)->h_source, node->macaddress_A, ETH_ALEN);
395f421436aSArvid Brodin }
396f421436aSArvid Brodin 
397f421436aSArvid Brodin /* 'skb' is a frame meant for another host.
398f266a683SArvid Brodin  * 'port' is the outgoing interface
399f421436aSArvid Brodin  *
400f421436aSArvid Brodin  * Substitute the target (dest) MAC address if necessary, so the it matches the
401f421436aSArvid Brodin  * recipient interface MAC address, regardless of whether that is the
402f421436aSArvid Brodin  * recipient's A or B interface.
403f421436aSArvid Brodin  * This is needed to keep the packets flowing through switches that learn on
404f421436aSArvid Brodin  * which "side" the different interfaces are.
405f421436aSArvid Brodin  */
hsr_addr_subst_dest(struct hsr_node * node_src,struct sk_buff * skb,struct hsr_port * port)406f266a683SArvid Brodin void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb,
407c5a75911SArvid Brodin 			 struct hsr_port *port)
408f421436aSArvid Brodin {
409f266a683SArvid Brodin 	struct hsr_node *node_dst;
410f421436aSArvid Brodin 
411f266a683SArvid Brodin 	if (!skb_mac_header_was_set(skb)) {
412f266a683SArvid Brodin 		WARN_ONCE(1, "%s: Mac header not set\n", __func__);
413f266a683SArvid Brodin 		return;
414f266a683SArvid Brodin 	}
415f266a683SArvid Brodin 
416f266a683SArvid Brodin 	if (!is_unicast_ether_addr(eth_hdr(skb)->h_dest))
417f266a683SArvid Brodin 		return;
418f266a683SArvid Brodin 
419e012764cSSebastian Andrzej Siewior 	node_dst = find_node_by_addr_A(&port->hsr->node_db,
420d595b85aSMurali Karicheri 				       eth_hdr(skb)->h_dest);
421f266a683SArvid Brodin 	if (!node_dst) {
4221b0120e4SMatthieu Baerts 		if (port->hsr->prot_version != PRP_V1 && net_ratelimit())
4234b793acdSTaehee Yoo 			netdev_err(skb->dev, "%s: Unknown node\n", __func__);
424f266a683SArvid Brodin 		return;
425f266a683SArvid Brodin 	}
426b1b4aa91SMurali Karicheri 	if (port->type != node_dst->addr_B_port)
427f266a683SArvid Brodin 		return;
428f266a683SArvid Brodin 
429eea9f73eSMurali Karicheri 	if (is_valid_ether_addr(node_dst->macaddress_B))
430b1b4aa91SMurali Karicheri 		ether_addr_copy(eth_hdr(skb)->h_dest, node_dst->macaddress_B);
431f421436aSArvid Brodin }
432f421436aSArvid Brodin 
hsr_register_frame_in(struct hsr_node * node,struct hsr_port * port,u16 sequence_nr)433f266a683SArvid Brodin void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port,
434f266a683SArvid Brodin 			   u16 sequence_nr)
435f421436aSArvid Brodin {
436f266a683SArvid Brodin 	/* Don't register incoming frames without a valid sequence number. This
437f266a683SArvid Brodin 	 * ensures entries of restarted nodes gets pruned so that they can
438f266a683SArvid Brodin 	 * re-register and resume communications.
439213e3bc7SArvid Brodin 	 */
440c2ae34a7SGeorge McCollister 	if (!(port->dev->features & NETIF_F_HW_HSR_TAG_RM) &&
441c2ae34a7SGeorge McCollister 	    seq_nr_before(sequence_nr, node->seq_out[port->type]))
442f266a683SArvid Brodin 		return;
443f421436aSArvid Brodin 
444c5a75911SArvid Brodin 	node->time_in[port->type] = jiffies;
445c5a75911SArvid Brodin 	node->time_in_stale[port->type] = false;
446f421436aSArvid Brodin }
447f421436aSArvid Brodin 
448f421436aSArvid Brodin /* 'skb' is a HSR Ethernet frame (with a HSR tag inserted), with a valid
449f421436aSArvid Brodin  * ethhdr->h_source address and skb->mac_header set.
450f421436aSArvid Brodin  *
451f421436aSArvid Brodin  * Return:
452f421436aSArvid Brodin  *	 1 if frame can be shown to have been sent recently on this interface,
453f421436aSArvid Brodin  *	 0 otherwise, or
454f421436aSArvid Brodin  *	 negative error code on error
455f421436aSArvid Brodin  */
hsr_register_frame_out(struct hsr_port * port,struct hsr_node * node,u16 sequence_nr)456f266a683SArvid Brodin int hsr_register_frame_out(struct hsr_port *port, struct hsr_node *node,
457f266a683SArvid Brodin 			   u16 sequence_nr)
458f421436aSArvid Brodin {
4595c7aa132SSebastian Andrzej Siewior 	spin_lock_bh(&node->seq_out_lock);
460f1764114SMarco Wenzel 	if (seq_nr_before_or_eq(sequence_nr, node->seq_out[port->type]) &&
461f1764114SMarco Wenzel 	    time_is_after_jiffies(node->time_out[port->type] +
4625c7aa132SSebastian Andrzej Siewior 	    msecs_to_jiffies(HSR_ENTRY_FORGET_TIME))) {
4635c7aa132SSebastian Andrzej Siewior 		spin_unlock_bh(&node->seq_out_lock);
464f421436aSArvid Brodin 		return 1;
4655c7aa132SSebastian Andrzej Siewior 	}
466f421436aSArvid Brodin 
467f1764114SMarco Wenzel 	node->time_out[port->type] = jiffies;
468c5a75911SArvid Brodin 	node->seq_out[port->type] = sequence_nr;
4695c7aa132SSebastian Andrzej Siewior 	spin_unlock_bh(&node->seq_out_lock);
470f421436aSArvid Brodin 	return 0;
471f421436aSArvid Brodin }
472f421436aSArvid Brodin 
get_late_port(struct hsr_priv * hsr,struct hsr_node * node)473c5a75911SArvid Brodin static struct hsr_port *get_late_port(struct hsr_priv *hsr,
474c5a75911SArvid Brodin 				      struct hsr_node *node)
475f421436aSArvid Brodin {
476c5a75911SArvid Brodin 	if (node->time_in_stale[HSR_PT_SLAVE_A])
477c5a75911SArvid Brodin 		return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A);
478c5a75911SArvid Brodin 	if (node->time_in_stale[HSR_PT_SLAVE_B])
479c5a75911SArvid Brodin 		return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B);
480f421436aSArvid Brodin 
481c5a75911SArvid Brodin 	if (time_after(node->time_in[HSR_PT_SLAVE_B],
482c5a75911SArvid Brodin 		       node->time_in[HSR_PT_SLAVE_A] +
483f421436aSArvid Brodin 					msecs_to_jiffies(MAX_SLAVE_DIFF)))
484c5a75911SArvid Brodin 		return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A);
485c5a75911SArvid Brodin 	if (time_after(node->time_in[HSR_PT_SLAVE_A],
486c5a75911SArvid Brodin 		       node->time_in[HSR_PT_SLAVE_B] +
487c5a75911SArvid Brodin 					msecs_to_jiffies(MAX_SLAVE_DIFF)))
488c5a75911SArvid Brodin 		return hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B);
489f421436aSArvid Brodin 
490c5a75911SArvid Brodin 	return NULL;
491f421436aSArvid Brodin }
492f421436aSArvid Brodin 
493f421436aSArvid Brodin /* Remove stale sequence_nr records. Called by timer every
494f421436aSArvid Brodin  * HSR_LIFE_CHECK_INTERVAL (two seconds or so).
495f421436aSArvid Brodin  */
hsr_prune_nodes(struct timer_list * t)496dda436b7SKees Cook void hsr_prune_nodes(struct timer_list *t)
497f421436aSArvid Brodin {
498dda436b7SKees Cook 	struct hsr_priv *hsr = from_timer(hsr, t, prune_timer);
49970ebe4a4SArvid Brodin 	struct hsr_node *node;
500e012764cSSebastian Andrzej Siewior 	struct hsr_node *tmp;
501c5a75911SArvid Brodin 	struct hsr_port *port;
502f421436aSArvid Brodin 	unsigned long timestamp;
503f421436aSArvid Brodin 	unsigned long time_a, time_b;
504f421436aSArvid Brodin 
50592a35678STaehee Yoo 	spin_lock_bh(&hsr->list_lock);
506e012764cSSebastian Andrzej Siewior 	list_for_each_entry_safe(node, tmp, &hsr->node_db, mac_list) {
507e012764cSSebastian Andrzej Siewior 		/* Don't prune own node. Neither time_in[HSR_PT_SLAVE_A]
508e012764cSSebastian Andrzej Siewior 		 * nor time_in[HSR_PT_SLAVE_B], will ever be updated for
509e012764cSSebastian Andrzej Siewior 		 * the master port. Thus the master node will be repeatedly
510e012764cSSebastian Andrzej Siewior 		 * pruned leading to packet loss.
511d2daa127SAndreas Oetken 		 */
512d2daa127SAndreas Oetken 		if (hsr_addr_is_self(hsr, node->macaddress_A))
513d2daa127SAndreas Oetken 			continue;
514d2daa127SAndreas Oetken 
515f421436aSArvid Brodin 		/* Shorthand */
516c5a75911SArvid Brodin 		time_a = node->time_in[HSR_PT_SLAVE_A];
517c5a75911SArvid Brodin 		time_b = node->time_in[HSR_PT_SLAVE_B];
518f421436aSArvid Brodin 
519e012764cSSebastian Andrzej Siewior 		/* Check for timestamps old enough to risk wrap-around */
520f421436aSArvid Brodin 		if (time_after(jiffies, time_a + MAX_JIFFY_OFFSET / 2))
521c5a75911SArvid Brodin 			node->time_in_stale[HSR_PT_SLAVE_A] = true;
522f421436aSArvid Brodin 		if (time_after(jiffies, time_b + MAX_JIFFY_OFFSET / 2))
523c5a75911SArvid Brodin 			node->time_in_stale[HSR_PT_SLAVE_B] = true;
524f421436aSArvid Brodin 
525f421436aSArvid Brodin 		/* Get age of newest frame from node.
526e012764cSSebastian Andrzej Siewior 		 * At least one time_in is OK here; nodes get pruned long
527e012764cSSebastian Andrzej Siewior 		 * before both time_ins can get stale
528f421436aSArvid Brodin 		 */
529f421436aSArvid Brodin 		timestamp = time_a;
530c5a75911SArvid Brodin 		if (node->time_in_stale[HSR_PT_SLAVE_A] ||
531c5a75911SArvid Brodin 		    (!node->time_in_stale[HSR_PT_SLAVE_B] &&
532f421436aSArvid Brodin 		    time_after(time_b, time_a)))
533f421436aSArvid Brodin 			timestamp = time_b;
534f421436aSArvid Brodin 
535e012764cSSebastian Andrzej Siewior 		/* Warn of ring error only as long as we get frames at all */
536f421436aSArvid Brodin 		if (time_is_after_jiffies(timestamp +
537f421436aSArvid Brodin 				msecs_to_jiffies(1.5 * MAX_SLAVE_DIFF))) {
538c5a75911SArvid Brodin 			rcu_read_lock();
539c5a75911SArvid Brodin 			port = get_late_port(hsr, node);
54005ca6e64SMurali Karicheri 			if (port)
541e012764cSSebastian Andrzej Siewior 				hsr_nl_ringerror(hsr, node->macaddress_A, port);
542c5a75911SArvid Brodin 			rcu_read_unlock();
543f421436aSArvid Brodin 		}
544f421436aSArvid Brodin 
545f421436aSArvid Brodin 		/* Prune old entries */
546f421436aSArvid Brodin 		if (time_is_before_jiffies(timestamp +
547f421436aSArvid Brodin 				msecs_to_jiffies(HSR_NODE_FORGET_TIME))) {
548b1b4aa91SMurali Karicheri 			hsr_nl_nodedown(hsr, node->macaddress_A);
5490c74d9f7SSebastian Andrzej Siewior 			if (!node->removed) {
550e012764cSSebastian Andrzej Siewior 				list_del_rcu(&node->mac_list);
5510c74d9f7SSebastian Andrzej Siewior 				node->removed = true;
552e012764cSSebastian Andrzej Siewior 				/* Note that we need to free this entry later: */
5531aee6cc2SWei Yongjun 				kfree_rcu(node, rcu_head);
554f421436aSArvid Brodin 			}
555f421436aSArvid Brodin 		}
5560c74d9f7SSebastian Andrzej Siewior 	}
55792a35678STaehee Yoo 	spin_unlock_bh(&hsr->list_lock);
5585150b45fSAaron Kramer 
5595150b45fSAaron Kramer 	/* Restart timer */
5605150b45fSAaron Kramer 	mod_timer(&hsr->prune_timer,
5615150b45fSAaron Kramer 		  jiffies + msecs_to_jiffies(PRUNE_PERIOD));
562f421436aSArvid Brodin }
563f421436aSArvid Brodin 
hsr_get_next_node(struct hsr_priv * hsr,void * _pos,unsigned char addr[ETH_ALEN])56470ebe4a4SArvid Brodin void *hsr_get_next_node(struct hsr_priv *hsr, void *_pos,
565f421436aSArvid Brodin 			unsigned char addr[ETH_ALEN])
566f421436aSArvid Brodin {
56770ebe4a4SArvid Brodin 	struct hsr_node *node;
568f421436aSArvid Brodin 
569f421436aSArvid Brodin 	if (!_pos) {
570e012764cSSebastian Andrzej Siewior 		node = list_first_or_null_rcu(&hsr->node_db,
571e012764cSSebastian Andrzej Siewior 					      struct hsr_node, mac_list);
572f421436aSArvid Brodin 		if (node)
573b1b4aa91SMurali Karicheri 			ether_addr_copy(addr, node->macaddress_A);
574f421436aSArvid Brodin 		return node;
575f421436aSArvid Brodin 	}
576f421436aSArvid Brodin 
577f421436aSArvid Brodin 	node = _pos;
578e012764cSSebastian Andrzej Siewior 	list_for_each_entry_continue_rcu(node, &hsr->node_db, mac_list) {
579b1b4aa91SMurali Karicheri 		ether_addr_copy(addr, node->macaddress_A);
580f421436aSArvid Brodin 		return node;
581f421436aSArvid Brodin 	}
582f421436aSArvid Brodin 
583f421436aSArvid Brodin 	return NULL;
584f421436aSArvid Brodin }
585f421436aSArvid Brodin 
hsr_get_node_data(struct hsr_priv * hsr,const unsigned char * addr,unsigned char addr_b[ETH_ALEN],unsigned int * addr_b_ifindex,int * if1_age,u16 * if1_seq,int * if2_age,u16 * if2_seq)58670ebe4a4SArvid Brodin int hsr_get_node_data(struct hsr_priv *hsr,
587f421436aSArvid Brodin 		      const unsigned char *addr,
588f421436aSArvid Brodin 		      unsigned char addr_b[ETH_ALEN],
589f421436aSArvid Brodin 		      unsigned int *addr_b_ifindex,
590f421436aSArvid Brodin 		      int *if1_age,
591f421436aSArvid Brodin 		      u16 *if1_seq,
592f421436aSArvid Brodin 		      int *if2_age,
593f421436aSArvid Brodin 		      u16 *if2_seq)
594f421436aSArvid Brodin {
59570ebe4a4SArvid Brodin 	struct hsr_node *node;
596c5a75911SArvid Brodin 	struct hsr_port *port;
597f421436aSArvid Brodin 	unsigned long tdiff;
598f421436aSArvid Brodin 
599e012764cSSebastian Andrzej Siewior 	node = find_node_by_addr_A(&hsr->node_db, addr);
600173756b8STaehee Yoo 	if (!node)
601173756b8STaehee Yoo 		return -ENOENT;
602f421436aSArvid Brodin 
603b1b4aa91SMurali Karicheri 	ether_addr_copy(addr_b, node->macaddress_B);
604f421436aSArvid Brodin 
605c5a75911SArvid Brodin 	tdiff = jiffies - node->time_in[HSR_PT_SLAVE_A];
606c5a75911SArvid Brodin 	if (node->time_in_stale[HSR_PT_SLAVE_A])
607f421436aSArvid Brodin 		*if1_age = INT_MAX;
608f421436aSArvid Brodin #if HZ <= MSEC_PER_SEC
609f421436aSArvid Brodin 	else if (tdiff > msecs_to_jiffies(INT_MAX))
610f421436aSArvid Brodin 		*if1_age = INT_MAX;
611f421436aSArvid Brodin #endif
612f421436aSArvid Brodin 	else
613f421436aSArvid Brodin 		*if1_age = jiffies_to_msecs(tdiff);
614f421436aSArvid Brodin 
615c5a75911SArvid Brodin 	tdiff = jiffies - node->time_in[HSR_PT_SLAVE_B];
616c5a75911SArvid Brodin 	if (node->time_in_stale[HSR_PT_SLAVE_B])
617f421436aSArvid Brodin 		*if2_age = INT_MAX;
618f421436aSArvid Brodin #if HZ <= MSEC_PER_SEC
619f421436aSArvid Brodin 	else if (tdiff > msecs_to_jiffies(INT_MAX))
620f421436aSArvid Brodin 		*if2_age = INT_MAX;
621f421436aSArvid Brodin #endif
622f421436aSArvid Brodin 	else
623f421436aSArvid Brodin 		*if2_age = jiffies_to_msecs(tdiff);
624f421436aSArvid Brodin 
625f421436aSArvid Brodin 	/* Present sequence numbers as if they were incoming on interface */
626c5a75911SArvid Brodin 	*if1_seq = node->seq_out[HSR_PT_SLAVE_B];
627c5a75911SArvid Brodin 	*if2_seq = node->seq_out[HSR_PT_SLAVE_A];
628f421436aSArvid Brodin 
629b1b4aa91SMurali Karicheri 	if (node->addr_B_port != HSR_PT_NONE) {
630b1b4aa91SMurali Karicheri 		port = hsr_port_get_hsr(hsr, node->addr_B_port);
631c5a75911SArvid Brodin 		*addr_b_ifindex = port->dev->ifindex;
632c5a75911SArvid Brodin 	} else {
633f421436aSArvid Brodin 		*addr_b_ifindex = -1;
634c5a75911SArvid Brodin 	}
635f421436aSArvid Brodin 
636f421436aSArvid Brodin 	return 0;
637f421436aSArvid Brodin }
638