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(ð_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