Skip to content

Commit

Permalink
net: prp: add supervision frame generation utility function
Browse files Browse the repository at this point in the history
Add support for generation of PRP supervision frames. For PRP,
supervision frame format is similar to HSR version 0, but have
a PRP Redundancy Control Trailer (RCT) added and uses a different
message type, PRP_TLV_LIFE_CHECK_DD. Also update
is_supervision_frame() to include the new message type used for
PRP supervision frame.

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Murali Karicheri authored and David S. Miller committed Jul 27, 2020
1 parent 28e458e commit c643ff0
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 2 deletions.
64 changes: 63 additions & 1 deletion net/hsr/hsr_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ static struct sk_buff *hsr_init_skb(struct hsr_port *master, u16 proto)

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 trailer and for HSR it is a
* header
*/
skb = dev_alloc_skb(sizeof(struct hsr_tag) +
sizeof(struct hsr_sup_tag) +
sizeof(struct hsr_sup_payload) + hlen + tlen);
Expand Down Expand Up @@ -336,6 +340,55 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
return;
}

static void send_prp_supervision_frame(struct hsr_port *master,
unsigned long *interval)
{
struct hsr_priv *hsr = master->hsr;
struct hsr_sup_payload *hsr_sp;
struct hsr_sup_tag *hsr_stag;
unsigned long irqflags;
struct sk_buff *skb;
struct prp_rct *rct;
u8 *tail;

skb = hsr_init_skb(master, ETH_P_PRP);
if (!skb) {
WARN_ONCE(1, "PRP: Could not send supervision frame\n");
return;
}

*interval = msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL);
hsr_stag = skb_put(skb, sizeof(struct hsr_sup_tag));
set_hsr_stag_path(hsr_stag, (hsr->prot_version ? 0x0 : 0xf));
set_hsr_stag_HSR_ver(hsr_stag, (hsr->prot_version ? 1 : 0));

/* From HSRv1 on we have separate supervision sequence numbers. */
spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags);
hsr_stag->sequence_nr = htons(hsr->sup_sequence_nr);
hsr->sup_sequence_nr++;
hsr_stag->HSR_TLV_type = PRP_TLV_LIFE_CHECK_DD;
hsr_stag->HSR_TLV_length = sizeof(struct hsr_sup_payload);

/* Payload: MacAddressA */
hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr);

if (skb_put_padto(skb, ETH_ZLEN + HSR_HLEN)) {
spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags);
return;
}

tail = skb_tail_pointer(skb) - HSR_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(hsr->sequence_nr);
hsr->sequence_nr++;
spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags);

hsr_forward_skb(skb, master);
}

/* Announce (supervision frame) timer function
*/
static void hsr_announce(struct timer_list *t)
Expand Down Expand Up @@ -389,6 +442,10 @@ static struct hsr_proto_ops hsr_ops = {
.send_sv_frame = send_hsr_supervision_frame,
};

struct hsr_proto_ops prp_ops = {
.send_sv_frame = send_prp_supervision_frame,
};

void hsr_dev_setup(struct net_device *dev)
{
eth_hw_addr_random(dev);
Expand Down Expand Up @@ -452,7 +509,12 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
if (protocol_version == PRP_V1)
return -EPROTONOSUPPORT;

hsr->proto_ops = &hsr_ops;
/* initialize protocol specific functions */
if (protocol_version == PRP_V1)
hsr->proto_ops = &prp_ops;
else
hsr->proto_ops = &hsr_ops;

/* Make sure we recognize frames from ourselves in hsr_rcv() */
res = hsr_create_self_node(hsr, hsr_dev->dev_addr,
slave[1]->dev_addr);
Expand Down
4 changes: 3 additions & 1 deletion net/hsr/hsr_forward.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb)
}

if (hsr_sup_tag->HSR_TLV_type != HSR_TLV_ANNOUNCE &&
hsr_sup_tag->HSR_TLV_type != HSR_TLV_LIFE_CHECK)
hsr_sup_tag->HSR_TLV_type != HSR_TLV_LIFE_CHECK &&
hsr_sup_tag->HSR_TLV_type != PRP_TLV_LIFE_CHECK_DD &&
hsr_sup_tag->HSR_TLV_type != PRP_TLV_LIFE_CHECK_DA)
return false;
if (hsr_sup_tag->HSR_TLV_length != 12 &&
hsr_sup_tag->HSR_TLV_length != sizeof(struct hsr_sup_payload))
Expand Down
22 changes: 22 additions & 0 deletions net/hsr/hsr_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@

#define HSR_TLV_ANNOUNCE 22
#define HSR_TLV_LIFE_CHECK 23
/* PRP V1 life check for Duplicate discard */
#define PRP_TLV_LIFE_CHECK_DD 20
/* PRP V1 life check for Duplicate Accept */
#define PRP_TLV_LIFE_CHECK_DA 21

/* HSR Tag.
* As defined in IEC-62439-3:2010, the HSR tag is really { ethertype = 0x88FB,
Expand Down Expand Up @@ -126,6 +130,24 @@ enum hsr_port_type {
HSR_PT_PORTS, /* This must be the last item in the enum */
};

/* PRP Redunancy Control Trailor (RCT).
* As defined in IEC-62439-4:2012, the PRP RCT is really { sequence Nr,
* Lan indentifier (LanId), LSDU_size and PRP_suffix = 0x88FB }.
*
* Field names as defined in the IEC:2012 standard for PRP.
*/
struct prp_rct {
__be16 sequence_nr;
__be16 lan_id_and_LSDU_size;
__be16 PRP_suffix;
} __packed;

static inline void set_prp_LSDU_size(struct prp_rct *rct, u16 LSDU_size)
{
rct->lan_id_and_LSDU_size = htons((ntohs(rct->lan_id_and_LSDU_size) &
0xF000) | (LSDU_size & 0x0FFF));
}

struct hsr_port {
struct list_head port_list;
struct net_device *dev;
Expand Down

0 comments on commit c643ff0

Please sign in to comment.