net: hsr: fix mac_len checks
authorGeorge McCollister <george.mccollister@gmail.com>
Mon, 24 May 2021 18:50:54 +0000 (13:50 -0500)
committerDavid S. Miller <davem@davemloft.net>
Mon, 24 May 2021 21:10:28 +0000 (14:10 -0700)
Commit 2e9f60932a2c ("net: hsr: check skb can contain struct hsr_ethhdr
in fill_frame_info") added the following which resulted in -EINVAL
always being returned:
if (skb->mac_len < sizeof(struct hsr_ethhdr))
return -EINVAL;

mac_len was not being set correctly so this check completely broke
HSR/PRP since it was always 14, not 20.

Set mac_len correctly and modify the mac_len checks to test in the
correct places since sometimes it is legitimately 14.

Fixes: 2e9f60932a2c ("net: hsr: check skb can contain struct hsr_ethhdr in fill_frame_info")
Signed-off-by: George McCollister <george.mccollister@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/hsr/hsr_device.c
net/hsr/hsr_forward.c
net/hsr/hsr_forward.h
net/hsr/hsr_main.h
net/hsr/hsr_slave.c

index bfcdc75..26c3240 100644 (file)
@@ -218,6 +218,7 @@ static netdev_tx_t hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        if (master) {
                skb->dev = master->dev;
                skb_reset_mac_header(skb);
+               skb_reset_mac_len(skb);
                hsr_forward_skb(skb, master);
        } else {
                atomic_long_inc(&dev->tx_dropped);
@@ -259,6 +260,7 @@ static struct sk_buff *hsr_init_skb(struct hsr_port *master)
                goto out;
 
        skb_reset_mac_header(skb);
+       skb_reset_mac_len(skb);
        skb_reset_network_header(skb);
        skb_reset_transport_header(skb);
 
index 6852e9b..ceb8afb 100644 (file)
@@ -474,8 +474,8 @@ static void handle_std_frame(struct sk_buff *skb,
        }
 }
 
-void hsr_fill_frame_info(__be16 proto, struct sk_buff *skb,
-                        struct hsr_frame_info *frame)
+int hsr_fill_frame_info(__be16 proto, struct sk_buff *skb,
+                       struct hsr_frame_info *frame)
 {
        struct hsr_port *port = frame->port_rcv;
        struct hsr_priv *hsr = port->hsr;
@@ -483,20 +483,26 @@ void hsr_fill_frame_info(__be16 proto, struct sk_buff *skb,
        /* HSRv0 supervisory frames double as a tag so treat them as tagged. */
        if ((!hsr->prot_version && proto == htons(ETH_P_PRP)) ||
            proto == htons(ETH_P_HSR)) {
+               /* Check if skb contains hsr_ethhdr */
+               if (skb->mac_len < sizeof(struct hsr_ethhdr))
+                       return -EINVAL;
+
                /* HSR tagged frame :- Data or Supervision */
                frame->skb_std = NULL;
                frame->skb_prp = NULL;
                frame->skb_hsr = skb;
                frame->sequence_nr = hsr_get_skb_sequence_nr(skb);
-               return;
+               return 0;
        }
 
        /* Standard frame or PRP from master port */
        handle_std_frame(skb, frame);
+
+       return 0;
 }
 
-void prp_fill_frame_info(__be16 proto, struct sk_buff *skb,
-                        struct hsr_frame_info *frame)
+int prp_fill_frame_info(__be16 proto, struct sk_buff *skb,
+                       struct hsr_frame_info *frame)
 {
        /* Supervision frame */
        struct prp_rct *rct = skb_get_PRP_rct(skb);
@@ -507,9 +513,11 @@ void prp_fill_frame_info(__be16 proto, struct sk_buff *skb,
                frame->skb_std = NULL;
                frame->skb_prp = skb;
                frame->sequence_nr = prp_get_skb_sequence_nr(rct);
-               return;
+               return 0;
        }
        handle_std_frame(skb, frame);
+
+       return 0;
 }
 
 static int fill_frame_info(struct hsr_frame_info *frame,
@@ -519,9 +527,10 @@ static int fill_frame_info(struct hsr_frame_info *frame,
        struct hsr_vlan_ethhdr *vlan_hdr;
        struct ethhdr *ethhdr;
        __be16 proto;
+       int ret;
 
-       /* Check if skb contains hsr_ethhdr */
-       if (skb->mac_len < sizeof(struct hsr_ethhdr))
+       /* Check if skb contains ethhdr */
+       if (skb->mac_len < sizeof(struct ethhdr))
                return -EINVAL;
 
        memset(frame, 0, sizeof(*frame));
@@ -548,7 +557,10 @@ static int fill_frame_info(struct hsr_frame_info *frame,
 
        frame->is_from_san = false;
        frame->port_rcv = port;
-       hsr->proto_ops->fill_frame_info(proto, skb, frame);
+       ret = hsr->proto_ops->fill_frame_info(proto, skb, frame);
+       if (ret)
+               return ret;
+
        check_local_dest(port->hsr, skb, frame);
 
        return 0;
index b6acaaf..2066367 100644 (file)
@@ -24,8 +24,8 @@ struct sk_buff *prp_get_untagged_frame(struct hsr_frame_info *frame,
                                       struct hsr_port *port);
 bool prp_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port);
 bool hsr_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port);
-void prp_fill_frame_info(__be16 proto, struct sk_buff *skb,
-                        struct hsr_frame_info *frame);
-void hsr_fill_frame_info(__be16 proto, struct sk_buff *skb,
-                        struct hsr_frame_info *frame);
+int prp_fill_frame_info(__be16 proto, struct sk_buff *skb,
+                       struct hsr_frame_info *frame);
+int hsr_fill_frame_info(__be16 proto, struct sk_buff *skb,
+                       struct hsr_frame_info *frame);
 #endif /* __HSR_FORWARD_H */
index 8f26467..53d1f7a 100644 (file)
@@ -186,8 +186,8 @@ struct hsr_proto_ops {
                                               struct hsr_port *port);
        struct sk_buff * (*create_tagged_frame)(struct hsr_frame_info *frame,
                                                struct hsr_port *port);
-       void (*fill_frame_info)(__be16 proto, struct sk_buff *skb,
-                               struct hsr_frame_info *frame);
+       int (*fill_frame_info)(__be16 proto, struct sk_buff *skb,
+                              struct hsr_frame_info *frame);
        bool (*invalid_dan_ingress_frame)(__be16 protocol);
        void (*update_san_info)(struct hsr_node *node, bool is_sup);
 };
index c5227d4..b70e6bb 100644 (file)
@@ -60,12 +60,11 @@ static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb)
                goto finish_pass;
 
        skb_push(skb, ETH_HLEN);
-
-       if (skb_mac_header(skb) != skb->data) {
-               WARN_ONCE(1, "%s:%d: Malformed frame at source port %s)\n",
-                         __func__, __LINE__, port->dev->name);
-               goto finish_consume;
-       }
+       skb_reset_mac_header(skb);
+       if ((!hsr->prot_version && protocol == htons(ETH_P_PRP)) ||
+           protocol == htons(ETH_P_HSR))
+               skb_set_network_header(skb, ETH_HLEN + HSR_HLEN);
+       skb_reset_mac_len(skb);
 
        hsr_forward_skb(skb, port);