mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net/hsr: Added support for HSR v1
This patch adds support for the newer version 1 of the HSR networking standard. Version 0 is still default and the new version has to be selected via iproute2. Main changes are in the supervision frame handling and its ethertype field. Signed-off-by: Peter Heise <peter.heise@airbus.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									125c8d1233
								
							
						
					
					
						commit
						ee1c279772
					
				
					 10 changed files with 126 additions and 63 deletions
				
			
		| 
						 | 
				
			
			@ -92,6 +92,7 @@
 | 
			
		|||
#define ETH_P_TDLS	0x890D          /* TDLS */
 | 
			
		||||
#define ETH_P_FIP	0x8914		/* FCoE Initialization Protocol */
 | 
			
		||||
#define ETH_P_80221	0x8917		/* IEEE 802.21 Media Independent Handover Protocol */
 | 
			
		||||
#define ETH_P_HSR	0x892F		/* IEC 62439-3 HSRv1	*/
 | 
			
		||||
#define ETH_P_LOOPBACK	0x9000		/* Ethernet loopback packet, per IEEE 802.3 */
 | 
			
		||||
#define ETH_P_QINQ1	0x9100		/* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
 | 
			
		||||
#define ETH_P_QINQ2	0x9200		/* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -773,6 +773,7 @@ enum {
 | 
			
		|||
	IFLA_HSR_SLAVE1,
 | 
			
		||||
	IFLA_HSR_SLAVE2,
 | 
			
		||||
	IFLA_HSR_MULTICAST_SPEC,	/* Last byte of supervision addr */
 | 
			
		||||
	IFLA_HSR_VERSION,		/* HSR version */
 | 
			
		||||
	IFLA_HSR_SUPERVISION_ADDR,	/* Supervision frame multicast addr */
 | 
			
		||||
	IFLA_HSR_SEQ_NR,
 | 
			
		||||
	__IFLA_HSR_MAX,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,8 +18,9 @@ config HSR
 | 
			
		|||
	  earlier.
 | 
			
		||||
 | 
			
		||||
	  This code is a "best effort" to comply with the HSR standard as
 | 
			
		||||
	  described in IEC 62439-3:2010 (HSRv0), but no compliancy tests have
 | 
			
		||||
	  been made.
 | 
			
		||||
	  described in IEC 62439-3:2010 (HSRv0) and IEC 62439-3:2012 (HSRv1),
 | 
			
		||||
	  but no compliancy tests have been made. Use iproute2 to select
 | 
			
		||||
	  the version you desire.
 | 
			
		||||
 | 
			
		||||
	  You need to perform any and all necessary tests yourself before
 | 
			
		||||
	  relying on this code in a safety critical system!
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -90,7 +90,8 @@ static void hsr_check_announce(struct net_device *hsr_dev,
 | 
			
		|||
 | 
			
		||||
	hsr = netdev_priv(hsr_dev);
 | 
			
		||||
 | 
			
		||||
	if ((hsr_dev->operstate == IF_OPER_UP) && (old_operstate != IF_OPER_UP)) {
 | 
			
		||||
	if ((hsr_dev->operstate == IF_OPER_UP)
 | 
			
		||||
			&& (old_operstate != IF_OPER_UP)) {
 | 
			
		||||
		/* Went up */
 | 
			
		||||
		hsr->announce_count = 0;
 | 
			
		||||
		hsr->announce_timer.expires = jiffies +
 | 
			
		||||
| 
						 | 
				
			
			@ -250,31 +251,22 @@ static const struct header_ops hsr_header_ops = {
 | 
			
		|||
	.parse	 = eth_header_parse,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* HSR:2010 supervision frames should be padded so that the whole frame,
 | 
			
		||||
 * including headers and FCS, is 64 bytes (without VLAN).
 | 
			
		||||
 */
 | 
			
		||||
static int hsr_pad(int size)
 | 
			
		||||
{
 | 
			
		||||
	const int min_size = ETH_ZLEN - HSR_HLEN - ETH_HLEN;
 | 
			
		||||
 | 
			
		||||
	if (size >= min_size)
 | 
			
		||||
		return size;
 | 
			
		||||
	return min_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void send_hsr_supervision_frame(struct hsr_port *master, u8 type)
 | 
			
		||||
static void send_hsr_supervision_frame(struct hsr_port *master,
 | 
			
		||||
		u8 type, u8 hsrVer)
 | 
			
		||||
{
 | 
			
		||||
	struct sk_buff *skb;
 | 
			
		||||
	int hlen, tlen;
 | 
			
		||||
	struct hsr_tag *hsr_tag;
 | 
			
		||||
	struct hsr_sup_tag *hsr_stag;
 | 
			
		||||
	struct hsr_sup_payload *hsr_sp;
 | 
			
		||||
	unsigned long irqflags;
 | 
			
		||||
 | 
			
		||||
	hlen = LL_RESERVED_SPACE(master->dev);
 | 
			
		||||
	tlen = master->dev->needed_tailroom;
 | 
			
		||||
	skb = alloc_skb(hsr_pad(sizeof(struct hsr_sup_payload)) + hlen + tlen,
 | 
			
		||||
			GFP_ATOMIC);
 | 
			
		||||
	skb = dev_alloc_skb(
 | 
			
		||||
			sizeof(struct hsr_tag) +
 | 
			
		||||
			sizeof(struct hsr_sup_tag) +
 | 
			
		||||
			sizeof(struct hsr_sup_payload) + hlen + tlen);
 | 
			
		||||
 | 
			
		||||
	if (skb == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -282,32 +274,48 @@ static void send_hsr_supervision_frame(struct hsr_port *master, u8 type)
 | 
			
		|||
	skb_reserve(skb, hlen);
 | 
			
		||||
 | 
			
		||||
	skb->dev = master->dev;
 | 
			
		||||
	skb->protocol = htons(ETH_P_PRP);
 | 
			
		||||
	skb->protocol = htons(hsrVer ? ETH_P_HSR : ETH_P_PRP);
 | 
			
		||||
	skb->priority = TC_PRIO_CONTROL;
 | 
			
		||||
 | 
			
		||||
	if (dev_hard_header(skb, skb->dev, ETH_P_PRP,
 | 
			
		||||
	if (dev_hard_header(skb, skb->dev, (hsrVer ? ETH_P_HSR : ETH_P_PRP),
 | 
			
		||||
			    master->hsr->sup_multicast_addr,
 | 
			
		||||
			    skb->dev->dev_addr, skb->len) <= 0)
 | 
			
		||||
		goto out;
 | 
			
		||||
	skb_reset_mac_header(skb);
 | 
			
		||||
 | 
			
		||||
	hsr_stag = (typeof(hsr_stag)) skb_put(skb, sizeof(*hsr_stag));
 | 
			
		||||
	if (hsrVer > 0) {
 | 
			
		||||
		hsr_tag = (typeof(hsr_tag)) skb_put(skb, sizeof(struct hsr_tag));
 | 
			
		||||
		hsr_tag->encap_proto = htons(ETH_P_PRP);
 | 
			
		||||
		set_hsr_tag_LSDU_size(hsr_tag, HSR_V1_SUP_LSDUSIZE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	set_hsr_stag_path(hsr_stag, 0xf);
 | 
			
		||||
	set_hsr_stag_HSR_Ver(hsr_stag, 0);
 | 
			
		||||
	hsr_stag = (typeof(hsr_stag)) skb_put(skb, sizeof(struct hsr_sup_tag));
 | 
			
		||||
	set_hsr_stag_path(hsr_stag, (hsrVer ? 0x0 : 0xf));
 | 
			
		||||
	set_hsr_stag_HSR_Ver(hsr_stag, hsrVer);
 | 
			
		||||
 | 
			
		||||
	/* From HSRv1 on we have separate supervision sequence numbers. */
 | 
			
		||||
	spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags);
 | 
			
		||||
	hsr_stag->sequence_nr = htons(master->hsr->sequence_nr);
 | 
			
		||||
	master->hsr->sequence_nr++;
 | 
			
		||||
	if (hsrVer > 0) {
 | 
			
		||||
		hsr_stag->sequence_nr = htons(master->hsr->sup_sequence_nr);
 | 
			
		||||
		hsr_tag->sequence_nr = htons(master->hsr->sequence_nr);
 | 
			
		||||
		master->hsr->sup_sequence_nr++;
 | 
			
		||||
		master->hsr->sequence_nr++;
 | 
			
		||||
	} else {
 | 
			
		||||
		hsr_stag->sequence_nr = htons(master->hsr->sequence_nr);
 | 
			
		||||
		master->hsr->sequence_nr++;
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags);
 | 
			
		||||
 | 
			
		||||
	hsr_stag->HSR_TLV_Type = type;
 | 
			
		||||
	hsr_stag->HSR_TLV_Length = 12;
 | 
			
		||||
	/* TODO: Why 12 in HSRv0? */
 | 
			
		||||
	hsr_stag->HSR_TLV_Length = hsrVer ? sizeof(struct hsr_sup_payload) : 12;
 | 
			
		||||
 | 
			
		||||
	/* Payload: MacAddressA */
 | 
			
		||||
	hsr_sp = (typeof(hsr_sp)) skb_put(skb, sizeof(*hsr_sp));
 | 
			
		||||
	hsr_sp = (typeof(hsr_sp)) skb_put(skb, sizeof(struct hsr_sup_payload));
 | 
			
		||||
	ether_addr_copy(hsr_sp->MacAddressA, master->dev->dev_addr);
 | 
			
		||||
 | 
			
		||||
	skb_put_padto(skb, ETH_ZLEN + HSR_HLEN);
 | 
			
		||||
 | 
			
		||||
	hsr_forward_skb(skb, master);
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -329,19 +337,20 @@ static void hsr_announce(unsigned long data)
 | 
			
		|||
	rcu_read_lock();
 | 
			
		||||
	master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
 | 
			
		||||
 | 
			
		||||
	if (hsr->announce_count < 3) {
 | 
			
		||||
		send_hsr_supervision_frame(master, HSR_TLV_ANNOUNCE);
 | 
			
		||||
	if (hsr->announce_count < 3 && hsr->protVersion == 0) {
 | 
			
		||||
		send_hsr_supervision_frame(master, HSR_TLV_ANNOUNCE,
 | 
			
		||||
				hsr->protVersion);
 | 
			
		||||
		hsr->announce_count++;
 | 
			
		||||
	} else {
 | 
			
		||||
		send_hsr_supervision_frame(master, HSR_TLV_LIFE_CHECK);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (hsr->announce_count < 3)
 | 
			
		||||
		hsr->announce_timer.expires = jiffies +
 | 
			
		||||
				msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL);
 | 
			
		||||
	else
 | 
			
		||||
	} else {
 | 
			
		||||
		send_hsr_supervision_frame(master, HSR_TLV_LIFE_CHECK,
 | 
			
		||||
				hsr->protVersion);
 | 
			
		||||
 | 
			
		||||
		hsr->announce_timer.expires = jiffies +
 | 
			
		||||
				msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (is_admin_up(master->dev))
 | 
			
		||||
		add_timer(&hsr->announce_timer);
 | 
			
		||||
| 
						 | 
				
			
			@ -428,7 +437,7 @@ static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
 | 
			
		||||
		     unsigned char multicast_spec)
 | 
			
		||||
		     unsigned char multicast_spec, u8 protocol_version)
 | 
			
		||||
{
 | 
			
		||||
	struct hsr_priv *hsr;
 | 
			
		||||
	struct hsr_port *port;
 | 
			
		||||
| 
						 | 
				
			
			@ -450,6 +459,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
 | 
			
		|||
	spin_lock_init(&hsr->seqnr_lock);
 | 
			
		||||
	/* Overflow soon to find bugs easier: */
 | 
			
		||||
	hsr->sequence_nr = HSR_SEQNR_START;
 | 
			
		||||
	hsr->sup_sequence_nr = HSR_SUP_SEQNR_START;
 | 
			
		||||
 | 
			
		||||
	init_timer(&hsr->announce_timer);
 | 
			
		||||
	hsr->announce_timer.function = hsr_announce;
 | 
			
		||||
| 
						 | 
				
			
			@ -462,6 +472,8 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
 | 
			
		|||
	ether_addr_copy(hsr->sup_multicast_addr, def_multicast_addr);
 | 
			
		||||
	hsr->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec;
 | 
			
		||||
 | 
			
		||||
	hsr->protVersion = protocol_version;
 | 
			
		||||
 | 
			
		||||
	/* FIXME: should I modify the value of these?
 | 
			
		||||
	 *
 | 
			
		||||
	 * - hsr_dev->flags - i.e.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@
 | 
			
		|||
 | 
			
		||||
void hsr_dev_setup(struct net_device *dev);
 | 
			
		||||
int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
 | 
			
		||||
		     unsigned char multicast_spec);
 | 
			
		||||
		     unsigned char multicast_spec, u8 protocol_version);
 | 
			
		||||
void hsr_check_carrier_and_operstate(struct hsr_priv *hsr);
 | 
			
		||||
bool is_hsr_master(struct net_device *dev);
 | 
			
		||||
int hsr_get_max_mtu(struct hsr_priv *hsr);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,21 +50,40 @@ struct hsr_frame_info {
 | 
			
		|||
 */
 | 
			
		||||
static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	struct hsr_ethhdr_sp *hdr;
 | 
			
		||||
	struct ethhdr *ethHdr;
 | 
			
		||||
	struct hsr_sup_tag *hsrSupTag;
 | 
			
		||||
	struct hsrv1_ethhdr_sp *hsrV1Hdr;
 | 
			
		||||
 | 
			
		||||
	WARN_ON_ONCE(!skb_mac_header_was_set(skb));
 | 
			
		||||
	hdr = (struct hsr_ethhdr_sp *) skb_mac_header(skb);
 | 
			
		||||
	ethHdr = (struct ethhdr *) skb_mac_header(skb);
 | 
			
		||||
 | 
			
		||||
	if (!ether_addr_equal(hdr->ethhdr.h_dest,
 | 
			
		||||
	/* Correct addr? */
 | 
			
		||||
	if (!ether_addr_equal(ethHdr->h_dest,
 | 
			
		||||
			      hsr->sup_multicast_addr))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	if (get_hsr_stag_path(&hdr->hsr_sup) != 0x0f)
 | 
			
		||||
	/* Correct ether type?. */
 | 
			
		||||
	if (!(ethHdr->h_proto == htons(ETH_P_PRP)
 | 
			
		||||
			|| ethHdr->h_proto == htons(ETH_P_HSR)))
 | 
			
		||||
		return false;
 | 
			
		||||
	if ((hdr->hsr_sup.HSR_TLV_Type != HSR_TLV_ANNOUNCE) &&
 | 
			
		||||
	    (hdr->hsr_sup.HSR_TLV_Type != HSR_TLV_LIFE_CHECK))
 | 
			
		||||
 | 
			
		||||
	/* Get the supervision header from correct location. */
 | 
			
		||||
	if (ethHdr->h_proto == htons(ETH_P_HSR)) { /* Okay HSRv1. */
 | 
			
		||||
		hsrV1Hdr = (struct hsrv1_ethhdr_sp *) skb_mac_header(skb);
 | 
			
		||||
		if (hsrV1Hdr->hsr.encap_proto != htons(ETH_P_PRP))
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		hsrSupTag = &hsrV1Hdr->hsr_sup;
 | 
			
		||||
	} else {
 | 
			
		||||
		hsrSupTag = &((struct hsrv0_ethhdr_sp *) skb_mac_header(skb))->hsr_sup;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((hsrSupTag->HSR_TLV_Type != HSR_TLV_ANNOUNCE) &&
 | 
			
		||||
	    (hsrSupTag->HSR_TLV_Type != HSR_TLV_LIFE_CHECK))
 | 
			
		||||
		return false;
 | 
			
		||||
	if (hdr->hsr_sup.HSR_TLV_Length != 12)
 | 
			
		||||
	if ((hsrSupTag->HSR_TLV_Length != 12) &&
 | 
			
		||||
			(hsrSupTag->HSR_TLV_Length !=
 | 
			
		||||
					sizeof(struct hsr_sup_payload)))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +129,7 @@ static struct sk_buff *frame_get_stripped_skb(struct hsr_frame_info *frame,
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
static void hsr_fill_tag(struct sk_buff *skb, struct hsr_frame_info *frame,
 | 
			
		||||
			 struct hsr_port *port)
 | 
			
		||||
			 struct hsr_port *port, u8 protoVersion)
 | 
			
		||||
{
 | 
			
		||||
	struct hsr_ethhdr *hsr_ethhdr;
 | 
			
		||||
	int lane_id;
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +150,8 @@ static void hsr_fill_tag(struct sk_buff *skb, struct hsr_frame_info *frame,
 | 
			
		|||
	set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, lsdu_size);
 | 
			
		||||
	hsr_ethhdr->hsr_tag.sequence_nr = htons(frame->sequence_nr);
 | 
			
		||||
	hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto;
 | 
			
		||||
	hsr_ethhdr->ethhdr.h_proto = htons(ETH_P_PRP);
 | 
			
		||||
	hsr_ethhdr->ethhdr.h_proto = htons(protoVersion ?
 | 
			
		||||
			ETH_P_HSR : ETH_P_PRP);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct sk_buff *create_tagged_skb(struct sk_buff *skb_o,
 | 
			
		||||
| 
						 | 
				
			
			@ -160,7 +180,7 @@ static struct sk_buff *create_tagged_skb(struct sk_buff *skb_o,
 | 
			
		|||
	memmove(dst, src, movelen);
 | 
			
		||||
	skb_reset_mac_header(skb);
 | 
			
		||||
 | 
			
		||||
	hsr_fill_tag(skb, frame, port);
 | 
			
		||||
	hsr_fill_tag(skb, frame, port, port->hsr->protVersion);
 | 
			
		||||
 | 
			
		||||
	return skb;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -320,7 +340,8 @@ static int hsr_fill_frame_info(struct hsr_frame_info *frame,
 | 
			
		|||
		/* FIXME: */
 | 
			
		||||
		WARN_ONCE(1, "HSR: VLAN not yet supported");
 | 
			
		||||
	}
 | 
			
		||||
	if (ethhdr->h_proto == htons(ETH_P_PRP)) {
 | 
			
		||||
	if (ethhdr->h_proto == htons(ETH_P_PRP)
 | 
			
		||||
			|| ethhdr->h_proto == htons(ETH_P_HSR)) {
 | 
			
		||||
		frame->skb_std = NULL;
 | 
			
		||||
		frame->skb_hsr = skb;
 | 
			
		||||
		frame->sequence_nr = hsr_get_skb_sequence_nr(skb);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -177,17 +177,17 @@ struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb,
 | 
			
		|||
			return node;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!is_sup)
 | 
			
		||||
		return NULL; /* Only supervision frame may create node entry */
 | 
			
		||||
	/* Everyone may create a node entry, connected node to a HSR device. */
 | 
			
		||||
 | 
			
		||||
	if (ethhdr->h_proto == htons(ETH_P_PRP)) {
 | 
			
		||||
	if (ethhdr->h_proto == htons(ETH_P_PRP)
 | 
			
		||||
			|| ethhdr->h_proto == htons(ETH_P_HSR)) {
 | 
			
		||||
		/* Use the existing sequence_nr from the tag as starting point
 | 
			
		||||
		 * for filtering duplicate frames.
 | 
			
		||||
		 */
 | 
			
		||||
		seq_out = hsr_get_skb_sequence_nr(skb) - 1;
 | 
			
		||||
	} else {
 | 
			
		||||
		WARN_ONCE(1, "%s: Non-HSR frame\n", __func__);
 | 
			
		||||
		seq_out = 0;
 | 
			
		||||
		seq_out = HSR_SEQNR_START;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return hsr_add_node(node_db, ethhdr->h_source, seq_out);
 | 
			
		||||
| 
						 | 
				
			
			@ -200,17 +200,25 @@ struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb,
 | 
			
		|||
void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr,
 | 
			
		||||
			  struct hsr_port *port_rcv)
 | 
			
		||||
{
 | 
			
		||||
	struct ethhdr *ethhdr;
 | 
			
		||||
	struct hsr_node *node_real;
 | 
			
		||||
	struct hsr_sup_payload *hsr_sp;
 | 
			
		||||
	struct list_head *node_db;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	skb_pull(skb, sizeof(struct hsr_ethhdr_sp));
 | 
			
		||||
	hsr_sp = (struct hsr_sup_payload *) skb->data;
 | 
			
		||||
	ethhdr = (struct ethhdr *) skb_mac_header(skb);
 | 
			
		||||
 | 
			
		||||
	if (ether_addr_equal(eth_hdr(skb)->h_source, hsr_sp->MacAddressA))
 | 
			
		||||
		/* Not sent from MacAddressB of a PICS_SUBS capable node */
 | 
			
		||||
		goto done;
 | 
			
		||||
	/* Leave the ethernet header. */
 | 
			
		||||
	skb_pull(skb, sizeof(struct ethhdr));
 | 
			
		||||
 | 
			
		||||
	/* And leave the HSR tag. */
 | 
			
		||||
	if (ethhdr->h_proto == htons(ETH_P_HSR))
 | 
			
		||||
		skb_pull(skb, sizeof(struct hsr_tag));
 | 
			
		||||
 | 
			
		||||
	/* And leave the HSR sup tag. */
 | 
			
		||||
	skb_pull(skb, sizeof(struct hsr_sup_tag));
 | 
			
		||||
 | 
			
		||||
	hsr_sp = (struct hsr_sup_payload *) skb->data;
 | 
			
		||||
 | 
			
		||||
	/* Merge node_curr (registered on MacAddressB) into node_real */
 | 
			
		||||
	node_db = &port_rcv->hsr->node_db;
 | 
			
		||||
| 
						 | 
				
			
			@ -225,7 +233,7 @@ void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr,
 | 
			
		|||
		/* Node has already been merged */
 | 
			
		||||
		goto done;
 | 
			
		||||
 | 
			
		||||
	ether_addr_copy(node_real->MacAddressB, eth_hdr(skb)->h_source);
 | 
			
		||||
	ether_addr_copy(node_real->MacAddressB, ethhdr->h_source);
 | 
			
		||||
	for (i = 0; i < HSR_PT_PORTS; i++) {
 | 
			
		||||
		if (!node_curr->time_in_stale[i] &&
 | 
			
		||||
		    time_after(node_curr->time_in[i], node_real->time_in[i])) {
 | 
			
		||||
| 
						 | 
				
			
			@ -241,7 +249,7 @@ void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr,
 | 
			
		|||
	kfree_rcu(node_curr, rcu_head);
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	skb_push(skb, sizeof(struct hsr_ethhdr_sp));
 | 
			
		||||
	skb_push(skb, sizeof(struct hsrv1_ethhdr_sp));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,7 @@
 | 
			
		|||
 */
 | 
			
		||||
#define MAX_SLAVE_DIFF			 3000 /* ms */
 | 
			
		||||
#define HSR_SEQNR_START			(USHRT_MAX - 1024)
 | 
			
		||||
#define HSR_SUP_SEQNR_START		(HSR_SEQNR_START / 2)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* How often shall we check for broken ring and remove node entries older than
 | 
			
		||||
| 
						 | 
				
			
			@ -58,6 +59,8 @@ struct hsr_tag {
 | 
			
		|||
 | 
			
		||||
#define HSR_HLEN	6
 | 
			
		||||
 | 
			
		||||
#define HSR_V1_SUP_LSDUSIZE		52
 | 
			
		||||
 | 
			
		||||
/* The helper functions below assumes that 'path' occupies the 4 most
 | 
			
		||||
 * significant bits of the 16-bit field shared by 'path' and 'LSDU_size' (or
 | 
			
		||||
 * equivalently, the 4 most significant bits of HSR tag byte 14).
 | 
			
		||||
| 
						 | 
				
			
			@ -131,11 +134,17 @@ static inline void set_hsr_stag_HSR_Ver(struct hsr_sup_tag *hst, u16 HSR_Ver)
 | 
			
		|||
	set_hsr_tag_LSDU_size((struct hsr_tag *) hst, HSR_Ver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct hsr_ethhdr_sp {
 | 
			
		||||
struct hsrv0_ethhdr_sp {
 | 
			
		||||
	struct ethhdr		ethhdr;
 | 
			
		||||
	struct hsr_sup_tag	hsr_sup;
 | 
			
		||||
} __packed;
 | 
			
		||||
 | 
			
		||||
struct hsrv1_ethhdr_sp {
 | 
			
		||||
	struct ethhdr		ethhdr;
 | 
			
		||||
	struct hsr_tag		hsr;
 | 
			
		||||
	struct hsr_sup_tag	hsr_sup;
 | 
			
		||||
} __packed;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
enum hsr_port_type {
 | 
			
		||||
	HSR_PT_NONE = 0,	/* Must be 0, used by framereg */
 | 
			
		||||
| 
						 | 
				
			
			@ -162,6 +171,8 @@ struct hsr_priv {
 | 
			
		|||
	struct timer_list	prune_timer;
 | 
			
		||||
	int announce_count;
 | 
			
		||||
	u16 sequence_nr;
 | 
			
		||||
	u16 sup_sequence_nr;			/* For HSRv1 separate seq_nr for supervision */
 | 
			
		||||
	u8 protVersion;					/* Indicate if HSRv0 or HSRv1. */
 | 
			
		||||
	spinlock_t seqnr_lock;			/* locking for sequence_nr */
 | 
			
		||||
	unsigned char		sup_multicast_addr[ETH_ALEN];
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ static const struct nla_policy hsr_policy[IFLA_HSR_MAX + 1] = {
 | 
			
		|||
	[IFLA_HSR_SLAVE1]		= { .type = NLA_U32 },
 | 
			
		||||
	[IFLA_HSR_SLAVE2]		= { .type = NLA_U32 },
 | 
			
		||||
	[IFLA_HSR_MULTICAST_SPEC]	= { .type = NLA_U8 },
 | 
			
		||||
	[IFLA_HSR_VERSION]	= { .type = NLA_U8 },
 | 
			
		||||
	[IFLA_HSR_SUPERVISION_ADDR]	= { .type = NLA_BINARY, .len = ETH_ALEN },
 | 
			
		||||
	[IFLA_HSR_SEQ_NR]		= { .type = NLA_U16 },
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +36,7 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev,
 | 
			
		|||
		       struct nlattr *tb[], struct nlattr *data[])
 | 
			
		||||
{
 | 
			
		||||
	struct net_device *link[2];
 | 
			
		||||
	unsigned char multicast_spec;
 | 
			
		||||
	unsigned char multicast_spec, hsr_version;
 | 
			
		||||
 | 
			
		||||
	if (!data) {
 | 
			
		||||
		netdev_info(dev, "HSR: No slave devices specified\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +63,12 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev,
 | 
			
		|||
	else
 | 
			
		||||
		multicast_spec = nla_get_u8(data[IFLA_HSR_MULTICAST_SPEC]);
 | 
			
		||||
 | 
			
		||||
	return hsr_dev_finalize(dev, link, multicast_spec);
 | 
			
		||||
	if (!data[IFLA_HSR_VERSION])
 | 
			
		||||
		hsr_version = 0;
 | 
			
		||||
	else
 | 
			
		||||
		hsr_version = nla_get_u8(data[IFLA_HSR_VERSION]);
 | 
			
		||||
 | 
			
		||||
	return hsr_dev_finalize(dev, link, multicast_spec, hsr_version);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,7 @@ static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb)
 | 
			
		|||
{
 | 
			
		||||
	struct sk_buff *skb = *pskb;
 | 
			
		||||
	struct hsr_port *port;
 | 
			
		||||
	u16 protocol;
 | 
			
		||||
 | 
			
		||||
	if (!skb_mac_header_was_set(skb)) {
 | 
			
		||||
		WARN_ONCE(1, "%s: skb invalid", __func__);
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +38,8 @@ static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb)
 | 
			
		|||
		goto finish_consume;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (eth_hdr(skb)->h_proto != htons(ETH_P_PRP))
 | 
			
		||||
	protocol = eth_hdr(skb)->h_proto;
 | 
			
		||||
	if (protocol != htons(ETH_P_PRP) && protocol != htons(ETH_P_HSR))
 | 
			
		||||
		goto finish_pass;
 | 
			
		||||
 | 
			
		||||
	skb_push(skb, ETH_HLEN);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue