net: hsr: fix mac_len checks
Commit2e9f60932a
("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:2e9f60932a
("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>
This commit is contained in:
parent
a4dd4fc610
commit
48b491a5cc
@ -218,6 +218,7 @@ static netdev_tx_t hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||||||
if (master) {
|
if (master) {
|
||||||
skb->dev = master->dev;
|
skb->dev = master->dev;
|
||||||
skb_reset_mac_header(skb);
|
skb_reset_mac_header(skb);
|
||||||
|
skb_reset_mac_len(skb);
|
||||||
hsr_forward_skb(skb, master);
|
hsr_forward_skb(skb, master);
|
||||||
} else {
|
} else {
|
||||||
atomic_long_inc(&dev->tx_dropped);
|
atomic_long_inc(&dev->tx_dropped);
|
||||||
@ -259,6 +260,7 @@ static struct sk_buff *hsr_init_skb(struct hsr_port *master)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
skb_reset_mac_header(skb);
|
skb_reset_mac_header(skb);
|
||||||
|
skb_reset_mac_len(skb);
|
||||||
skb_reset_network_header(skb);
|
skb_reset_network_header(skb);
|
||||||
skb_reset_transport_header(skb);
|
skb_reset_transport_header(skb);
|
||||||
|
|
||||||
|
@ -474,8 +474,8 @@ static void handle_std_frame(struct sk_buff *skb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hsr_fill_frame_info(__be16 proto, struct sk_buff *skb,
|
int hsr_fill_frame_info(__be16 proto, struct sk_buff *skb,
|
||||||
struct hsr_frame_info *frame)
|
struct hsr_frame_info *frame)
|
||||||
{
|
{
|
||||||
struct hsr_port *port = frame->port_rcv;
|
struct hsr_port *port = frame->port_rcv;
|
||||||
struct hsr_priv *hsr = port->hsr;
|
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. */
|
/* HSRv0 supervisory frames double as a tag so treat them as tagged. */
|
||||||
if ((!hsr->prot_version && proto == htons(ETH_P_PRP)) ||
|
if ((!hsr->prot_version && proto == htons(ETH_P_PRP)) ||
|
||||||
proto == htons(ETH_P_HSR)) {
|
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 */
|
/* HSR tagged frame :- Data or Supervision */
|
||||||
frame->skb_std = NULL;
|
frame->skb_std = NULL;
|
||||||
frame->skb_prp = NULL;
|
frame->skb_prp = NULL;
|
||||||
frame->skb_hsr = skb;
|
frame->skb_hsr = skb;
|
||||||
frame->sequence_nr = hsr_get_skb_sequence_nr(skb);
|
frame->sequence_nr = hsr_get_skb_sequence_nr(skb);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Standard frame or PRP from master port */
|
/* Standard frame or PRP from master port */
|
||||||
handle_std_frame(skb, frame);
|
handle_std_frame(skb, frame);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void prp_fill_frame_info(__be16 proto, struct sk_buff *skb,
|
int prp_fill_frame_info(__be16 proto, struct sk_buff *skb,
|
||||||
struct hsr_frame_info *frame)
|
struct hsr_frame_info *frame)
|
||||||
{
|
{
|
||||||
/* Supervision frame */
|
/* Supervision frame */
|
||||||
struct prp_rct *rct = skb_get_PRP_rct(skb);
|
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_std = NULL;
|
||||||
frame->skb_prp = skb;
|
frame->skb_prp = skb;
|
||||||
frame->sequence_nr = prp_get_skb_sequence_nr(rct);
|
frame->sequence_nr = prp_get_skb_sequence_nr(rct);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
handle_std_frame(skb, frame);
|
handle_std_frame(skb, frame);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fill_frame_info(struct hsr_frame_info *frame,
|
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 hsr_vlan_ethhdr *vlan_hdr;
|
||||||
struct ethhdr *ethhdr;
|
struct ethhdr *ethhdr;
|
||||||
__be16 proto;
|
__be16 proto;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* Check if skb contains hsr_ethhdr */
|
/* Check if skb contains ethhdr */
|
||||||
if (skb->mac_len < sizeof(struct hsr_ethhdr))
|
if (skb->mac_len < sizeof(struct ethhdr))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
memset(frame, 0, sizeof(*frame));
|
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->is_from_san = false;
|
||||||
frame->port_rcv = port;
|
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);
|
check_local_dest(port->hsr, skb, frame);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -24,8 +24,8 @@ struct sk_buff *prp_get_untagged_frame(struct hsr_frame_info *frame,
|
|||||||
struct hsr_port *port);
|
struct hsr_port *port);
|
||||||
bool prp_drop_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);
|
bool hsr_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port);
|
||||||
void prp_fill_frame_info(__be16 proto, struct sk_buff *skb,
|
int prp_fill_frame_info(__be16 proto, struct sk_buff *skb,
|
||||||
struct hsr_frame_info *frame);
|
struct hsr_frame_info *frame);
|
||||||
void hsr_fill_frame_info(__be16 proto, struct sk_buff *skb,
|
int hsr_fill_frame_info(__be16 proto, struct sk_buff *skb,
|
||||||
struct hsr_frame_info *frame);
|
struct hsr_frame_info *frame);
|
||||||
#endif /* __HSR_FORWARD_H */
|
#endif /* __HSR_FORWARD_H */
|
||||||
|
@ -186,8 +186,8 @@ struct hsr_proto_ops {
|
|||||||
struct hsr_port *port);
|
struct hsr_port *port);
|
||||||
struct sk_buff * (*create_tagged_frame)(struct hsr_frame_info *frame,
|
struct sk_buff * (*create_tagged_frame)(struct hsr_frame_info *frame,
|
||||||
struct hsr_port *port);
|
struct hsr_port *port);
|
||||||
void (*fill_frame_info)(__be16 proto, struct sk_buff *skb,
|
int (*fill_frame_info)(__be16 proto, struct sk_buff *skb,
|
||||||
struct hsr_frame_info *frame);
|
struct hsr_frame_info *frame);
|
||||||
bool (*invalid_dan_ingress_frame)(__be16 protocol);
|
bool (*invalid_dan_ingress_frame)(__be16 protocol);
|
||||||
void (*update_san_info)(struct hsr_node *node, bool is_sup);
|
void (*update_san_info)(struct hsr_node *node, bool is_sup);
|
||||||
};
|
};
|
||||||
|
@ -60,12 +60,11 @@ static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb)
|
|||||||
goto finish_pass;
|
goto finish_pass;
|
||||||
|
|
||||||
skb_push(skb, ETH_HLEN);
|
skb_push(skb, ETH_HLEN);
|
||||||
|
skb_reset_mac_header(skb);
|
||||||
if (skb_mac_header(skb) != skb->data) {
|
if ((!hsr->prot_version && protocol == htons(ETH_P_PRP)) ||
|
||||||
WARN_ONCE(1, "%s:%d: Malformed frame at source port %s)\n",
|
protocol == htons(ETH_P_HSR))
|
||||||
__func__, __LINE__, port->dev->name);
|
skb_set_network_header(skb, ETH_HLEN + HSR_HLEN);
|
||||||
goto finish_consume;
|
skb_reset_mac_len(skb);
|
||||||
}
|
|
||||||
|
|
||||||
hsr_forward_skb(skb, port);
|
hsr_forward_skb(skb, port);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user