162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/* Copyright 2011-2014 Autronica Fire and Security AS
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Author(s):
562306a36Sopenharmony_ci *	2011-2014 Arvid Brodin, arvid.brodin@alten.se
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * include file for HSR and PRP.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#ifndef __HSR_PRIVATE_H
1162306a36Sopenharmony_ci#define __HSR_PRIVATE_H
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/netdevice.h>
1462306a36Sopenharmony_ci#include <linux/list.h>
1562306a36Sopenharmony_ci#include <linux/if_vlan.h>
1662306a36Sopenharmony_ci#include <linux/if_hsr.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* Time constants as specified in the HSR specification (IEC-62439-3 2010)
1962306a36Sopenharmony_ci * Table 8.
2062306a36Sopenharmony_ci * All values in milliseconds.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci#define HSR_LIFE_CHECK_INTERVAL		 2000 /* ms */
2362306a36Sopenharmony_ci#define HSR_NODE_FORGET_TIME		60000 /* ms */
2462306a36Sopenharmony_ci#define HSR_ANNOUNCE_INTERVAL		  100 /* ms */
2562306a36Sopenharmony_ci#define HSR_ENTRY_FORGET_TIME		  400 /* ms */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* By how much may slave1 and slave2 timestamps of latest received frame from
2862306a36Sopenharmony_ci * each node differ before we notify of communication problem?
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci#define MAX_SLAVE_DIFF			 3000 /* ms */
3162306a36Sopenharmony_ci#define HSR_SEQNR_START			(USHRT_MAX - 1024)
3262306a36Sopenharmony_ci#define HSR_SUP_SEQNR_START		(HSR_SEQNR_START / 2)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* How often shall we check for broken ring and remove node entries older than
3562306a36Sopenharmony_ci * HSR_NODE_FORGET_TIME?
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ci#define PRUNE_PERIOD			 3000 /* ms */
3862306a36Sopenharmony_ci#define HSR_TLV_EOT				   0  /* End of TLVs */
3962306a36Sopenharmony_ci#define HSR_TLV_ANNOUNCE		   22
4062306a36Sopenharmony_ci#define HSR_TLV_LIFE_CHECK		   23
4162306a36Sopenharmony_ci/* PRP V1 life check for Duplicate discard */
4262306a36Sopenharmony_ci#define PRP_TLV_LIFE_CHECK_DD		   20
4362306a36Sopenharmony_ci/* PRP V1 life check for Duplicate Accept */
4462306a36Sopenharmony_ci#define PRP_TLV_LIFE_CHECK_DA		   21
4562306a36Sopenharmony_ci/* PRP V1 life redundancy box MAC address */
4662306a36Sopenharmony_ci#define PRP_TLV_REDBOX_MAC		   30
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define HSR_V1_SUP_LSDUSIZE		52
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/* The helper functions below assumes that 'path' occupies the 4 most
5162306a36Sopenharmony_ci * significant bits of the 16-bit field shared by 'path' and 'LSDU_size' (or
5262306a36Sopenharmony_ci * equivalently, the 4 most significant bits of HSR tag byte 14).
5362306a36Sopenharmony_ci *
5462306a36Sopenharmony_ci * This is unclear in the IEC specification; its definition of MAC addresses
5562306a36Sopenharmony_ci * indicates the spec is written with the least significant bit first (to the
5662306a36Sopenharmony_ci * left). This, however, would mean that the LSDU field would be split in two
5762306a36Sopenharmony_ci * with the path field in-between, which seems strange. I'm guessing the MAC
5862306a36Sopenharmony_ci * address definition is in error.
5962306a36Sopenharmony_ci */
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic inline void set_hsr_tag_path(struct hsr_tag *ht, u16 path)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	ht->path_and_LSDU_size =
6462306a36Sopenharmony_ci		htons((ntohs(ht->path_and_LSDU_size) & 0x0FFF) | (path << 12));
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic inline void set_hsr_tag_LSDU_size(struct hsr_tag *ht, u16 LSDU_size)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	ht->path_and_LSDU_size = htons((ntohs(ht->path_and_LSDU_size) &
7062306a36Sopenharmony_ci				       0xF000) | (LSDU_size & 0x0FFF));
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistruct hsr_ethhdr {
7462306a36Sopenharmony_ci	struct ethhdr	ethhdr;
7562306a36Sopenharmony_ci	struct hsr_tag	hsr_tag;
7662306a36Sopenharmony_ci} __packed;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistruct hsr_vlan_ethhdr {
7962306a36Sopenharmony_ci	struct vlan_ethhdr vlanhdr;
8062306a36Sopenharmony_ci	struct hsr_tag	hsr_tag;
8162306a36Sopenharmony_ci} __packed;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistruct hsr_sup_tlv {
8462306a36Sopenharmony_ci	u8		HSR_TLV_type;
8562306a36Sopenharmony_ci	u8		HSR_TLV_length;
8662306a36Sopenharmony_ci} __packed;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/* HSR/PRP Supervision Frame data types.
8962306a36Sopenharmony_ci * Field names as defined in the IEC:2010 standard for HSR.
9062306a36Sopenharmony_ci */
9162306a36Sopenharmony_cistruct hsr_sup_tag {
9262306a36Sopenharmony_ci	__be16				path_and_HSR_ver;
9362306a36Sopenharmony_ci	__be16				sequence_nr;
9462306a36Sopenharmony_ci	struct hsr_sup_tlv  tlv;
9562306a36Sopenharmony_ci} __packed;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistruct hsr_sup_payload {
9862306a36Sopenharmony_ci	unsigned char	macaddress_A[ETH_ALEN];
9962306a36Sopenharmony_ci} __packed;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic inline void set_hsr_stag_path(struct hsr_sup_tag *hst, u16 path)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	set_hsr_tag_path((struct hsr_tag *)hst, path);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic inline void set_hsr_stag_HSR_ver(struct hsr_sup_tag *hst, u16 HSR_ver)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	set_hsr_tag_LSDU_size((struct hsr_tag *)hst, HSR_ver);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct hsrv0_ethhdr_sp {
11262306a36Sopenharmony_ci	struct ethhdr		ethhdr;
11362306a36Sopenharmony_ci	struct hsr_sup_tag	hsr_sup;
11462306a36Sopenharmony_ci} __packed;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistruct hsrv1_ethhdr_sp {
11762306a36Sopenharmony_ci	struct ethhdr		ethhdr;
11862306a36Sopenharmony_ci	struct hsr_tag		hsr;
11962306a36Sopenharmony_ci	struct hsr_sup_tag	hsr_sup;
12062306a36Sopenharmony_ci} __packed;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cienum hsr_port_type {
12362306a36Sopenharmony_ci	HSR_PT_NONE = 0,	/* Must be 0, used by framereg */
12462306a36Sopenharmony_ci	HSR_PT_SLAVE_A,
12562306a36Sopenharmony_ci	HSR_PT_SLAVE_B,
12662306a36Sopenharmony_ci	HSR_PT_INTERLINK,
12762306a36Sopenharmony_ci	HSR_PT_MASTER,
12862306a36Sopenharmony_ci	HSR_PT_PORTS,	/* This must be the last item in the enum */
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/* PRP Redunancy Control Trailor (RCT).
13262306a36Sopenharmony_ci * As defined in IEC-62439-4:2012, the PRP RCT is really { sequence Nr,
13362306a36Sopenharmony_ci * Lan indentifier (LanId), LSDU_size and PRP_suffix = 0x88FB }.
13462306a36Sopenharmony_ci *
13562306a36Sopenharmony_ci * Field names as defined in the IEC:2012 standard for PRP.
13662306a36Sopenharmony_ci */
13762306a36Sopenharmony_cistruct prp_rct {
13862306a36Sopenharmony_ci	__be16          sequence_nr;
13962306a36Sopenharmony_ci	__be16          lan_id_and_LSDU_size;
14062306a36Sopenharmony_ci	__be16          PRP_suffix;
14162306a36Sopenharmony_ci} __packed;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic inline u16 get_prp_LSDU_size(struct prp_rct *rct)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	return ntohs(rct->lan_id_and_LSDU_size) & 0x0FFF;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic inline void set_prp_lan_id(struct prp_rct *rct, u16 lan_id)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	rct->lan_id_and_LSDU_size = htons((ntohs(rct->lan_id_and_LSDU_size) &
15162306a36Sopenharmony_ci					  0x0FFF) | (lan_id << 12));
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_cistatic inline void set_prp_LSDU_size(struct prp_rct *rct, u16 LSDU_size)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	rct->lan_id_and_LSDU_size = htons((ntohs(rct->lan_id_and_LSDU_size) &
15662306a36Sopenharmony_ci					  0xF000) | (LSDU_size & 0x0FFF));
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistruct hsr_port {
16062306a36Sopenharmony_ci	struct list_head	port_list;
16162306a36Sopenharmony_ci	struct net_device	*dev;
16262306a36Sopenharmony_ci	struct hsr_priv		*hsr;
16362306a36Sopenharmony_ci	enum hsr_port_type	type;
16462306a36Sopenharmony_ci};
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistruct hsr_frame_info;
16762306a36Sopenharmony_cistruct hsr_node;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistruct hsr_proto_ops {
17062306a36Sopenharmony_ci	/* format and send supervision frame */
17162306a36Sopenharmony_ci	void (*send_sv_frame)(struct hsr_port *port, unsigned long *interval);
17262306a36Sopenharmony_ci	void (*handle_san_frame)(bool san, enum hsr_port_type port,
17362306a36Sopenharmony_ci				 struct hsr_node *node);
17462306a36Sopenharmony_ci	bool (*drop_frame)(struct hsr_frame_info *frame, struct hsr_port *port);
17562306a36Sopenharmony_ci	struct sk_buff * (*get_untagged_frame)(struct hsr_frame_info *frame,
17662306a36Sopenharmony_ci					       struct hsr_port *port);
17762306a36Sopenharmony_ci	struct sk_buff * (*create_tagged_frame)(struct hsr_frame_info *frame,
17862306a36Sopenharmony_ci						struct hsr_port *port);
17962306a36Sopenharmony_ci	int (*fill_frame_info)(__be16 proto, struct sk_buff *skb,
18062306a36Sopenharmony_ci			       struct hsr_frame_info *frame);
18162306a36Sopenharmony_ci	bool (*invalid_dan_ingress_frame)(__be16 protocol);
18262306a36Sopenharmony_ci	void (*update_san_info)(struct hsr_node *node, bool is_sup);
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistruct hsr_self_node {
18662306a36Sopenharmony_ci	unsigned char	macaddress_A[ETH_ALEN];
18762306a36Sopenharmony_ci	unsigned char	macaddress_B[ETH_ALEN];
18862306a36Sopenharmony_ci	struct rcu_head	rcu_head;
18962306a36Sopenharmony_ci};
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistruct hsr_priv {
19262306a36Sopenharmony_ci	struct rcu_head		rcu_head;
19362306a36Sopenharmony_ci	struct list_head	ports;
19462306a36Sopenharmony_ci	struct list_head	node_db;	/* Known HSR nodes */
19562306a36Sopenharmony_ci	struct hsr_self_node	__rcu *self_node;	/* MACs of slaves */
19662306a36Sopenharmony_ci	struct timer_list	announce_timer;	/* Supervision frame dispatch */
19762306a36Sopenharmony_ci	struct timer_list	prune_timer;
19862306a36Sopenharmony_ci	int announce_count;
19962306a36Sopenharmony_ci	u16 sequence_nr;
20062306a36Sopenharmony_ci	u16 sup_sequence_nr;	/* For HSRv1 separate seq_nr for supervision */
20162306a36Sopenharmony_ci	enum hsr_version prot_version;	/* Indicate if HSRv0, HSRv1 or PRPv1 */
20262306a36Sopenharmony_ci	spinlock_t seqnr_lock;	/* locking for sequence_nr */
20362306a36Sopenharmony_ci	spinlock_t list_lock;	/* locking for node list */
20462306a36Sopenharmony_ci	struct hsr_proto_ops	*proto_ops;
20562306a36Sopenharmony_ci#define PRP_LAN_ID	0x5     /* 0x1010 for A and 0x1011 for B. Bit 0 is set
20662306a36Sopenharmony_ci				 * based on SLAVE_A or SLAVE_B
20762306a36Sopenharmony_ci				 */
20862306a36Sopenharmony_ci	u8 net_id;		/* for PRP, it occupies most significant 3 bits
20962306a36Sopenharmony_ci				 * of lan_id
21062306a36Sopenharmony_ci				 */
21162306a36Sopenharmony_ci	bool fwd_offloaded;	/* Forwarding offloaded to HW */
21262306a36Sopenharmony_ci	unsigned char		sup_multicast_addr[ETH_ALEN] __aligned(sizeof(u16));
21362306a36Sopenharmony_ci				/* Align to u16 boundary to avoid unaligned access
21462306a36Sopenharmony_ci				 * in ether_addr_equal
21562306a36Sopenharmony_ci				 */
21662306a36Sopenharmony_ci#ifdef	CONFIG_DEBUG_FS
21762306a36Sopenharmony_ci	struct dentry *node_tbl_root;
21862306a36Sopenharmony_ci#endif
21962306a36Sopenharmony_ci};
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci#define hsr_for_each_port(hsr, port) \
22262306a36Sopenharmony_ci	list_for_each_entry_rcu((port), &(hsr)->ports, port_list)
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistruct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci/* Caller must ensure skb is a valid HSR frame */
22762306a36Sopenharmony_cistatic inline u16 hsr_get_skb_sequence_nr(struct sk_buff *skb)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	struct hsr_ethhdr *hsr_ethhdr;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	hsr_ethhdr = (struct hsr_ethhdr *)skb_mac_header(skb);
23262306a36Sopenharmony_ci	return ntohs(hsr_ethhdr->hsr_tag.sequence_nr);
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic inline struct prp_rct *skb_get_PRP_rct(struct sk_buff *skb)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	unsigned char *tail = skb_tail_pointer(skb) - HSR_HLEN;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	struct prp_rct *rct = (struct prp_rct *)tail;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (rct->PRP_suffix == htons(ETH_P_PRP))
24262306a36Sopenharmony_ci		return rct;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return NULL;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci/* Assume caller has confirmed this skb is PRP suffixed */
24862306a36Sopenharmony_cistatic inline u16 prp_get_skb_sequence_nr(struct prp_rct *rct)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	return ntohs(rct->sequence_nr);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci/* assume there is a valid rct */
25462306a36Sopenharmony_cistatic inline bool prp_check_lsdu_size(struct sk_buff *skb,
25562306a36Sopenharmony_ci				       struct prp_rct *rct,
25662306a36Sopenharmony_ci				       bool is_sup)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	struct ethhdr *ethhdr;
25962306a36Sopenharmony_ci	int expected_lsdu_size;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (is_sup) {
26262306a36Sopenharmony_ci		expected_lsdu_size = HSR_V1_SUP_LSDUSIZE;
26362306a36Sopenharmony_ci	} else {
26462306a36Sopenharmony_ci		ethhdr = (struct ethhdr *)skb_mac_header(skb);
26562306a36Sopenharmony_ci		expected_lsdu_size = skb->len - 14;
26662306a36Sopenharmony_ci		if (ethhdr->h_proto == htons(ETH_P_8021Q))
26762306a36Sopenharmony_ci			expected_lsdu_size -= 4;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	return (expected_lsdu_size == get_prp_LSDU_size(rct));
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DEBUG_FS)
27462306a36Sopenharmony_civoid hsr_debugfs_rename(struct net_device *dev);
27562306a36Sopenharmony_civoid hsr_debugfs_init(struct hsr_priv *priv, struct net_device *hsr_dev);
27662306a36Sopenharmony_civoid hsr_debugfs_term(struct hsr_priv *priv);
27762306a36Sopenharmony_civoid hsr_debugfs_create_root(void);
27862306a36Sopenharmony_civoid hsr_debugfs_remove_root(void);
27962306a36Sopenharmony_ci#else
28062306a36Sopenharmony_cistatic inline void hsr_debugfs_rename(struct net_device *dev)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_cistatic inline void hsr_debugfs_init(struct hsr_priv *priv,
28462306a36Sopenharmony_ci				    struct net_device *hsr_dev)
28562306a36Sopenharmony_ci{}
28662306a36Sopenharmony_cistatic inline void hsr_debugfs_term(struct hsr_priv *priv)
28762306a36Sopenharmony_ci{}
28862306a36Sopenharmony_cistatic inline void hsr_debugfs_create_root(void)
28962306a36Sopenharmony_ci{}
29062306a36Sopenharmony_cistatic inline void hsr_debugfs_remove_root(void)
29162306a36Sopenharmony_ci{}
29262306a36Sopenharmony_ci#endif
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci#endif /*  __HSR_PRIVATE_H */
295