|
|
@@ -248,13 +248,20 @@ static void send_supervision_frame(struct hsr_prp_port *master,
|
|
|
{
|
|
|
struct sk_buff *skb;
|
|
|
int hlen, tlen;
|
|
|
- struct hsr_tag *hsr_tag;
|
|
|
+ struct hsr_tag *hsr_tag = NULL;
|
|
|
+ struct prp_rct *rct;
|
|
|
struct hsr_prp_sup_tag *hsr_stag;
|
|
|
struct hsr_prp_sup_payload *hsr_sp;
|
|
|
unsigned long irqflags;
|
|
|
+ u16 proto;
|
|
|
+ u8 *tail;
|
|
|
|
|
|
hlen = LL_RESERVED_SPACE(master->dev);
|
|
|
tlen = master->dev->needed_tailroom;
|
|
|
+ /* skb size is same for PRP/HSR frames, only difference
|
|
|
+ * being for PRP, it is a trailor and for HSR it is a
|
|
|
+ * header
|
|
|
+ */
|
|
|
skb = dev_alloc_skb(sizeof(struct hsr_tag) +
|
|
|
sizeof(struct hsr_prp_sup_tag) +
|
|
|
sizeof(struct hsr_prp_sup_payload) + hlen + tlen);
|
|
|
@@ -263,18 +270,21 @@ static void send_supervision_frame(struct hsr_prp_port *master,
|
|
|
return;
|
|
|
|
|
|
skb_reserve(skb, hlen);
|
|
|
-
|
|
|
+ if (!proto_ver)
|
|
|
+ proto = ETH_P_PRP;
|
|
|
+ else
|
|
|
+ proto = (proto_ver == HSR_V1) ? ETH_P_HSR : ETH_P_PRP;
|
|
|
skb->dev = master->dev;
|
|
|
- skb->protocol = htons(proto_ver ? ETH_P_HSR : ETH_P_PRP);
|
|
|
+ skb->protocol = htons(proto);
|
|
|
skb->priority = TC_PRIO_CONTROL;
|
|
|
|
|
|
- if (dev_hard_header(skb, skb->dev, (proto_ver ? ETH_P_HSR : ETH_P_PRP),
|
|
|
+ if (dev_hard_header(skb, skb->dev, proto,
|
|
|
master->priv->sup_multicast_addr,
|
|
|
skb->dev->dev_addr, skb->len) <= 0)
|
|
|
goto out;
|
|
|
skb_reset_mac_header(skb);
|
|
|
|
|
|
- if (proto_ver > 0) {
|
|
|
+ if (proto_ver == HSR_V1) {
|
|
|
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);
|
|
|
@@ -282,15 +292,19 @@ static void send_supervision_frame(struct hsr_prp_port *master,
|
|
|
|
|
|
hsr_stag = skb_put(skb, sizeof(struct hsr_prp_sup_tag));
|
|
|
set_hsr_stag_path(hsr_stag, (proto_ver ? 0x0 : 0xf));
|
|
|
- set_hsr_stag_HSR_ver(hsr_stag, proto_ver);
|
|
|
+ set_hsr_stag_HSR_ver(hsr_stag, proto_ver ? 0x1 : 0x0);
|
|
|
|
|
|
/* From HSRv1 on we have separate supervision sequence numbers. */
|
|
|
spin_lock_irqsave(&master->priv->seqnr_lock, irqflags);
|
|
|
if (proto_ver > 0) {
|
|
|
hsr_stag->sequence_nr = htons(master->priv->sup_sequence_nr);
|
|
|
- hsr_tag->sequence_nr = htons(master->priv->sequence_nr);
|
|
|
+ if (hsr_tag)
|
|
|
+ hsr_tag->sequence_nr = htons(master->priv->sequence_nr);
|
|
|
master->priv->sup_sequence_nr++;
|
|
|
- master->priv->sequence_nr++;
|
|
|
+ if (proto_ver == HSR_V1) {
|
|
|
+ hsr_tag->sequence_nr = htons(master->priv->sequence_nr);
|
|
|
+ master->priv->sequence_nr++;
|
|
|
+ }
|
|
|
} else {
|
|
|
hsr_stag->sequence_nr = htons(master->priv->sequence_nr);
|
|
|
master->priv->sequence_nr++;
|
|
|
@@ -309,6 +323,16 @@ static void send_supervision_frame(struct hsr_prp_port *master,
|
|
|
if (skb_put_padto(skb, ETH_ZLEN + HSR_PRP_HLEN))
|
|
|
return;
|
|
|
|
|
|
+ spin_lock_irqsave(&master->priv->seqnr_lock, irqflags);
|
|
|
+ if (proto_ver == PRP_V1) {
|
|
|
+ tail = skb_tail_pointer(skb) - HSR_PRP_HLEN;
|
|
|
+ rct = (struct prp_rct *)tail;
|
|
|
+ rct->PRP_suffix = htons(ETH_P_PRP);
|
|
|
+ set_prp_LSDU_size(rct, HSR_V1_SUP_LSDUSIZE);
|
|
|
+ rct->sequence_nr = htons(master->priv->sequence_nr);
|
|
|
+ master->priv->sequence_nr++;
|
|
|
+ }
|
|
|
+ spin_unlock_irqrestore(&master->priv->seqnr_lock, irqflags);
|
|
|
hsr_prp_forward_skb(skb, master);
|
|
|
return;
|
|
|
|
|
|
@@ -337,8 +361,12 @@ static void hsr_prp_announce(struct timer_list *t)
|
|
|
|
|
|
interval = msecs_to_jiffies(HSR_PRP_ANNOUNCE_INTERVAL);
|
|
|
} else {
|
|
|
- send_supervision_frame(master, HSR_TLV_LIFE_CHECK,
|
|
|
- priv->prot_version);
|
|
|
+ if (priv->prot_version <= HSR_V1)
|
|
|
+ send_supervision_frame(master, HSR_TLV_LIFE_CHECK,
|
|
|
+ priv->prot_version);
|
|
|
+ else /* PRP */
|
|
|
+ send_supervision_frame(master, PRP_TLV_LIFE_CHECK_DD,
|
|
|
+ priv->prot_version);
|
|
|
|
|
|
interval = msecs_to_jiffies(HSR_PRP_LIFE_CHECK_INTERVAL);
|
|
|
}
|