Commit eafaa88b authored by Andreas Oetken's avatar Andreas Oetken Committed by David S. Miller

net: hsr: Add support for redbox supervision frames

added support for the redbox supervision frames
as defined in the IEC-62439-3:2018.
Signed-off-by: default avatarAndreas Oetken <andreas.oetken@siemens-energy.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3247e3ff
...@@ -309,9 +309,9 @@ static void send_hsr_supervision_frame(struct hsr_port *master, ...@@ -309,9 +309,9 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
} }
spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags); spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags);
hsr_stag->HSR_TLV_type = type; hsr_stag->tlv.HSR_TLV_type = type;
/* TODO: Why 12 in HSRv0? */ /* TODO: Why 12 in HSRv0? */
hsr_stag->HSR_TLV_length = hsr->prot_version ? hsr_stag->tlv.HSR_TLV_length = hsr->prot_version ?
sizeof(struct hsr_sup_payload) : 12; sizeof(struct hsr_sup_payload) : 12;
/* Payload: MacAddressA */ /* Payload: MacAddressA */
...@@ -350,8 +350,8 @@ static void send_prp_supervision_frame(struct hsr_port *master, ...@@ -350,8 +350,8 @@ static void send_prp_supervision_frame(struct hsr_port *master,
spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags); spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags);
hsr_stag->sequence_nr = htons(hsr->sup_sequence_nr); hsr_stag->sequence_nr = htons(hsr->sup_sequence_nr);
hsr->sup_sequence_nr++; hsr->sup_sequence_nr++;
hsr_stag->HSR_TLV_type = PRP_TLV_LIFE_CHECK_DD; hsr_stag->tlv.HSR_TLV_type = PRP_TLV_LIFE_CHECK_DD;
hsr_stag->HSR_TLV_length = sizeof(struct hsr_sup_payload); hsr_stag->tlv.HSR_TLV_length = sizeof(struct hsr_sup_payload);
/* Payload: MacAddressA */ /* Payload: MacAddressA */
hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload)); hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
......
...@@ -37,6 +37,8 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) ...@@ -37,6 +37,8 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb)
struct ethhdr *eth_hdr; struct ethhdr *eth_hdr;
struct hsr_sup_tag *hsr_sup_tag; struct hsr_sup_tag *hsr_sup_tag;
struct hsrv1_ethhdr_sp *hsr_V1_hdr; struct hsrv1_ethhdr_sp *hsr_V1_hdr;
struct hsr_sup_tlv *hsr_sup_tlv;
u16 total_length = 0;
WARN_ON_ONCE(!skb_mac_header_was_set(skb)); WARN_ON_ONCE(!skb_mac_header_was_set(skb));
eth_hdr = (struct ethhdr *)skb_mac_header(skb); eth_hdr = (struct ethhdr *)skb_mac_header(skb);
...@@ -53,23 +55,63 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb) ...@@ -53,23 +55,63 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb)
/* Get the supervision header from correct location. */ /* Get the supervision header from correct location. */
if (eth_hdr->h_proto == htons(ETH_P_HSR)) { /* Okay HSRv1. */ if (eth_hdr->h_proto == htons(ETH_P_HSR)) { /* Okay HSRv1. */
total_length = sizeof(struct hsrv1_ethhdr_sp);
if (!pskb_may_pull(skb, total_length))
return false;
hsr_V1_hdr = (struct hsrv1_ethhdr_sp *)skb_mac_header(skb); hsr_V1_hdr = (struct hsrv1_ethhdr_sp *)skb_mac_header(skb);
if (hsr_V1_hdr->hsr.encap_proto != htons(ETH_P_PRP)) if (hsr_V1_hdr->hsr.encap_proto != htons(ETH_P_PRP))
return false; return false;
hsr_sup_tag = &hsr_V1_hdr->hsr_sup; hsr_sup_tag = &hsr_V1_hdr->hsr_sup;
} else { } else {
total_length = sizeof(struct hsrv0_ethhdr_sp);
if (!pskb_may_pull(skb, total_length))
return false;
hsr_sup_tag = hsr_sup_tag =
&((struct hsrv0_ethhdr_sp *)skb_mac_header(skb))->hsr_sup; &((struct hsrv0_ethhdr_sp *)skb_mac_header(skb))->hsr_sup;
} }
if (hsr_sup_tag->HSR_TLV_type != HSR_TLV_ANNOUNCE && if (hsr_sup_tag->tlv.HSR_TLV_type != HSR_TLV_ANNOUNCE &&
hsr_sup_tag->HSR_TLV_type != HSR_TLV_LIFE_CHECK && hsr_sup_tag->tlv.HSR_TLV_type != HSR_TLV_LIFE_CHECK &&
hsr_sup_tag->HSR_TLV_type != PRP_TLV_LIFE_CHECK_DD && hsr_sup_tag->tlv.HSR_TLV_type != PRP_TLV_LIFE_CHECK_DD &&
hsr_sup_tag->HSR_TLV_type != PRP_TLV_LIFE_CHECK_DA) hsr_sup_tag->tlv.HSR_TLV_type != PRP_TLV_LIFE_CHECK_DA)
return false; return false;
if (hsr_sup_tag->HSR_TLV_length != 12 && if (hsr_sup_tag->tlv.HSR_TLV_length != 12 &&
hsr_sup_tag->HSR_TLV_length != sizeof(struct hsr_sup_payload)) hsr_sup_tag->tlv.HSR_TLV_length != sizeof(struct hsr_sup_payload))
return false;
/* Get next tlv */
total_length += sizeof(struct hsr_sup_tlv) + hsr_sup_tag->tlv.HSR_TLV_length;
if (!pskb_may_pull(skb, total_length))
return false;
skb_pull(skb, total_length);
hsr_sup_tlv = (struct hsr_sup_tlv *)skb->data;
skb_push(skb, total_length);
/* if this is a redbox supervision frame we need to verify
* that more data is available
*/
if (hsr_sup_tlv->HSR_TLV_type == PRP_TLV_REDBOX_MAC) {
/* tlv length must be a length of a mac address */
if (hsr_sup_tlv->HSR_TLV_length != sizeof(struct hsr_sup_payload))
return false;
/* make sure another tlv follows */
total_length += sizeof(struct hsr_sup_tlv) + hsr_sup_tlv->HSR_TLV_length;
if (!pskb_may_pull(skb, total_length))
return false;
/* get next tlv */
skb_pull(skb, total_length);
hsr_sup_tlv = (struct hsr_sup_tlv *)skb->data;
skb_push(skb, total_length);
}
/* end of tlvs must follow at the end */
if (hsr_sup_tlv->HSR_TLV_type == HSR_TLV_EOT &&
hsr_sup_tlv->HSR_TLV_length != 0)
return false; return false;
return true; return true;
......
...@@ -265,11 +265,14 @@ void hsr_handle_sup_frame(struct hsr_frame_info *frame) ...@@ -265,11 +265,14 @@ void hsr_handle_sup_frame(struct hsr_frame_info *frame)
struct hsr_port *port_rcv = frame->port_rcv; struct hsr_port *port_rcv = frame->port_rcv;
struct hsr_priv *hsr = port_rcv->hsr; struct hsr_priv *hsr = port_rcv->hsr;
struct hsr_sup_payload *hsr_sp; struct hsr_sup_payload *hsr_sp;
struct hsr_sup_tlv *hsr_sup_tlv;
struct hsr_node *node_real; struct hsr_node *node_real;
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
struct list_head *node_db; struct list_head *node_db;
struct ethhdr *ethhdr; struct ethhdr *ethhdr;
int i; int i;
unsigned int pull_size = 0;
unsigned int total_pull_size = 0;
/* Here either frame->skb_hsr or frame->skb_prp should be /* Here either frame->skb_hsr or frame->skb_prp should be
* valid as supervision frame always will have protocol * valid as supervision frame always will have protocol
...@@ -284,18 +287,26 @@ void hsr_handle_sup_frame(struct hsr_frame_info *frame) ...@@ -284,18 +287,26 @@ void hsr_handle_sup_frame(struct hsr_frame_info *frame)
if (!skb) if (!skb)
return; return;
ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* Leave the ethernet header. */ /* Leave the ethernet header. */
skb_pull(skb, sizeof(struct ethhdr)); pull_size = sizeof(struct ethhdr);
skb_pull(skb, pull_size);
total_pull_size += pull_size;
ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* And leave the HSR tag. */ /* And leave the HSR tag. */
if (ethhdr->h_proto == htons(ETH_P_HSR)) if (ethhdr->h_proto == htons(ETH_P_HSR)) {
skb_pull(skb, sizeof(struct hsr_tag)); pull_size = sizeof(struct ethhdr);
skb_pull(skb, pull_size);
total_pull_size += pull_size;
}
/* And leave the HSR sup tag. */ /* And leave the HSR sup tag. */
skb_pull(skb, sizeof(struct hsr_sup_tag)); pull_size = sizeof(struct hsr_tag);
skb_pull(skb, pull_size);
total_pull_size += pull_size;
/* get HSR sup payload */
hsr_sp = (struct hsr_sup_payload *)skb->data; hsr_sp = (struct hsr_sup_payload *)skb->data;
/* Merge node_curr (registered on macaddress_B) into node_real */ /* Merge node_curr (registered on macaddress_B) into node_real */
...@@ -312,6 +323,37 @@ void hsr_handle_sup_frame(struct hsr_frame_info *frame) ...@@ -312,6 +323,37 @@ void hsr_handle_sup_frame(struct hsr_frame_info *frame)
/* Node has already been merged */ /* Node has already been merged */
goto done; goto done;
/* Leave the first HSR sup payload. */
pull_size = sizeof(struct hsr_sup_payload);
skb_pull(skb, pull_size);
total_pull_size += pull_size;
/* Get second supervision tlv */
hsr_sup_tlv = (struct hsr_sup_tlv *)skb->data;
/* And check if it is a redbox mac TLV */
if (hsr_sup_tlv->HSR_TLV_type == PRP_TLV_REDBOX_MAC) {
/* We could stop here after pushing hsr_sup_payload,
* or proceed and allow macaddress_B and for redboxes.
*/
/* Sanity check length */
if (hsr_sup_tlv->HSR_TLV_length != 6)
goto done;
/* Leave the second HSR sup tlv. */
pull_size = sizeof(struct hsr_sup_tlv);
skb_pull(skb, pull_size);
total_pull_size += pull_size;
/* Get redbox mac address. */
hsr_sp = (struct hsr_sup_payload *)skb->data;
/* Check if redbox mac and node mac are equal. */
if (!ether_addr_equal(node_real->macaddress_A, hsr_sp->macaddress_A)) {
/* This is a redbox supervision frame for a VDAN! */
goto done;
}
}
ether_addr_copy(node_real->macaddress_B, ethhdr->h_source); ether_addr_copy(node_real->macaddress_B, ethhdr->h_source);
for (i = 0; i < HSR_PT_PORTS; i++) { for (i = 0; i < HSR_PT_PORTS; i++) {
if (!node_curr->time_in_stale[i] && if (!node_curr->time_in_stale[i] &&
...@@ -331,11 +373,8 @@ void hsr_handle_sup_frame(struct hsr_frame_info *frame) ...@@ -331,11 +373,8 @@ void hsr_handle_sup_frame(struct hsr_frame_info *frame)
kfree_rcu(node_curr, rcu_head); kfree_rcu(node_curr, rcu_head);
done: done:
/* PRP uses v0 header */ /* Push back here */
if (ethhdr->h_proto == htons(ETH_P_HSR)) skb_push(skb, total_pull_size);
skb_push(skb, sizeof(struct hsrv1_ethhdr_sp));
else
skb_push(skb, sizeof(struct hsrv0_ethhdr_sp));
} }
/* 'skb' is a frame meant for this host, that is to be passed to upper layers. /* 'skb' is a frame meant for this host, that is to be passed to upper layers.
......
...@@ -35,13 +35,15 @@ ...@@ -35,13 +35,15 @@
* HSR_NODE_FORGET_TIME? * HSR_NODE_FORGET_TIME?
*/ */
#define PRUNE_PERIOD 3000 /* ms */ #define PRUNE_PERIOD 3000 /* ms */
#define HSR_TLV_EOT 0 /* End of TLVs */
#define HSR_TLV_ANNOUNCE 22 #define HSR_TLV_ANNOUNCE 22
#define HSR_TLV_LIFE_CHECK 23 #define HSR_TLV_LIFE_CHECK 23
/* PRP V1 life check for Duplicate discard */ /* PRP V1 life check for Duplicate discard */
#define PRP_TLV_LIFE_CHECK_DD 20 #define PRP_TLV_LIFE_CHECK_DD 20
/* PRP V1 life check for Duplicate Accept */ /* PRP V1 life check for Duplicate Accept */
#define PRP_TLV_LIFE_CHECK_DA 21 #define PRP_TLV_LIFE_CHECK_DA 21
/* PRP V1 life redundancy box MAC address */
#define PRP_TLV_REDBOX_MAC 30
/* HSR Tag. /* HSR Tag.
* As defined in IEC-62439-3:2010, the HSR tag is really { ethertype = 0x88FB, * As defined in IEC-62439-3:2010, the HSR tag is really { ethertype = 0x88FB,
...@@ -94,14 +96,18 @@ struct hsr_vlan_ethhdr { ...@@ -94,14 +96,18 @@ struct hsr_vlan_ethhdr {
struct hsr_tag hsr_tag; struct hsr_tag hsr_tag;
} __packed; } __packed;
struct hsr_sup_tlv {
u8 HSR_TLV_type;
u8 HSR_TLV_length;
};
/* HSR/PRP Supervision Frame data types. /* HSR/PRP Supervision Frame data types.
* Field names as defined in the IEC:2010 standard for HSR. * Field names as defined in the IEC:2010 standard for HSR.
*/ */
struct hsr_sup_tag { struct hsr_sup_tag {
__be16 path_and_HSR_ver; __be16 path_and_HSR_ver;
__be16 sequence_nr; __be16 sequence_nr;
__u8 HSR_TLV_type; struct hsr_sup_tlv tlv;
__u8 HSR_TLV_length;
} __packed; } __packed;
struct hsr_sup_payload { struct hsr_sup_payload {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment