From: Haoze Xie PRP slave ports accept ordinary SAN traffic and forward it to the master device without needing a persistent node entry. Creating one node per previously unseen SAN source lets arbitrary source MAC floods grow node_db until the prune timer catches up. Keep the receive path for ordinary PRP SAN traffic, but stop learning a new node when the frame is untagged and does not carry a PRP trailer. Continue to deliver the frame locally and only keep node state for actual HSR/PRP senders or nodes that have already been learned. Fixes: 451d8123f897 ("net: prp: add packet handling support") Reported-by: Yifan Wu Reported-by: Juefei Pu Co-developed-by: Yuan Tan Signed-off-by: Yuan Tan Suggested-by: Xin Liu Tested-by: Yuqi Xu Signed-off-by: Haoze Xie Signed-off-by: Ao Zhou --- net/hsr/hsr_forward.c | 14 ++++++++++---- net/hsr/hsr_framereg.c | 16 +++++++++++++--- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c index aefc9b6936ba..5fbfc42997d2 100644 --- a/net/hsr/hsr_forward.c +++ b/net/hsr/hsr_forward.c @@ -403,7 +403,8 @@ static void hsr_deliver_master(struct sk_buff *skb, struct net_device *dev, int res, recv_len; was_multicast_frame = (skb->pkt_type == PACKET_MULTICAST); - hsr_addr_subst_source(node_src, skb); + if (node_src) + hsr_addr_subst_source(node_src, skb); skb_pull(skb, ETH_HLEN); recv_len = skb->len; res = netif_rx(skb); @@ -699,8 +700,12 @@ static int fill_frame_info(struct hsr_frame_info *frame, frame->node_src = hsr_get_node(port, n_db, skb, frame->is_supervision, port->type); - if (!frame->node_src) - return -1; /* Unknown node and !is_supervision, or no mem */ + if (IS_ERR(frame->node_src)) { + ret = PTR_ERR(frame->node_src); + if (ret != -ENOENT) + return ret; + frame->node_src = NULL; + } ethhdr = (struct ethhdr *)skb_mac_header(skb); frame->is_vlan = false; @@ -739,7 +744,8 @@ void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port) if (fill_frame_info(&frame, skb, port) < 0) goto out_drop; - hsr_register_frame_in(frame.node_src, port, frame.sequence_nr); + if (frame.node_src) + hsr_register_frame_in(frame.node_src, port, frame.sequence_nr); hsr_forward_do(&frame); rcu_read_unlock(); /* Gets called for ingress frames as well as egress from master port. diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index 50996f4de7f9..13e1a0484879 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c @@ -230,7 +230,7 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db, bool san = false; if (!skb_mac_header_was_set(skb)) - return NULL; + return ERR_PTR(-EINVAL); ethhdr = (struct ethhdr *)skb_mac_header(skb); @@ -263,14 +263,24 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db, ethhdr->h_proto == htons(ETH_P_HSR)) { /* Check if skb contains hsr_ethhdr */ if (skb->mac_len < sizeof(struct hsr_ethhdr)) - return NULL; + return ERR_PTR(-EINVAL); } else { rct = skb_get_PRP_rct(skb); if (!rct && rx_port != HSR_PT_MASTER) san = true; } - return hsr_add_node(hsr, node_db, ethhdr->h_source, san, rx_port); + /* PRP accepts ordinary SAN traffic on slave ports without learning a + * persistent node entry. + */ + if (hsr->prot_version == PRP_V1 && san) + return ERR_PTR(-ENOENT); + + node = hsr_add_node(hsr, node_db, ethhdr->h_source, san, rx_port); + if (!node) + return ERR_PTR(-ENOMEM); + + return node; } static bool hsr_seq_block_is_old(struct hsr_seq_block *block) -- 2.53.0