diff options
Diffstat (limited to 'net/hsr/hsr_device.c')
-rw-r--r-- | net/hsr/hsr_device.c | 46 |
1 files changed, 30 insertions, 16 deletions
diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 049e22bdaafb..ebdfd5b64e17 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -231,7 +231,9 @@ static netdev_tx_t hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev) skb->dev = master->dev; skb_reset_mac_header(skb); skb_reset_mac_len(skb); + spin_lock_bh(&hsr->seqnr_lock); hsr_forward_skb(skb, master); + spin_unlock_bh(&hsr->seqnr_lock); } else { dev_core_stats_tx_dropped_inc(dev); dev_kfree_skb_any(skb); @@ -312,10 +314,14 @@ static void send_hsr_supervision_frame(struct hsr_port *port, set_hsr_stag_HSR_ver(hsr_stag, hsr->prot_version); /* From HSRv1 on we have separate supervision sequence numbers. */ - if (hsr->prot_version > 0) - hsr_stag->sequence_nr = htons(atomic_inc_return(&hsr->sup_sequence_nr)); - else - hsr_stag->sequence_nr = htons(atomic_inc_return(&hsr->sequence_nr)); + spin_lock_bh(&hsr->seqnr_lock); + if (hsr->prot_version > 0) { + hsr_stag->sequence_nr = htons(hsr->sup_sequence_nr); + hsr->sup_sequence_nr++; + } else { + hsr_stag->sequence_nr = htons(hsr->sequence_nr); + hsr->sequence_nr++; + } hsr_stag->tlv.HSR_TLV_type = type; /* TODO: Why 12 in HSRv0? */ @@ -337,11 +343,13 @@ static void send_hsr_supervision_frame(struct hsr_port *port, ether_addr_copy(hsr_sp->macaddress_A, hsr->macaddress_redbox); } - if (skb_put_padto(skb, ETH_ZLEN)) + if (skb_put_padto(skb, ETH_ZLEN)) { + spin_unlock_bh(&hsr->seqnr_lock); return; + } hsr_forward_skb(skb, port); - + spin_unlock_bh(&hsr->seqnr_lock); return; } @@ -366,7 +374,9 @@ static void send_prp_supervision_frame(struct hsr_port *master, set_hsr_stag_HSR_ver(hsr_stag, (hsr->prot_version ? 1 : 0)); /* From HSRv1 on we have separate supervision sequence numbers. */ - hsr_stag->sequence_nr = htons(atomic_inc_return(&hsr->sup_sequence_nr)); + spin_lock_bh(&hsr->seqnr_lock); + hsr_stag->sequence_nr = htons(hsr->sup_sequence_nr); + hsr->sup_sequence_nr++; hsr_stag->tlv.HSR_TLV_type = PRP_TLV_LIFE_CHECK_DD; hsr_stag->tlv.HSR_TLV_length = sizeof(struct hsr_sup_payload); @@ -374,10 +384,13 @@ static void send_prp_supervision_frame(struct hsr_port *master, 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)) + if (skb_put_padto(skb, ETH_ZLEN)) { + spin_unlock_bh(&hsr->seqnr_lock); return; + } hsr_forward_skb(skb, master); + spin_unlock_bh(&hsr->seqnr_lock); } /* Announce (supervision frame) timer function @@ -545,6 +558,12 @@ void hsr_dev_setup(struct net_device *dev) dev->netdev_ops = &hsr_device_ops; SET_NETDEV_DEVTYPE(dev, &hsr_type); dev->priv_flags |= IFF_NO_QUEUE | IFF_DISABLE_NETPOLL; + /* Prevent recursive tx locking */ + dev->lltx = true; + /* Not sure about this. Taken from bridge code. netdevice.h says + * it means "Does not change network namespaces". + */ + dev->netns_local = true; dev->needs_free_netdev = true; @@ -554,16 +573,10 @@ void hsr_dev_setup(struct net_device *dev) dev->features = dev->hw_features; - /* Prevent recursive tx locking */ - dev->features |= NETIF_F_LLTX; /* VLAN on top of HSR needs testing and probably some work on * hsr_header_create() etc. */ dev->features |= NETIF_F_VLAN_CHALLENGED; - /* Not sure about this. Taken from bridge code. netdev_features.h says - * it means "Does not change network namespaces". - */ - dev->features |= NETIF_F_NETNS_LOCAL; } /* Return true if dev is a HSR master; return false otherwise. @@ -612,9 +625,10 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], if (res < 0) return res; + spin_lock_init(&hsr->seqnr_lock); /* Overflow soon to find bugs easier: */ - atomic_set(&hsr->sequence_nr, HSR_SEQNR_START); - atomic_set(&hsr->sup_sequence_nr, HSR_SUP_SEQNR_START); + hsr->sequence_nr = HSR_SEQNR_START; + hsr->sup_sequence_nr = HSR_SUP_SEQNR_START; timer_setup(&hsr->announce_timer, hsr_announce, 0); timer_setup(&hsr->prune_timer, hsr_prune_nodes, 0); |