Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: prp: add supervision frame generation utility function

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>

authored by

Murali Karicheri and committed by
David S. Miller
c643ff03 28e458e0

+88 -2
+63 -1
net/hsr/hsr_device.c
··· 238 238 239 239 hlen = LL_RESERVED_SPACE(master->dev); 240 240 tlen = master->dev->needed_tailroom; 241 + /* skb size is same for PRP/HSR frames, only difference 242 + * being, for PRP it is a trailer and for HSR it is a 243 + * header 244 + */ 241 245 skb = dev_alloc_skb(sizeof(struct hsr_tag) + 242 246 sizeof(struct hsr_sup_tag) + 243 247 sizeof(struct hsr_sup_payload) + hlen + tlen); ··· 340 336 return; 341 337 } 342 338 339 + static void send_prp_supervision_frame(struct hsr_port *master, 340 + unsigned long *interval) 341 + { 342 + struct hsr_priv *hsr = master->hsr; 343 + struct hsr_sup_payload *hsr_sp; 344 + struct hsr_sup_tag *hsr_stag; 345 + unsigned long irqflags; 346 + struct sk_buff *skb; 347 + struct prp_rct *rct; 348 + u8 *tail; 349 + 350 + skb = hsr_init_skb(master, ETH_P_PRP); 351 + if (!skb) { 352 + WARN_ONCE(1, "PRP: Could not send supervision frame\n"); 353 + return; 354 + } 355 + 356 + *interval = msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL); 357 + hsr_stag = skb_put(skb, sizeof(struct hsr_sup_tag)); 358 + set_hsr_stag_path(hsr_stag, (hsr->prot_version ? 0x0 : 0xf)); 359 + set_hsr_stag_HSR_ver(hsr_stag, (hsr->prot_version ? 1 : 0)); 360 + 361 + /* From HSRv1 on we have separate supervision sequence numbers. */ 362 + spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags); 363 + hsr_stag->sequence_nr = htons(hsr->sup_sequence_nr); 364 + hsr->sup_sequence_nr++; 365 + hsr_stag->HSR_TLV_type = PRP_TLV_LIFE_CHECK_DD; 366 + hsr_stag->HSR_TLV_length = sizeof(struct hsr_sup_payload); 367 + 368 + /* Payload: MacAddressA */ 369 + hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload)); 370 + ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr); 371 + 372 + if (skb_put_padto(skb, ETH_ZLEN + HSR_HLEN)) { 373 + spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags); 374 + return; 375 + } 376 + 377 + tail = skb_tail_pointer(skb) - HSR_HLEN; 378 + rct = (struct prp_rct *)tail; 379 + rct->PRP_suffix = htons(ETH_P_PRP); 380 + set_prp_LSDU_size(rct, HSR_V1_SUP_LSDUSIZE); 381 + rct->sequence_nr = htons(hsr->sequence_nr); 382 + hsr->sequence_nr++; 383 + spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags); 384 + 385 + hsr_forward_skb(skb, master); 386 + } 387 + 343 388 /* Announce (supervision frame) timer function 344 389 */ 345 390 static void hsr_announce(struct timer_list *t) ··· 440 387 441 388 static struct hsr_proto_ops hsr_ops = { 442 389 .send_sv_frame = send_hsr_supervision_frame, 390 + }; 391 + 392 + struct hsr_proto_ops prp_ops = { 393 + .send_sv_frame = send_prp_supervision_frame, 443 394 }; 444 395 445 396 void hsr_dev_setup(struct net_device *dev) ··· 509 452 if (protocol_version == PRP_V1) 510 453 return -EPROTONOSUPPORT; 511 454 512 - hsr->proto_ops = &hsr_ops; 455 + /* initialize protocol specific functions */ 456 + if (protocol_version == PRP_V1) 457 + hsr->proto_ops = &prp_ops; 458 + else 459 + hsr->proto_ops = &hsr_ops; 460 + 513 461 /* Make sure we recognize frames from ourselves in hsr_rcv() */ 514 462 res = hsr_create_self_node(hsr, hsr_dev->dev_addr, 515 463 slave[1]->dev_addr);
+3 -1
net/hsr/hsr_forward.c
··· 76 76 } 77 77 78 78 if (hsr_sup_tag->HSR_TLV_type != HSR_TLV_ANNOUNCE && 79 - hsr_sup_tag->HSR_TLV_type != HSR_TLV_LIFE_CHECK) 79 + hsr_sup_tag->HSR_TLV_type != HSR_TLV_LIFE_CHECK && 80 + hsr_sup_tag->HSR_TLV_type != PRP_TLV_LIFE_CHECK_DD && 81 + hsr_sup_tag->HSR_TLV_type != PRP_TLV_LIFE_CHECK_DA) 80 82 return false; 81 83 if (hsr_sup_tag->HSR_TLV_length != 12 && 82 84 hsr_sup_tag->HSR_TLV_length != sizeof(struct hsr_sup_payload))
+22
net/hsr/hsr_main.h
··· 35 35 36 36 #define HSR_TLV_ANNOUNCE 22 37 37 #define HSR_TLV_LIFE_CHECK 23 38 + /* PRP V1 life check for Duplicate discard */ 39 + #define PRP_TLV_LIFE_CHECK_DD 20 40 + /* PRP V1 life check for Duplicate Accept */ 41 + #define PRP_TLV_LIFE_CHECK_DA 21 38 42 39 43 /* HSR Tag. 40 44 * As defined in IEC-62439-3:2010, the HSR tag is really { ethertype = 0x88FB, ··· 129 125 HSR_PT_MASTER, 130 126 HSR_PT_PORTS, /* This must be the last item in the enum */ 131 127 }; 128 + 129 + /* PRP Redunancy Control Trailor (RCT). 130 + * As defined in IEC-62439-4:2012, the PRP RCT is really { sequence Nr, 131 + * Lan indentifier (LanId), LSDU_size and PRP_suffix = 0x88FB }. 132 + * 133 + * Field names as defined in the IEC:2012 standard for PRP. 134 + */ 135 + struct prp_rct { 136 + __be16 sequence_nr; 137 + __be16 lan_id_and_LSDU_size; 138 + __be16 PRP_suffix; 139 + } __packed; 140 + 141 + static inline void set_prp_LSDU_size(struct prp_rct *rct, u16 LSDU_size) 142 + { 143 + rct->lan_id_and_LSDU_size = htons((ntohs(rct->lan_id_and_LSDU_size) & 144 + 0xF000) | (LSDU_size & 0x0FFF)); 145 + } 132 146 133 147 struct hsr_port { 134 148 struct list_head port_list;