18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/* Copyright 2011-2014 Autronica Fire and Security AS
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Author(s):
58c2ecf20Sopenharmony_ci *	2011-2014 Arvid Brodin, arvid.brodin@alten.se
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * include file for HSR and PRP.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#ifndef __HSR_PRIVATE_H
118c2ecf20Sopenharmony_ci#define __HSR_PRIVATE_H
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
148c2ecf20Sopenharmony_ci#include <linux/list.h>
158c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* Time constants as specified in the HSR specification (IEC-62439-3 2010)
188c2ecf20Sopenharmony_ci * Table 8.
198c2ecf20Sopenharmony_ci * All values in milliseconds.
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_ci#define HSR_LIFE_CHECK_INTERVAL		 2000 /* ms */
228c2ecf20Sopenharmony_ci#define HSR_NODE_FORGET_TIME		60000 /* ms */
238c2ecf20Sopenharmony_ci#define HSR_ANNOUNCE_INTERVAL		  100 /* ms */
248c2ecf20Sopenharmony_ci#define HSR_ENTRY_FORGET_TIME		  400 /* ms */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* By how much may slave1 and slave2 timestamps of latest received frame from
278c2ecf20Sopenharmony_ci * each node differ before we notify of communication problem?
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_ci#define MAX_SLAVE_DIFF			 3000 /* ms */
308c2ecf20Sopenharmony_ci#define HSR_SEQNR_START			(USHRT_MAX - 1024)
318c2ecf20Sopenharmony_ci#define HSR_SUP_SEQNR_START		(HSR_SEQNR_START / 2)
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/* How often shall we check for broken ring and remove node entries older than
348c2ecf20Sopenharmony_ci * HSR_NODE_FORGET_TIME?
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci#define PRUNE_PERIOD			 3000 /* ms */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define HSR_TLV_ANNOUNCE		   22
398c2ecf20Sopenharmony_ci#define HSR_TLV_LIFE_CHECK		   23
408c2ecf20Sopenharmony_ci/* PRP V1 life check for Duplicate discard */
418c2ecf20Sopenharmony_ci#define PRP_TLV_LIFE_CHECK_DD		   20
428c2ecf20Sopenharmony_ci/* PRP V1 life check for Duplicate Accept */
438c2ecf20Sopenharmony_ci#define PRP_TLV_LIFE_CHECK_DA		   21
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* HSR Tag.
468c2ecf20Sopenharmony_ci * As defined in IEC-62439-3:2010, the HSR tag is really { ethertype = 0x88FB,
478c2ecf20Sopenharmony_ci * path, LSDU_size, sequence Nr }. But we let eth_header() create { h_dest,
488c2ecf20Sopenharmony_ci * h_source, h_proto = 0x88FB }, and add { path, LSDU_size, sequence Nr,
498c2ecf20Sopenharmony_ci * encapsulated protocol } instead.
508c2ecf20Sopenharmony_ci *
518c2ecf20Sopenharmony_ci * Field names as defined in the IEC:2010 standard for HSR.
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_cistruct hsr_tag {
548c2ecf20Sopenharmony_ci	__be16		path_and_LSDU_size;
558c2ecf20Sopenharmony_ci	__be16		sequence_nr;
568c2ecf20Sopenharmony_ci	__be16		encap_proto;
578c2ecf20Sopenharmony_ci} __packed;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define HSR_HLEN	6
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define HSR_V1_SUP_LSDUSIZE		52
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* The helper functions below assumes that 'path' occupies the 4 most
648c2ecf20Sopenharmony_ci * significant bits of the 16-bit field shared by 'path' and 'LSDU_size' (or
658c2ecf20Sopenharmony_ci * equivalently, the 4 most significant bits of HSR tag byte 14).
668c2ecf20Sopenharmony_ci *
678c2ecf20Sopenharmony_ci * This is unclear in the IEC specification; its definition of MAC addresses
688c2ecf20Sopenharmony_ci * indicates the spec is written with the least significant bit first (to the
698c2ecf20Sopenharmony_ci * left). This, however, would mean that the LSDU field would be split in two
708c2ecf20Sopenharmony_ci * with the path field in-between, which seems strange. I'm guessing the MAC
718c2ecf20Sopenharmony_ci * address definition is in error.
728c2ecf20Sopenharmony_ci */
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic inline void set_hsr_tag_path(struct hsr_tag *ht, u16 path)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	ht->path_and_LSDU_size =
778c2ecf20Sopenharmony_ci		htons((ntohs(ht->path_and_LSDU_size) & 0x0FFF) | (path << 12));
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic inline void set_hsr_tag_LSDU_size(struct hsr_tag *ht, u16 LSDU_size)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	ht->path_and_LSDU_size = htons((ntohs(ht->path_and_LSDU_size) &
838c2ecf20Sopenharmony_ci				       0xF000) | (LSDU_size & 0x0FFF));
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistruct hsr_ethhdr {
878c2ecf20Sopenharmony_ci	struct ethhdr	ethhdr;
888c2ecf20Sopenharmony_ci	struct hsr_tag	hsr_tag;
898c2ecf20Sopenharmony_ci} __packed;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistruct hsr_vlan_ethhdr {
928c2ecf20Sopenharmony_ci	struct vlan_ethhdr vlanhdr;
938c2ecf20Sopenharmony_ci	struct hsr_tag	hsr_tag;
948c2ecf20Sopenharmony_ci} __packed;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/* HSR/PRP Supervision Frame data types.
978c2ecf20Sopenharmony_ci * Field names as defined in the IEC:2010 standard for HSR.
988c2ecf20Sopenharmony_ci */
998c2ecf20Sopenharmony_cistruct hsr_sup_tag {
1008c2ecf20Sopenharmony_ci	__be16		path_and_HSR_ver;
1018c2ecf20Sopenharmony_ci	__be16		sequence_nr;
1028c2ecf20Sopenharmony_ci	__u8		HSR_TLV_type;
1038c2ecf20Sopenharmony_ci	__u8		HSR_TLV_length;
1048c2ecf20Sopenharmony_ci} __packed;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistruct hsr_sup_payload {
1078c2ecf20Sopenharmony_ci	unsigned char	macaddress_A[ETH_ALEN];
1088c2ecf20Sopenharmony_ci} __packed;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic inline void set_hsr_stag_path(struct hsr_sup_tag *hst, u16 path)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	set_hsr_tag_path((struct hsr_tag *)hst, path);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic inline void set_hsr_stag_HSR_ver(struct hsr_sup_tag *hst, u16 HSR_ver)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	set_hsr_tag_LSDU_size((struct hsr_tag *)hst, HSR_ver);
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistruct hsrv0_ethhdr_sp {
1218c2ecf20Sopenharmony_ci	struct ethhdr		ethhdr;
1228c2ecf20Sopenharmony_ci	struct hsr_sup_tag	hsr_sup;
1238c2ecf20Sopenharmony_ci} __packed;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistruct hsrv1_ethhdr_sp {
1268c2ecf20Sopenharmony_ci	struct ethhdr		ethhdr;
1278c2ecf20Sopenharmony_ci	struct hsr_tag		hsr;
1288c2ecf20Sopenharmony_ci	struct hsr_sup_tag	hsr_sup;
1298c2ecf20Sopenharmony_ci} __packed;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cienum hsr_port_type {
1328c2ecf20Sopenharmony_ci	HSR_PT_NONE = 0,	/* Must be 0, used by framereg */
1338c2ecf20Sopenharmony_ci	HSR_PT_SLAVE_A,
1348c2ecf20Sopenharmony_ci	HSR_PT_SLAVE_B,
1358c2ecf20Sopenharmony_ci	HSR_PT_INTERLINK,
1368c2ecf20Sopenharmony_ci	HSR_PT_MASTER,
1378c2ecf20Sopenharmony_ci	HSR_PT_PORTS,	/* This must be the last item in the enum */
1388c2ecf20Sopenharmony_ci};
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/* PRP Redunancy Control Trailor (RCT).
1418c2ecf20Sopenharmony_ci * As defined in IEC-62439-4:2012, the PRP RCT is really { sequence Nr,
1428c2ecf20Sopenharmony_ci * Lan indentifier (LanId), LSDU_size and PRP_suffix = 0x88FB }.
1438c2ecf20Sopenharmony_ci *
1448c2ecf20Sopenharmony_ci * Field names as defined in the IEC:2012 standard for PRP.
1458c2ecf20Sopenharmony_ci */
1468c2ecf20Sopenharmony_cistruct prp_rct {
1478c2ecf20Sopenharmony_ci	__be16          sequence_nr;
1488c2ecf20Sopenharmony_ci	__be16          lan_id_and_LSDU_size;
1498c2ecf20Sopenharmony_ci	__be16          PRP_suffix;
1508c2ecf20Sopenharmony_ci} __packed;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic inline u16 get_prp_LSDU_size(struct prp_rct *rct)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	return ntohs(rct->lan_id_and_LSDU_size) & 0x0FFF;
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic inline void set_prp_lan_id(struct prp_rct *rct, u16 lan_id)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	rct->lan_id_and_LSDU_size = htons((ntohs(rct->lan_id_and_LSDU_size) &
1608c2ecf20Sopenharmony_ci					  0x0FFF) | (lan_id << 12));
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_cistatic inline void set_prp_LSDU_size(struct prp_rct *rct, u16 LSDU_size)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	rct->lan_id_and_LSDU_size = htons((ntohs(rct->lan_id_and_LSDU_size) &
1658c2ecf20Sopenharmony_ci					  0xF000) | (LSDU_size & 0x0FFF));
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistruct hsr_port {
1698c2ecf20Sopenharmony_ci	struct list_head	port_list;
1708c2ecf20Sopenharmony_ci	struct net_device	*dev;
1718c2ecf20Sopenharmony_ci	struct hsr_priv		*hsr;
1728c2ecf20Sopenharmony_ci	enum hsr_port_type	type;
1738c2ecf20Sopenharmony_ci};
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci/* used by driver internally to differentiate various protocols */
1768c2ecf20Sopenharmony_cienum hsr_version {
1778c2ecf20Sopenharmony_ci	HSR_V0 = 0,
1788c2ecf20Sopenharmony_ci	HSR_V1,
1798c2ecf20Sopenharmony_ci	PRP_V1,
1808c2ecf20Sopenharmony_ci};
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistruct hsr_frame_info;
1838c2ecf20Sopenharmony_cistruct hsr_node;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistruct hsr_proto_ops {
1868c2ecf20Sopenharmony_ci	/* format and send supervision frame */
1878c2ecf20Sopenharmony_ci	void (*send_sv_frame)(struct hsr_port *port, unsigned long *interval);
1888c2ecf20Sopenharmony_ci	void (*handle_san_frame)(bool san, enum hsr_port_type port,
1898c2ecf20Sopenharmony_ci				 struct hsr_node *node);
1908c2ecf20Sopenharmony_ci	bool (*drop_frame)(struct hsr_frame_info *frame, struct hsr_port *port);
1918c2ecf20Sopenharmony_ci	struct sk_buff * (*get_untagged_frame)(struct hsr_frame_info *frame,
1928c2ecf20Sopenharmony_ci					       struct hsr_port *port);
1938c2ecf20Sopenharmony_ci	struct sk_buff * (*create_tagged_frame)(struct hsr_frame_info *frame,
1948c2ecf20Sopenharmony_ci						struct hsr_port *port);
1958c2ecf20Sopenharmony_ci	int (*fill_frame_info)(__be16 proto, struct sk_buff *skb,
1968c2ecf20Sopenharmony_ci			       struct hsr_frame_info *frame);
1978c2ecf20Sopenharmony_ci	bool (*invalid_dan_ingress_frame)(__be16 protocol);
1988c2ecf20Sopenharmony_ci	void (*update_san_info)(struct hsr_node *node, bool is_sup);
1998c2ecf20Sopenharmony_ci};
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistruct hsr_priv {
2028c2ecf20Sopenharmony_ci	struct rcu_head		rcu_head;
2038c2ecf20Sopenharmony_ci	struct list_head	ports;
2048c2ecf20Sopenharmony_ci	struct list_head	node_db;	/* Known HSR nodes */
2058c2ecf20Sopenharmony_ci	struct list_head	self_node_db;	/* MACs of slaves */
2068c2ecf20Sopenharmony_ci	struct timer_list	announce_timer;	/* Supervision frame dispatch */
2078c2ecf20Sopenharmony_ci	struct timer_list	prune_timer;
2088c2ecf20Sopenharmony_ci	int announce_count;
2098c2ecf20Sopenharmony_ci	u16 sequence_nr;
2108c2ecf20Sopenharmony_ci	u16 sup_sequence_nr;	/* For HSRv1 separate seq_nr for supervision */
2118c2ecf20Sopenharmony_ci	enum hsr_version prot_version;	/* Indicate if HSRv0, HSRv1 or PRPv1 */
2128c2ecf20Sopenharmony_ci	spinlock_t seqnr_lock;	/* locking for sequence_nr */
2138c2ecf20Sopenharmony_ci	spinlock_t list_lock;	/* locking for node list */
2148c2ecf20Sopenharmony_ci	struct hsr_proto_ops	*proto_ops;
2158c2ecf20Sopenharmony_ci#define PRP_LAN_ID	0x5     /* 0x1010 for A and 0x1011 for B. Bit 0 is set
2168c2ecf20Sopenharmony_ci				 * based on SLAVE_A or SLAVE_B
2178c2ecf20Sopenharmony_ci				 */
2188c2ecf20Sopenharmony_ci	u8 net_id;		/* for PRP, it occupies most significant 3 bits
2198c2ecf20Sopenharmony_ci				 * of lan_id
2208c2ecf20Sopenharmony_ci				 */
2218c2ecf20Sopenharmony_ci	unsigned char		sup_multicast_addr[ETH_ALEN];
2228c2ecf20Sopenharmony_ci#ifdef	CONFIG_DEBUG_FS
2238c2ecf20Sopenharmony_ci	struct dentry *node_tbl_root;
2248c2ecf20Sopenharmony_ci#endif
2258c2ecf20Sopenharmony_ci};
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci#define hsr_for_each_port(hsr, port) \
2288c2ecf20Sopenharmony_ci	list_for_each_entry_rcu((port), &(hsr)->ports, port_list)
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistruct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci/* Caller must ensure skb is a valid HSR frame */
2338c2ecf20Sopenharmony_cistatic inline u16 hsr_get_skb_sequence_nr(struct sk_buff *skb)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct hsr_ethhdr *hsr_ethhdr;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	hsr_ethhdr = (struct hsr_ethhdr *)skb_mac_header(skb);
2388c2ecf20Sopenharmony_ci	return ntohs(hsr_ethhdr->hsr_tag.sequence_nr);
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic inline struct prp_rct *skb_get_PRP_rct(struct sk_buff *skb)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	unsigned char *tail = skb_tail_pointer(skb) - HSR_HLEN;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	struct prp_rct *rct = (struct prp_rct *)tail;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if (rct->PRP_suffix == htons(ETH_P_PRP))
2488c2ecf20Sopenharmony_ci		return rct;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	return NULL;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci/* Assume caller has confirmed this skb is PRP suffixed */
2548c2ecf20Sopenharmony_cistatic inline u16 prp_get_skb_sequence_nr(struct prp_rct *rct)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	return ntohs(rct->sequence_nr);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic inline u16 get_prp_lan_id(struct prp_rct *rct)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	return ntohs(rct->lan_id_and_LSDU_size) >> 12;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci/* assume there is a valid rct */
2658c2ecf20Sopenharmony_cistatic inline bool prp_check_lsdu_size(struct sk_buff *skb,
2668c2ecf20Sopenharmony_ci				       struct prp_rct *rct,
2678c2ecf20Sopenharmony_ci				       bool is_sup)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	struct ethhdr *ethhdr;
2708c2ecf20Sopenharmony_ci	int expected_lsdu_size;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (is_sup) {
2738c2ecf20Sopenharmony_ci		expected_lsdu_size = HSR_V1_SUP_LSDUSIZE;
2748c2ecf20Sopenharmony_ci	} else {
2758c2ecf20Sopenharmony_ci		ethhdr = (struct ethhdr *)skb_mac_header(skb);
2768c2ecf20Sopenharmony_ci		expected_lsdu_size = skb->len - 14;
2778c2ecf20Sopenharmony_ci		if (ethhdr->h_proto == htons(ETH_P_8021Q))
2788c2ecf20Sopenharmony_ci			expected_lsdu_size -= 4;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	return (expected_lsdu_size == get_prp_LSDU_size(rct));
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DEBUG_FS)
2858c2ecf20Sopenharmony_civoid hsr_debugfs_rename(struct net_device *dev);
2868c2ecf20Sopenharmony_civoid hsr_debugfs_init(struct hsr_priv *priv, struct net_device *hsr_dev);
2878c2ecf20Sopenharmony_civoid hsr_debugfs_term(struct hsr_priv *priv);
2888c2ecf20Sopenharmony_civoid hsr_debugfs_create_root(void);
2898c2ecf20Sopenharmony_civoid hsr_debugfs_remove_root(void);
2908c2ecf20Sopenharmony_ci#else
2918c2ecf20Sopenharmony_cistatic inline void hsr_debugfs_rename(struct net_device *dev)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_cistatic inline void hsr_debugfs_init(struct hsr_priv *priv,
2958c2ecf20Sopenharmony_ci				    struct net_device *hsr_dev)
2968c2ecf20Sopenharmony_ci{}
2978c2ecf20Sopenharmony_cistatic inline void hsr_debugfs_term(struct hsr_priv *priv)
2988c2ecf20Sopenharmony_ci{}
2998c2ecf20Sopenharmony_cistatic inline void hsr_debugfs_create_root(void)
3008c2ecf20Sopenharmony_ci{}
3018c2ecf20Sopenharmony_cistatic inline void hsr_debugfs_remove_root(void)
3028c2ecf20Sopenharmony_ci{}
3038c2ecf20Sopenharmony_ci#endif
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci#endif /*  __HSR_PRIVATE_H */
306