mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-29 01:51:39 +00:00
Merge branch 'net-hsr-improvements-and-bug-fixes'
Murali Karicheri says: ==================== net: hsr: improvements and bug fixes This series has some coding style fixes and other bug fixes. Patch 12/14, I have also done SPDX conversion. Not sure if that is the only thing needed and is correct. So please pay close attention to this patch before merge as I would like to avoid any issue related to licensing applicable for this code. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
1e045a62ee
14 changed files with 327 additions and 277 deletions
|
@ -6,3 +6,4 @@ obj-$(CONFIG_HSR) += hsr.o
|
||||||
|
|
||||||
hsr-y := hsr_main.o hsr_framereg.o hsr_device.o \
|
hsr-y := hsr_main.o hsr_framereg.o hsr_device.o \
|
||||||
hsr_netlink.o hsr_slave.o hsr_forward.o
|
hsr_netlink.o hsr_slave.o hsr_forward.o
|
||||||
|
hsr-$(CONFIG_DEBUG_FS) += hsr_prp_debugfs.o
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/* Copyright 2011-2014 Autronica Fire and Security AS
|
/* Copyright 2011-2014 Autronica Fire and Security AS
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
||||||
|
@ -23,7 +19,6 @@
|
||||||
#include "hsr_main.h"
|
#include "hsr_main.h"
|
||||||
#include "hsr_forward.h"
|
#include "hsr_forward.h"
|
||||||
|
|
||||||
|
|
||||||
static bool is_admin_up(struct net_device *dev)
|
static bool is_admin_up(struct net_device *dev)
|
||||||
{
|
{
|
||||||
return dev && (dev->flags & IFF_UP);
|
return dev && (dev->flags & IFF_UP);
|
||||||
|
@ -68,7 +63,7 @@ static bool hsr_check_carrier(struct hsr_port *master)
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
hsr_for_each_port(master->hsr, port)
|
hsr_for_each_port(master->hsr, port)
|
||||||
if ((port->type != HSR_PT_MASTER) && is_slave_up(port->dev)) {
|
if (port->type != HSR_PT_MASTER && is_slave_up(port->dev)) {
|
||||||
has_carrier = true;
|
has_carrier = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +77,6 @@ static bool hsr_check_carrier(struct hsr_port *master)
|
||||||
return has_carrier;
|
return has_carrier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void hsr_check_announce(struct net_device *hsr_dev,
|
static void hsr_check_announce(struct net_device *hsr_dev,
|
||||||
unsigned char old_operstate)
|
unsigned char old_operstate)
|
||||||
{
|
{
|
||||||
|
@ -90,15 +84,14 @@ static void hsr_check_announce(struct net_device *hsr_dev,
|
||||||
|
|
||||||
hsr = netdev_priv(hsr_dev);
|
hsr = netdev_priv(hsr_dev);
|
||||||
|
|
||||||
if ((hsr_dev->operstate == IF_OPER_UP)
|
if (hsr_dev->operstate == IF_OPER_UP && old_operstate != IF_OPER_UP) {
|
||||||
&& (old_operstate != IF_OPER_UP)) {
|
|
||||||
/* Went up */
|
/* Went up */
|
||||||
hsr->announce_count = 0;
|
hsr->announce_count = 0;
|
||||||
mod_timer(&hsr->announce_timer,
|
mod_timer(&hsr->announce_timer,
|
||||||
jiffies + msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL));
|
jiffies + msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((hsr_dev->operstate != IF_OPER_UP) && (old_operstate == IF_OPER_UP))
|
if (hsr_dev->operstate != IF_OPER_UP && old_operstate == IF_OPER_UP)
|
||||||
/* Went down */
|
/* Went down */
|
||||||
del_timer(&hsr->announce_timer);
|
del_timer(&hsr->announce_timer);
|
||||||
}
|
}
|
||||||
|
@ -136,7 +129,6 @@ int hsr_get_max_mtu(struct hsr_priv *hsr)
|
||||||
return mtu_max - HSR_HLEN;
|
return mtu_max - HSR_HLEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int hsr_dev_change_mtu(struct net_device *dev, int new_mtu)
|
static int hsr_dev_change_mtu(struct net_device *dev, int new_mtu)
|
||||||
{
|
{
|
||||||
struct hsr_priv *hsr;
|
struct hsr_priv *hsr;
|
||||||
|
@ -191,14 +183,12 @@ static int hsr_dev_open(struct net_device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int hsr_dev_close(struct net_device *dev)
|
static int hsr_dev_close(struct net_device *dev)
|
||||||
{
|
{
|
||||||
/* Nothing to do here. */
|
/* Nothing to do here. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static netdev_features_t hsr_features_recompute(struct hsr_priv *hsr,
|
static netdev_features_t hsr_features_recompute(struct hsr_priv *hsr,
|
||||||
netdev_features_t features)
|
netdev_features_t features)
|
||||||
{
|
{
|
||||||
|
@ -231,7 +221,6 @@ static netdev_features_t hsr_fix_features(struct net_device *dev,
|
||||||
return hsr_features_recompute(hsr, features);
|
return hsr_features_recompute(hsr, features);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)
|
static int hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct hsr_priv *hsr = netdev_priv(dev);
|
struct hsr_priv *hsr = netdev_priv(dev);
|
||||||
|
@ -244,14 +233,13 @@ static int hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
return NETDEV_TX_OK;
|
return NETDEV_TX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const struct header_ops hsr_header_ops = {
|
static const struct header_ops hsr_header_ops = {
|
||||||
.create = eth_header,
|
.create = eth_header,
|
||||||
.parse = eth_header_parse,
|
.parse = eth_header_parse,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void send_hsr_supervision_frame(struct hsr_port *master,
|
static void send_hsr_supervision_frame(struct hsr_port *master,
|
||||||
u8 type, u8 hsrVer)
|
u8 type, u8 hsr_ver)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
int hlen, tlen;
|
int hlen, tlen;
|
||||||
|
@ -262,39 +250,38 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
|
||||||
|
|
||||||
hlen = LL_RESERVED_SPACE(master->dev);
|
hlen = LL_RESERVED_SPACE(master->dev);
|
||||||
tlen = master->dev->needed_tailroom;
|
tlen = master->dev->needed_tailroom;
|
||||||
skb = dev_alloc_skb(
|
skb = dev_alloc_skb(sizeof(struct hsr_tag) +
|
||||||
sizeof(struct hsr_tag) +
|
|
||||||
sizeof(struct hsr_sup_tag) +
|
sizeof(struct hsr_sup_tag) +
|
||||||
sizeof(struct hsr_sup_payload) + hlen + tlen);
|
sizeof(struct hsr_sup_payload) + hlen + tlen);
|
||||||
|
|
||||||
if (skb == NULL)
|
if (!skb)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
skb_reserve(skb, hlen);
|
skb_reserve(skb, hlen);
|
||||||
|
|
||||||
skb->dev = master->dev;
|
skb->dev = master->dev;
|
||||||
skb->protocol = htons(hsrVer ? ETH_P_HSR : ETH_P_PRP);
|
skb->protocol = htons(hsr_ver ? ETH_P_HSR : ETH_P_PRP);
|
||||||
skb->priority = TC_PRIO_CONTROL;
|
skb->priority = TC_PRIO_CONTROL;
|
||||||
|
|
||||||
if (dev_hard_header(skb, skb->dev, (hsrVer ? ETH_P_HSR : ETH_P_PRP),
|
if (dev_hard_header(skb, skb->dev, (hsr_ver ? ETH_P_HSR : ETH_P_PRP),
|
||||||
master->hsr->sup_multicast_addr,
|
master->hsr->sup_multicast_addr,
|
||||||
skb->dev->dev_addr, skb->len) <= 0)
|
skb->dev->dev_addr, skb->len) <= 0)
|
||||||
goto out;
|
goto out;
|
||||||
skb_reset_mac_header(skb);
|
skb_reset_mac_header(skb);
|
||||||
|
|
||||||
if (hsrVer > 0) {
|
if (hsr_ver > 0) {
|
||||||
hsr_tag = skb_put(skb, sizeof(struct hsr_tag));
|
hsr_tag = skb_put(skb, sizeof(struct hsr_tag));
|
||||||
hsr_tag->encap_proto = htons(ETH_P_PRP);
|
hsr_tag->encap_proto = htons(ETH_P_PRP);
|
||||||
set_hsr_tag_LSDU_size(hsr_tag, HSR_V1_SUP_LSDUSIZE);
|
set_hsr_tag_LSDU_size(hsr_tag, HSR_V1_SUP_LSDUSIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
hsr_stag = skb_put(skb, sizeof(struct hsr_sup_tag));
|
hsr_stag = skb_put(skb, sizeof(struct hsr_sup_tag));
|
||||||
set_hsr_stag_path(hsr_stag, (hsrVer ? 0x0 : 0xf));
|
set_hsr_stag_path(hsr_stag, (hsr_ver ? 0x0 : 0xf));
|
||||||
set_hsr_stag_HSR_Ver(hsr_stag, hsrVer);
|
set_hsr_stag_HSR_ver(hsr_stag, hsr_ver);
|
||||||
|
|
||||||
/* From HSRv1 on we have separate supervision sequence numbers. */
|
/* From HSRv1 on we have separate supervision sequence numbers. */
|
||||||
spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags);
|
spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags);
|
||||||
if (hsrVer > 0) {
|
if (hsr_ver > 0) {
|
||||||
hsr_stag->sequence_nr = htons(master->hsr->sup_sequence_nr);
|
hsr_stag->sequence_nr = htons(master->hsr->sup_sequence_nr);
|
||||||
hsr_tag->sequence_nr = htons(master->hsr->sequence_nr);
|
hsr_tag->sequence_nr = htons(master->hsr->sequence_nr);
|
||||||
master->hsr->sup_sequence_nr++;
|
master->hsr->sup_sequence_nr++;
|
||||||
|
@ -305,13 +292,14 @@ static void send_hsr_supervision_frame(struct hsr_port *master,
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags);
|
spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags);
|
||||||
|
|
||||||
hsr_stag->HSR_TLV_Type = type;
|
hsr_stag->HSR_TLV_type = type;
|
||||||
/* TODO: Why 12 in HSRv0? */
|
/* TODO: Why 12 in HSRv0? */
|
||||||
hsr_stag->HSR_TLV_Length = hsrVer ? sizeof(struct hsr_sup_payload) : 12;
|
hsr_stag->HSR_TLV_length =
|
||||||
|
hsr_ver ? sizeof(struct hsr_sup_payload) : 12;
|
||||||
|
|
||||||
/* Payload: MacAddressA */
|
/* Payload: MacAddressA */
|
||||||
hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
|
hsr_sp = skb_put(skb, sizeof(struct hsr_sup_payload));
|
||||||
ether_addr_copy(hsr_sp->MacAddressA, master->dev->dev_addr);
|
ether_addr_copy(hsr_sp->macaddress_A, master->dev->dev_addr);
|
||||||
|
|
||||||
if (skb_put_padto(skb, ETH_ZLEN + HSR_HLEN))
|
if (skb_put_padto(skb, ETH_ZLEN + HSR_HLEN))
|
||||||
return;
|
return;
|
||||||
|
@ -324,7 +312,6 @@ out:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Announce (supervision frame) timer function
|
/* Announce (supervision frame) timer function
|
||||||
*/
|
*/
|
||||||
static void hsr_announce(struct timer_list *t)
|
static void hsr_announce(struct timer_list *t)
|
||||||
|
@ -338,15 +325,15 @@ static void hsr_announce(struct timer_list *t)
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
|
master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
|
||||||
|
|
||||||
if (hsr->announce_count < 3 && hsr->protVersion == 0) {
|
if (hsr->announce_count < 3 && hsr->prot_version == 0) {
|
||||||
send_hsr_supervision_frame(master, HSR_TLV_ANNOUNCE,
|
send_hsr_supervision_frame(master, HSR_TLV_ANNOUNCE,
|
||||||
hsr->protVersion);
|
hsr->prot_version);
|
||||||
hsr->announce_count++;
|
hsr->announce_count++;
|
||||||
|
|
||||||
interval = msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL);
|
interval = msecs_to_jiffies(HSR_ANNOUNCE_INTERVAL);
|
||||||
} else {
|
} else {
|
||||||
send_hsr_supervision_frame(master, HSR_TLV_LIFE_CHECK,
|
send_hsr_supervision_frame(master, HSR_TLV_LIFE_CHECK,
|
||||||
hsr->protVersion);
|
hsr->prot_version);
|
||||||
|
|
||||||
interval = msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL);
|
interval = msecs_to_jiffies(HSR_LIFE_CHECK_INTERVAL);
|
||||||
}
|
}
|
||||||
|
@ -357,7 +344,6 @@ static void hsr_announce(struct timer_list *t)
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* According to comments in the declaration of struct net_device, this function
|
/* According to comments in the declaration of struct net_device, this function
|
||||||
* is "Called from unregister, can be used to call free_netdev". Ok then...
|
* is "Called from unregister, can be used to call free_netdev". Ok then...
|
||||||
*/
|
*/
|
||||||
|
@ -368,6 +354,8 @@ static void hsr_dev_destroy(struct net_device *hsr_dev)
|
||||||
|
|
||||||
hsr = netdev_priv(hsr_dev);
|
hsr = netdev_priv(hsr_dev);
|
||||||
|
|
||||||
|
hsr_prp_debugfs_term(hsr);
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
hsr_for_each_port(hsr, port)
|
hsr_for_each_port(hsr, port)
|
||||||
hsr_del_port(port);
|
hsr_del_port(port);
|
||||||
|
@ -423,7 +411,6 @@ void hsr_dev_setup(struct net_device *dev)
|
||||||
dev->features |= NETIF_F_NETNS_LOCAL;
|
dev->features |= NETIF_F_NETNS_LOCAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return true if dev is a HSR master; return false otherwise.
|
/* Return true if dev is a HSR master; return false otherwise.
|
||||||
*/
|
*/
|
||||||
inline bool is_hsr_master(struct net_device *dev)
|
inline bool is_hsr_master(struct net_device *dev)
|
||||||
|
@ -467,7 +454,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
|
||||||
ether_addr_copy(hsr->sup_multicast_addr, def_multicast_addr);
|
ether_addr_copy(hsr->sup_multicast_addr, def_multicast_addr);
|
||||||
hsr->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec;
|
hsr->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec;
|
||||||
|
|
||||||
hsr->protVersion = protocol_version;
|
hsr->prot_version = protocol_version;
|
||||||
|
|
||||||
/* FIXME: should I modify the value of these?
|
/* FIXME: should I modify the value of these?
|
||||||
*
|
*
|
||||||
|
@ -498,6 +485,9 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
mod_timer(&hsr->prune_timer, jiffies + msecs_to_jiffies(PRUNE_PERIOD));
|
mod_timer(&hsr->prune_timer, jiffies + msecs_to_jiffies(PRUNE_PERIOD));
|
||||||
|
res = hsr_prp_debugfs_init(hsr);
|
||||||
|
if (res)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/* Copyright 2011-2014 Autronica Fire and Security AS
|
/* Copyright 2011-2014 Autronica Fire and Security AS
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/* Copyright 2011-2014 Autronica Fire and Security AS
|
/* Copyright 2011-2014 Autronica Fire and Security AS
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
||||||
|
@ -17,7 +13,6 @@
|
||||||
#include "hsr_main.h"
|
#include "hsr_main.h"
|
||||||
#include "hsr_framereg.h"
|
#include "hsr_framereg.h"
|
||||||
|
|
||||||
|
|
||||||
struct hsr_node;
|
struct hsr_node;
|
||||||
|
|
||||||
struct hsr_frame_info {
|
struct hsr_frame_info {
|
||||||
|
@ -32,7 +27,6 @@ struct hsr_frame_info {
|
||||||
bool is_local_exclusive;
|
bool is_local_exclusive;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* The uses I can see for these HSR supervision frames are:
|
/* The uses I can see for these HSR supervision frames are:
|
||||||
* 1) Use the frames that are sent after node initialization ("HSR_TLV.Type =
|
* 1) Use the frames that are sent after node initialization ("HSR_TLV.Type =
|
||||||
* 22") to reset any sequence_nr counters belonging to that node. Useful if
|
* 22") to reset any sequence_nr counters belonging to that node. Useful if
|
||||||
|
@ -50,46 +44,45 @@ struct hsr_frame_info {
|
||||||
*/
|
*/
|
||||||
static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb)
|
static bool is_supervision_frame(struct hsr_priv *hsr, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct ethhdr *ethHdr;
|
struct ethhdr *eth_hdr;
|
||||||
struct hsr_sup_tag *hsrSupTag;
|
struct hsr_sup_tag *hsr_sup_tag;
|
||||||
struct hsrv1_ethhdr_sp *hsrV1Hdr;
|
struct hsrv1_ethhdr_sp *hsr_V1_hdr;
|
||||||
|
|
||||||
WARN_ON_ONCE(!skb_mac_header_was_set(skb));
|
WARN_ON_ONCE(!skb_mac_header_was_set(skb));
|
||||||
ethHdr = (struct ethhdr *) skb_mac_header(skb);
|
eth_hdr = (struct ethhdr *)skb_mac_header(skb);
|
||||||
|
|
||||||
/* Correct addr? */
|
/* Correct addr? */
|
||||||
if (!ether_addr_equal(ethHdr->h_dest,
|
if (!ether_addr_equal(eth_hdr->h_dest,
|
||||||
hsr->sup_multicast_addr))
|
hsr->sup_multicast_addr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Correct ether type?. */
|
/* Correct ether type?. */
|
||||||
if (!(ethHdr->h_proto == htons(ETH_P_PRP)
|
if (!(eth_hdr->h_proto == htons(ETH_P_PRP) ||
|
||||||
|| ethHdr->h_proto == htons(ETH_P_HSR)))
|
eth_hdr->h_proto == htons(ETH_P_HSR)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Get the supervision header from correct location. */
|
/* Get the supervision header from correct location. */
|
||||||
if (ethHdr->h_proto == htons(ETH_P_HSR)) { /* Okay HSRv1. */
|
if (eth_hdr->h_proto == htons(ETH_P_HSR)) { /* Okay HSRv1. */
|
||||||
hsrV1Hdr = (struct hsrv1_ethhdr_sp *) skb_mac_header(skb);
|
hsr_V1_hdr = (struct hsrv1_ethhdr_sp *)skb_mac_header(skb);
|
||||||
if (hsrV1Hdr->hsr.encap_proto != htons(ETH_P_PRP))
|
if (hsr_V1_hdr->hsr.encap_proto != htons(ETH_P_PRP))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
hsrSupTag = &hsrV1Hdr->hsr_sup;
|
hsr_sup_tag = &hsr_V1_hdr->hsr_sup;
|
||||||
} else {
|
} else {
|
||||||
hsrSupTag = &((struct hsrv0_ethhdr_sp *) skb_mac_header(skb))->hsr_sup;
|
hsr_sup_tag =
|
||||||
|
&((struct hsrv0_ethhdr_sp *)skb_mac_header(skb))->hsr_sup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((hsrSupTag->HSR_TLV_Type != HSR_TLV_ANNOUNCE) &&
|
if (hsr_sup_tag->HSR_TLV_type != HSR_TLV_ANNOUNCE &&
|
||||||
(hsrSupTag->HSR_TLV_Type != HSR_TLV_LIFE_CHECK))
|
hsr_sup_tag->HSR_TLV_type != HSR_TLV_LIFE_CHECK)
|
||||||
return false;
|
return false;
|
||||||
if ((hsrSupTag->HSR_TLV_Length != 12) &&
|
if (hsr_sup_tag->HSR_TLV_length != 12 &&
|
||||||
(hsrSupTag->HSR_TLV_Length !=
|
hsr_sup_tag->HSR_TLV_length != sizeof(struct hsr_sup_payload))
|
||||||
sizeof(struct hsr_sup_payload)))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct sk_buff *create_stripped_skb(struct sk_buff *skb_in,
|
static struct sk_buff *create_stripped_skb(struct sk_buff *skb_in,
|
||||||
struct hsr_frame_info *frame)
|
struct hsr_frame_info *frame)
|
||||||
{
|
{
|
||||||
|
@ -100,7 +93,7 @@ static struct sk_buff *create_stripped_skb(struct sk_buff *skb_in,
|
||||||
skb_pull(skb_in, HSR_HLEN);
|
skb_pull(skb_in, HSR_HLEN);
|
||||||
skb = __pskb_copy(skb_in, skb_headroom(skb_in) - HSR_HLEN, GFP_ATOMIC);
|
skb = __pskb_copy(skb_in, skb_headroom(skb_in) - HSR_HLEN, GFP_ATOMIC);
|
||||||
skb_push(skb_in, HSR_HLEN);
|
skb_push(skb_in, HSR_HLEN);
|
||||||
if (skb == NULL)
|
if (!skb)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
skb_reset_mac_header(skb);
|
skb_reset_mac_header(skb);
|
||||||
|
@ -127,9 +120,8 @@ static struct sk_buff *frame_get_stripped_skb(struct hsr_frame_info *frame,
|
||||||
return skb_clone(frame->skb_std, GFP_ATOMIC);
|
return skb_clone(frame->skb_std, GFP_ATOMIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void hsr_fill_tag(struct sk_buff *skb, struct hsr_frame_info *frame,
|
static void hsr_fill_tag(struct sk_buff *skb, struct hsr_frame_info *frame,
|
||||||
struct hsr_port *port, u8 protoVersion)
|
struct hsr_port *port, u8 proto_version)
|
||||||
{
|
{
|
||||||
struct hsr_ethhdr *hsr_ethhdr;
|
struct hsr_ethhdr *hsr_ethhdr;
|
||||||
int lane_id;
|
int lane_id;
|
||||||
|
@ -150,7 +142,7 @@ static void hsr_fill_tag(struct sk_buff *skb, struct hsr_frame_info *frame,
|
||||||
set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, lsdu_size);
|
set_hsr_tag_LSDU_size(&hsr_ethhdr->hsr_tag, lsdu_size);
|
||||||
hsr_ethhdr->hsr_tag.sequence_nr = htons(frame->sequence_nr);
|
hsr_ethhdr->hsr_tag.sequence_nr = htons(frame->sequence_nr);
|
||||||
hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto;
|
hsr_ethhdr->hsr_tag.encap_proto = hsr_ethhdr->ethhdr.h_proto;
|
||||||
hsr_ethhdr->ethhdr.h_proto = htons(protoVersion ?
|
hsr_ethhdr->ethhdr.h_proto = htons(proto_version ?
|
||||||
ETH_P_HSR : ETH_P_PRP);
|
ETH_P_HSR : ETH_P_PRP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +156,7 @@ static struct sk_buff *create_tagged_skb(struct sk_buff *skb_o,
|
||||||
|
|
||||||
/* Create the new skb with enough headroom to fit the HSR tag */
|
/* Create the new skb with enough headroom to fit the HSR tag */
|
||||||
skb = __pskb_copy(skb_o, skb_headroom(skb_o) + HSR_HLEN, GFP_ATOMIC);
|
skb = __pskb_copy(skb_o, skb_headroom(skb_o) + HSR_HLEN, GFP_ATOMIC);
|
||||||
if (skb == NULL)
|
if (!skb)
|
||||||
return NULL;
|
return NULL;
|
||||||
skb_reset_mac_header(skb);
|
skb_reset_mac_header(skb);
|
||||||
|
|
||||||
|
@ -180,7 +172,7 @@ static struct sk_buff *create_tagged_skb(struct sk_buff *skb_o,
|
||||||
memmove(dst, src, movelen);
|
memmove(dst, src, movelen);
|
||||||
skb_reset_mac_header(skb);
|
skb_reset_mac_header(skb);
|
||||||
|
|
||||||
hsr_fill_tag(skb, frame, port, port->hsr->protVersion);
|
hsr_fill_tag(skb, frame, port, port->hsr->prot_version);
|
||||||
|
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
@ -194,7 +186,7 @@ static struct sk_buff *frame_get_tagged_skb(struct hsr_frame_info *frame,
|
||||||
if (frame->skb_hsr)
|
if (frame->skb_hsr)
|
||||||
return skb_clone(frame->skb_hsr, GFP_ATOMIC);
|
return skb_clone(frame->skb_hsr, GFP_ATOMIC);
|
||||||
|
|
||||||
if ((port->type != HSR_PT_SLAVE_A) && (port->type != HSR_PT_SLAVE_B)) {
|
if (port->type != HSR_PT_SLAVE_A && port->type != HSR_PT_SLAVE_B) {
|
||||||
WARN_ONCE(1, "HSR: Bug: trying to create a tagged frame for a non-ring port");
|
WARN_ONCE(1, "HSR: Bug: trying to create a tagged frame for a non-ring port");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -202,7 +194,6 @@ static struct sk_buff *frame_get_tagged_skb(struct hsr_frame_info *frame,
|
||||||
return create_tagged_skb(frame->skb_std, frame, port);
|
return create_tagged_skb(frame->skb_std, frame, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void hsr_deliver_master(struct sk_buff *skb, struct net_device *dev,
|
static void hsr_deliver_master(struct sk_buff *skb, struct net_device *dev,
|
||||||
struct hsr_node *node_src)
|
struct hsr_node *node_src)
|
||||||
{
|
{
|
||||||
|
@ -237,7 +228,6 @@ static int hsr_xmit(struct sk_buff *skb, struct hsr_port *port,
|
||||||
return dev_queue_xmit(skb);
|
return dev_queue_xmit(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Forward the frame through all devices except:
|
/* Forward the frame through all devices except:
|
||||||
* - Back through the receiving device
|
* - Back through the receiving device
|
||||||
* - If it's a HSR frame: through a device where it has passed before
|
* - If it's a HSR frame: through a device where it has passed before
|
||||||
|
@ -260,11 +250,11 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Don't deliver locally unless we should */
|
/* Don't deliver locally unless we should */
|
||||||
if ((port->type == HSR_PT_MASTER) && !frame->is_local_dest)
|
if (port->type == HSR_PT_MASTER && !frame->is_local_dest)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Deliver frames directly addressed to us to master only */
|
/* Deliver frames directly addressed to us to master only */
|
||||||
if ((port->type != HSR_PT_MASTER) && frame->is_local_exclusive)
|
if (port->type != HSR_PT_MASTER && frame->is_local_exclusive)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Don't send frame over port where it has been sent before */
|
/* Don't send frame over port where it has been sent before */
|
||||||
|
@ -272,7 +262,7 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
|
||||||
frame->sequence_nr))
|
frame->sequence_nr))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (frame->is_supervision && (port->type == HSR_PT_MASTER)) {
|
if (frame->is_supervision && port->type == HSR_PT_MASTER) {
|
||||||
hsr_handle_sup_frame(frame->skb_hsr,
|
hsr_handle_sup_frame(frame->skb_hsr,
|
||||||
frame->node_src,
|
frame->node_src,
|
||||||
frame->port_rcv);
|
frame->port_rcv);
|
||||||
|
@ -283,7 +273,7 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
|
||||||
skb = frame_get_tagged_skb(frame, port);
|
skb = frame_get_tagged_skb(frame, port);
|
||||||
else
|
else
|
||||||
skb = frame_get_stripped_skb(frame, port);
|
skb = frame_get_stripped_skb(frame, port);
|
||||||
if (skb == NULL) {
|
if (!skb) {
|
||||||
/* FIXME: Record the dropped frame? */
|
/* FIXME: Record the dropped frame? */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -296,7 +286,6 @@ static void hsr_forward_do(struct hsr_frame_info *frame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void check_local_dest(struct hsr_priv *hsr, struct sk_buff *skb,
|
static void check_local_dest(struct hsr_priv *hsr, struct sk_buff *skb,
|
||||||
struct hsr_frame_info *frame)
|
struct hsr_frame_info *frame)
|
||||||
{
|
{
|
||||||
|
@ -307,16 +296,15 @@ static void check_local_dest(struct hsr_priv *hsr, struct sk_buff *skb,
|
||||||
frame->is_local_exclusive = false;
|
frame->is_local_exclusive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((skb->pkt_type == PACKET_HOST) ||
|
if (skb->pkt_type == PACKET_HOST ||
|
||||||
(skb->pkt_type == PACKET_MULTICAST) ||
|
skb->pkt_type == PACKET_MULTICAST ||
|
||||||
(skb->pkt_type == PACKET_BROADCAST)) {
|
skb->pkt_type == PACKET_BROADCAST) {
|
||||||
frame->is_local_dest = true;
|
frame->is_local_dest = true;
|
||||||
} else {
|
} else {
|
||||||
frame->is_local_dest = false;
|
frame->is_local_dest = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int hsr_fill_frame_info(struct hsr_frame_info *frame,
|
static int hsr_fill_frame_info(struct hsr_frame_info *frame,
|
||||||
struct sk_buff *skb, struct hsr_port *port)
|
struct sk_buff *skb, struct hsr_port *port)
|
||||||
{
|
{
|
||||||
|
@ -325,7 +313,7 @@ static int hsr_fill_frame_info(struct hsr_frame_info *frame,
|
||||||
|
|
||||||
frame->is_supervision = is_supervision_frame(port->hsr, skb);
|
frame->is_supervision = is_supervision_frame(port->hsr, skb);
|
||||||
frame->node_src = hsr_get_node(port, skb, frame->is_supervision);
|
frame->node_src = hsr_get_node(port, skb, frame->is_supervision);
|
||||||
if (frame->node_src == NULL)
|
if (!frame->node_src)
|
||||||
return -1; /* Unknown node and !is_supervision, or no mem */
|
return -1; /* Unknown node and !is_supervision, or no mem */
|
||||||
|
|
||||||
ethhdr = (struct ethhdr *)skb_mac_header(skb);
|
ethhdr = (struct ethhdr *)skb_mac_header(skb);
|
||||||
|
@ -335,8 +323,8 @@ static int hsr_fill_frame_info(struct hsr_frame_info *frame,
|
||||||
/* FIXME: */
|
/* FIXME: */
|
||||||
WARN_ONCE(1, "HSR: VLAN not yet supported");
|
WARN_ONCE(1, "HSR: VLAN not yet supported");
|
||||||
}
|
}
|
||||||
if (ethhdr->h_proto == htons(ETH_P_PRP)
|
if (ethhdr->h_proto == htons(ETH_P_PRP) ||
|
||||||
|| ethhdr->h_proto == htons(ETH_P_HSR)) {
|
ethhdr->h_proto == htons(ETH_P_HSR)) {
|
||||||
frame->skb_std = NULL;
|
frame->skb_std = 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);
|
||||||
|
@ -372,9 +360,9 @@ void hsr_forward_skb(struct sk_buff *skb, struct hsr_port *port)
|
||||||
hsr_register_frame_in(frame.node_src, port, frame.sequence_nr);
|
hsr_register_frame_in(frame.node_src, port, frame.sequence_nr);
|
||||||
hsr_forward_do(&frame);
|
hsr_forward_do(&frame);
|
||||||
|
|
||||||
if (frame.skb_hsr != NULL)
|
if (frame.skb_hsr)
|
||||||
kfree_skb(frame.skb_hsr);
|
kfree_skb(frame.skb_hsr);
|
||||||
if (frame.skb_std != NULL)
|
if (frame.skb_std)
|
||||||
kfree_skb(frame.skb_std);
|
kfree_skb(frame.skb_std);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/* Copyright 2011-2014 Autronica Fire and Security AS
|
/* Copyright 2011-2014 Autronica Fire and Security AS
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/* Copyright 2011-2014 Autronica Fire and Security AS
|
/* Copyright 2011-2014 Autronica Fire and Security AS
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
||||||
|
@ -22,23 +18,8 @@
|
||||||
#include "hsr_framereg.h"
|
#include "hsr_framereg.h"
|
||||||
#include "hsr_netlink.h"
|
#include "hsr_netlink.h"
|
||||||
|
|
||||||
|
|
||||||
struct hsr_node {
|
|
||||||
struct list_head mac_list;
|
|
||||||
unsigned char MacAddressA[ETH_ALEN];
|
|
||||||
unsigned char MacAddressB[ETH_ALEN];
|
|
||||||
/* Local slave through which AddrB frames are received from this node */
|
|
||||||
enum hsr_port_type AddrB_port;
|
|
||||||
unsigned long time_in[HSR_PT_PORTS];
|
|
||||||
bool time_in_stale[HSR_PT_PORTS];
|
|
||||||
u16 seq_out[HSR_PT_PORTS];
|
|
||||||
struct rcu_head rcu_head;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* TODO: use hash lists for mac addresses (linux/jhash.h)? */
|
/* TODO: use hash lists for mac addresses (linux/jhash.h)? */
|
||||||
|
|
||||||
|
|
||||||
/* seq_nr_after(a, b) - return true if a is after (higher in sequence than) b,
|
/* seq_nr_after(a, b) - return true if a is after (higher in sequence than) b,
|
||||||
* false otherwise.
|
* false otherwise.
|
||||||
*/
|
*/
|
||||||
|
@ -52,11 +33,11 @@ static bool seq_nr_after(u16 a, u16 b)
|
||||||
|
|
||||||
return (((s16)(b - a)) < 0);
|
return (((s16)(b - a)) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define seq_nr_before(a, b) seq_nr_after((b), (a))
|
#define seq_nr_before(a, b) seq_nr_after((b), (a))
|
||||||
#define seq_nr_after_or_eq(a, b) (!seq_nr_before((a), (b)))
|
#define seq_nr_after_or_eq(a, b) (!seq_nr_before((a), (b)))
|
||||||
#define seq_nr_before_or_eq(a, b) (!seq_nr_after((a), (b)))
|
#define seq_nr_before_or_eq(a, b) (!seq_nr_after((a), (b)))
|
||||||
|
|
||||||
|
|
||||||
bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr)
|
bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr)
|
||||||
{
|
{
|
||||||
struct hsr_node *node;
|
struct hsr_node *node;
|
||||||
|
@ -68,9 +49,9 @@ bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ether_addr_equal(addr, node->MacAddressA))
|
if (ether_addr_equal(addr, node->macaddress_A))
|
||||||
return true;
|
return true;
|
||||||
if (ether_addr_equal(addr, node->MacAddressB))
|
if (ether_addr_equal(addr, node->macaddress_B))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -78,20 +59,19 @@ bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr)
|
||||||
|
|
||||||
/* Search for mac entry. Caller must hold rcu read lock.
|
/* Search for mac entry. Caller must hold rcu read lock.
|
||||||
*/
|
*/
|
||||||
static struct hsr_node *find_node_by_AddrA(struct list_head *node_db,
|
static struct hsr_node *find_node_by_addr_A(struct list_head *node_db,
|
||||||
const unsigned char addr[ETH_ALEN])
|
const unsigned char addr[ETH_ALEN])
|
||||||
{
|
{
|
||||||
struct hsr_node *node;
|
struct hsr_node *node;
|
||||||
|
|
||||||
list_for_each_entry_rcu(node, node_db, mac_list) {
|
list_for_each_entry_rcu(node, node_db, mac_list) {
|
||||||
if (ether_addr_equal(node->MacAddressA, addr))
|
if (ether_addr_equal(node->macaddress_A, addr))
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Helper for device init; the self_node_db is used in hsr_rcv() to recognize
|
/* Helper for device init; the self_node_db is used in hsr_rcv() to recognize
|
||||||
* frames from self that's been looped over the HSR ring.
|
* frames from self that's been looped over the HSR ring.
|
||||||
*/
|
*/
|
||||||
|
@ -105,8 +85,8 @@ int hsr_create_self_node(struct list_head *self_node_db,
|
||||||
if (!node)
|
if (!node)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ether_addr_copy(node->MacAddressA, addr_a);
|
ether_addr_copy(node->macaddress_A, addr_a);
|
||||||
ether_addr_copy(node->MacAddressB, addr_b);
|
ether_addr_copy(node->macaddress_B, addr_b);
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
oldnode = list_first_or_null_rcu(self_node_db,
|
oldnode = list_first_or_null_rcu(self_node_db,
|
||||||
|
@ -137,7 +117,7 @@ void hsr_del_node(struct list_head *self_node_db)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate an hsr_node and add it to node_db. 'addr' is the node's AddressA;
|
/* Allocate an hsr_node and add it to node_db. 'addr' is the node's address_A;
|
||||||
* seq_out is used to initialize filtering of outgoing duplicate frames
|
* seq_out is used to initialize filtering of outgoing duplicate frames
|
||||||
* originating from the newly added node.
|
* originating from the newly added node.
|
||||||
*/
|
*/
|
||||||
|
@ -152,7 +132,7 @@ struct hsr_node *hsr_add_node(struct list_head *node_db, unsigned char addr[],
|
||||||
if (!node)
|
if (!node)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ether_addr_copy(node->MacAddressA, addr);
|
ether_addr_copy(node->macaddress_A, addr);
|
||||||
|
|
||||||
/* We are only interested in time diffs here, so use current jiffies
|
/* We are only interested in time diffs here, so use current jiffies
|
||||||
* as initialization. (0 could trigger an spurious ring error warning).
|
* as initialization. (0 could trigger an spurious ring error warning).
|
||||||
|
@ -184,16 +164,16 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct sk_buff *skb,
|
||||||
ethhdr = (struct ethhdr *)skb_mac_header(skb);
|
ethhdr = (struct ethhdr *)skb_mac_header(skb);
|
||||||
|
|
||||||
list_for_each_entry_rcu(node, node_db, mac_list) {
|
list_for_each_entry_rcu(node, node_db, mac_list) {
|
||||||
if (ether_addr_equal(node->MacAddressA, ethhdr->h_source))
|
if (ether_addr_equal(node->macaddress_A, ethhdr->h_source))
|
||||||
return node;
|
return node;
|
||||||
if (ether_addr_equal(node->MacAddressB, ethhdr->h_source))
|
if (ether_addr_equal(node->macaddress_B, ethhdr->h_source))
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Everyone may create a node entry, connected node to a HSR device. */
|
/* Everyone may create a node entry, connected node to a HSR device. */
|
||||||
|
|
||||||
if (ethhdr->h_proto == htons(ETH_P_PRP)
|
if (ethhdr->h_proto == htons(ETH_P_PRP) ||
|
||||||
|| ethhdr->h_proto == htons(ETH_P_HSR)) {
|
ethhdr->h_proto == htons(ETH_P_HSR)) {
|
||||||
/* Use the existing sequence_nr from the tag as starting point
|
/* Use the existing sequence_nr from the tag as starting point
|
||||||
* for filtering duplicate frames.
|
* for filtering duplicate frames.
|
||||||
*/
|
*/
|
||||||
|
@ -210,8 +190,8 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct sk_buff *skb,
|
||||||
return hsr_add_node(node_db, ethhdr->h_source, seq_out);
|
return hsr_add_node(node_db, ethhdr->h_source, seq_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use the Supervision frame's info about an eventual MacAddressB for merging
|
/* Use the Supervision frame's info about an eventual macaddress_B for merging
|
||||||
* nodes that has previously had their MacAddressB registered as a separate
|
* nodes that has previously had their macaddress_B registered as a separate
|
||||||
* node.
|
* node.
|
||||||
*/
|
*/
|
||||||
void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr,
|
void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr,
|
||||||
|
@ -237,12 +217,12 @@ void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr,
|
||||||
|
|
||||||
hsr_sp = (struct hsr_sup_payload *)skb->data;
|
hsr_sp = (struct hsr_sup_payload *)skb->data;
|
||||||
|
|
||||||
/* Merge node_curr (registered on MacAddressB) into node_real */
|
/* Merge node_curr (registered on macaddress_B) into node_real */
|
||||||
node_db = &port_rcv->hsr->node_db;
|
node_db = &port_rcv->hsr->node_db;
|
||||||
node_real = find_node_by_AddrA(node_db, hsr_sp->MacAddressA);
|
node_real = find_node_by_addr_A(node_db, hsr_sp->macaddress_A);
|
||||||
if (!node_real)
|
if (!node_real)
|
||||||
/* No frame received from AddrA of this node yet */
|
/* No frame received from AddrA of this node yet */
|
||||||
node_real = hsr_add_node(node_db, hsr_sp->MacAddressA,
|
node_real = hsr_add_node(node_db, hsr_sp->macaddress_A,
|
||||||
HSR_SEQNR_START - 1);
|
HSR_SEQNR_START - 1);
|
||||||
if (!node_real)
|
if (!node_real)
|
||||||
goto done; /* No mem */
|
goto done; /* No mem */
|
||||||
|
@ -250,17 +230,18 @@ void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr,
|
||||||
/* Node has already been merged */
|
/* Node has already been merged */
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
ether_addr_copy(node_real->MacAddressB, ethhdr->h_source);
|
ether_addr_copy(node_real->macaddress_B, ethhdr->h_source);
|
||||||
for (i = 0; i < HSR_PT_PORTS; i++) {
|
for (i = 0; i < HSR_PT_PORTS; i++) {
|
||||||
if (!node_curr->time_in_stale[i] &&
|
if (!node_curr->time_in_stale[i] &&
|
||||||
time_after(node_curr->time_in[i], node_real->time_in[i])) {
|
time_after(node_curr->time_in[i], node_real->time_in[i])) {
|
||||||
node_real->time_in[i] = node_curr->time_in[i];
|
node_real->time_in[i] = node_curr->time_in[i];
|
||||||
node_real->time_in_stale[i] = node_curr->time_in_stale[i];
|
node_real->time_in_stale[i] =
|
||||||
|
node_curr->time_in_stale[i];
|
||||||
}
|
}
|
||||||
if (seq_nr_after(node_curr->seq_out[i], node_real->seq_out[i]))
|
if (seq_nr_after(node_curr->seq_out[i], node_real->seq_out[i]))
|
||||||
node_real->seq_out[i] = node_curr->seq_out[i];
|
node_real->seq_out[i] = node_curr->seq_out[i];
|
||||||
}
|
}
|
||||||
node_real->AddrB_port = port_rcv->type;
|
node_real->addr_B_port = port_rcv->type;
|
||||||
|
|
||||||
list_del_rcu(&node_curr->mac_list);
|
list_del_rcu(&node_curr->mac_list);
|
||||||
kfree_rcu(node_curr, rcu_head);
|
kfree_rcu(node_curr, rcu_head);
|
||||||
|
@ -269,11 +250,10 @@ done:
|
||||||
skb_push(skb, sizeof(struct hsrv1_ethhdr_sp));
|
skb_push(skb, sizeof(struct hsrv1_ethhdr_sp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* 'skb' is a frame meant for this host, that is to be passed to upper layers.
|
/* 'skb' is a frame meant for this host, that is to be passed to upper layers.
|
||||||
*
|
*
|
||||||
* If the frame was sent by a node's B interface, replace the source
|
* If the frame was sent by a node's B interface, replace the source
|
||||||
* address with that node's "official" address (MacAddressA) so that upper
|
* address with that node's "official" address (macaddress_A) so that upper
|
||||||
* layers recognize where it came from.
|
* layers recognize where it came from.
|
||||||
*/
|
*/
|
||||||
void hsr_addr_subst_source(struct hsr_node *node, struct sk_buff *skb)
|
void hsr_addr_subst_source(struct hsr_node *node, struct sk_buff *skb)
|
||||||
|
@ -283,7 +263,7 @@ void hsr_addr_subst_source(struct hsr_node *node, struct sk_buff *skb)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(ð_hdr(skb)->h_source, node->MacAddressA, ETH_ALEN);
|
memcpy(ð_hdr(skb)->h_source, node->macaddress_A, ETH_ALEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 'skb' is a frame meant for another host.
|
/* 'skb' is a frame meant for another host.
|
||||||
|
@ -308,18 +288,18 @@ void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb,
|
||||||
if (!is_unicast_ether_addr(eth_hdr(skb)->h_dest))
|
if (!is_unicast_ether_addr(eth_hdr(skb)->h_dest))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
node_dst = find_node_by_AddrA(&port->hsr->node_db, eth_hdr(skb)->h_dest);
|
node_dst = find_node_by_addr_A(&port->hsr->node_db,
|
||||||
|
eth_hdr(skb)->h_dest);
|
||||||
if (!node_dst) {
|
if (!node_dst) {
|
||||||
WARN_ONCE(1, "%s: Unknown node\n", __func__);
|
WARN_ONCE(1, "%s: Unknown node\n", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (port->type != node_dst->AddrB_port)
|
if (port->type != node_dst->addr_B_port)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ether_addr_copy(eth_hdr(skb)->h_dest, node_dst->MacAddressB);
|
ether_addr_copy(eth_hdr(skb)->h_dest, node_dst->macaddress_B);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port,
|
void hsr_register_frame_in(struct hsr_node *node, struct hsr_port *port,
|
||||||
u16 sequence_nr)
|
u16 sequence_nr)
|
||||||
{
|
{
|
||||||
|
@ -352,7 +332,6 @@ int hsr_register_frame_out(struct hsr_port *port, struct hsr_node *node,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct hsr_port *get_late_port(struct hsr_priv *hsr,
|
static struct hsr_port *get_late_port(struct hsr_priv *hsr,
|
||||||
struct hsr_node *node)
|
struct hsr_node *node)
|
||||||
{
|
{
|
||||||
|
@ -373,7 +352,6 @@ static struct hsr_port *get_late_port(struct hsr_priv *hsr,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Remove stale sequence_nr records. Called by timer every
|
/* Remove stale sequence_nr records. Called by timer every
|
||||||
* HSR_LIFE_CHECK_INTERVAL (two seconds or so).
|
* HSR_LIFE_CHECK_INTERVAL (two seconds or so).
|
||||||
*/
|
*/
|
||||||
|
@ -412,23 +390,26 @@ void hsr_prune_nodes(struct timer_list *t)
|
||||||
msecs_to_jiffies(1.5 * MAX_SLAVE_DIFF))) {
|
msecs_to_jiffies(1.5 * MAX_SLAVE_DIFF))) {
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
port = get_late_port(hsr, node);
|
port = get_late_port(hsr, node);
|
||||||
if (port != NULL)
|
if (port)
|
||||||
hsr_nl_ringerror(hsr, node->MacAddressA, port);
|
hsr_nl_ringerror(hsr, node->macaddress_A, port);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prune old entries */
|
/* Prune old entries */
|
||||||
if (time_is_before_jiffies(timestamp +
|
if (time_is_before_jiffies(timestamp +
|
||||||
msecs_to_jiffies(HSR_NODE_FORGET_TIME))) {
|
msecs_to_jiffies(HSR_NODE_FORGET_TIME))) {
|
||||||
hsr_nl_nodedown(hsr, node->MacAddressA);
|
hsr_nl_nodedown(hsr, node->macaddress_A);
|
||||||
list_del_rcu(&node->mac_list);
|
list_del_rcu(&node->mac_list);
|
||||||
/* Note that we need to free this entry later: */
|
/* Note that we need to free this entry later: */
|
||||||
kfree_rcu(node, rcu_head);
|
kfree_rcu(node, rcu_head);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Restart timer */
|
||||||
|
mod_timer(&hsr->prune_timer,
|
||||||
|
jiffies + msecs_to_jiffies(PRUNE_PERIOD));
|
||||||
|
}
|
||||||
|
|
||||||
void *hsr_get_next_node(struct hsr_priv *hsr, void *_pos,
|
void *hsr_get_next_node(struct hsr_priv *hsr, void *_pos,
|
||||||
unsigned char addr[ETH_ALEN])
|
unsigned char addr[ETH_ALEN])
|
||||||
|
@ -439,20 +420,19 @@ void *hsr_get_next_node(struct hsr_priv *hsr, void *_pos,
|
||||||
node = list_first_or_null_rcu(&hsr->node_db,
|
node = list_first_or_null_rcu(&hsr->node_db,
|
||||||
struct hsr_node, mac_list);
|
struct hsr_node, mac_list);
|
||||||
if (node)
|
if (node)
|
||||||
ether_addr_copy(addr, node->MacAddressA);
|
ether_addr_copy(addr, node->macaddress_A);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = _pos;
|
node = _pos;
|
||||||
list_for_each_entry_continue_rcu(node, &hsr->node_db, mac_list) {
|
list_for_each_entry_continue_rcu(node, &hsr->node_db, mac_list) {
|
||||||
ether_addr_copy(addr, node->MacAddressA);
|
ether_addr_copy(addr, node->macaddress_A);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int hsr_get_node_data(struct hsr_priv *hsr,
|
int hsr_get_node_data(struct hsr_priv *hsr,
|
||||||
const unsigned char *addr,
|
const unsigned char *addr,
|
||||||
unsigned char addr_b[ETH_ALEN],
|
unsigned char addr_b[ETH_ALEN],
|
||||||
|
@ -466,15 +446,14 @@ int hsr_get_node_data(struct hsr_priv *hsr,
|
||||||
struct hsr_port *port;
|
struct hsr_port *port;
|
||||||
unsigned long tdiff;
|
unsigned long tdiff;
|
||||||
|
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
node = find_node_by_AddrA(&hsr->node_db, addr);
|
node = find_node_by_addr_A(&hsr->node_db, addr);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return -ENOENT; /* No such entry */
|
return -ENOENT; /* No such entry */
|
||||||
}
|
}
|
||||||
|
|
||||||
ether_addr_copy(addr_b, node->MacAddressB);
|
ether_addr_copy(addr_b, node->macaddress_B);
|
||||||
|
|
||||||
tdiff = jiffies - node->time_in[HSR_PT_SLAVE_A];
|
tdiff = jiffies - node->time_in[HSR_PT_SLAVE_A];
|
||||||
if (node->time_in_stale[HSR_PT_SLAVE_A])
|
if (node->time_in_stale[HSR_PT_SLAVE_A])
|
||||||
|
@ -500,8 +479,8 @@ int hsr_get_node_data(struct hsr_priv *hsr,
|
||||||
*if1_seq = node->seq_out[HSR_PT_SLAVE_B];
|
*if1_seq = node->seq_out[HSR_PT_SLAVE_B];
|
||||||
*if2_seq = node->seq_out[HSR_PT_SLAVE_A];
|
*if2_seq = node->seq_out[HSR_PT_SLAVE_A];
|
||||||
|
|
||||||
if (node->AddrB_port != HSR_PT_NONE) {
|
if (node->addr_B_port != HSR_PT_NONE) {
|
||||||
port = hsr_port_get_hsr(hsr, node->AddrB_port);
|
port = hsr_port_get_hsr(hsr, node->addr_B_port);
|
||||||
*addr_b_ifindex = port->dev->ifindex;
|
*addr_b_ifindex = port->dev->ifindex;
|
||||||
} else {
|
} else {
|
||||||
*addr_b_ifindex = -1;
|
*addr_b_ifindex = -1;
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/* Copyright 2011-2014 Autronica Fire and Security AS
|
/* Copyright 2011-2014 Autronica Fire and Security AS
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
||||||
|
@ -52,4 +48,16 @@ int hsr_get_node_data(struct hsr_priv *hsr,
|
||||||
int *if2_age,
|
int *if2_age,
|
||||||
u16 *if2_seq);
|
u16 *if2_seq);
|
||||||
|
|
||||||
|
struct hsr_node {
|
||||||
|
struct list_head mac_list;
|
||||||
|
unsigned char macaddress_A[ETH_ALEN];
|
||||||
|
unsigned char macaddress_B[ETH_ALEN];
|
||||||
|
/* Local slave through which AddrB frames are received from this node */
|
||||||
|
enum hsr_port_type addr_B_port;
|
||||||
|
unsigned long time_in[HSR_PT_PORTS];
|
||||||
|
bool time_in_stale[HSR_PT_PORTS];
|
||||||
|
u16 seq_out[HSR_PT_PORTS];
|
||||||
|
struct rcu_head rcu_head;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* __HSR_FRAMEREG_H */
|
#endif /* __HSR_FRAMEREG_H */
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/* Copyright 2011-2014 Autronica Fire and Security AS
|
/* Copyright 2011-2014 Autronica Fire and Security AS
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
||||||
|
@ -19,7 +15,6 @@
|
||||||
#include "hsr_framereg.h"
|
#include "hsr_framereg.h"
|
||||||
#include "hsr_slave.h"
|
#include "hsr_slave.h"
|
||||||
|
|
||||||
|
|
||||||
static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event,
|
static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event,
|
||||||
void *ptr)
|
void *ptr)
|
||||||
{
|
{
|
||||||
|
@ -31,12 +26,12 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event,
|
||||||
|
|
||||||
dev = netdev_notifier_info_to_dev(ptr);
|
dev = netdev_notifier_info_to_dev(ptr);
|
||||||
port = hsr_port_get_rtnl(dev);
|
port = hsr_port_get_rtnl(dev);
|
||||||
if (port == NULL) {
|
if (!port) {
|
||||||
if (!is_hsr_master(dev))
|
if (!is_hsr_master(dev))
|
||||||
return NOTIFY_DONE; /* Not an HSR device */
|
return NOTIFY_DONE; /* Not an HSR device */
|
||||||
hsr = netdev_priv(dev);
|
hsr = netdev_priv(dev);
|
||||||
port = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
|
port = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
|
||||||
if (port == NULL) {
|
if (!port) {
|
||||||
/* Resend of notification concerning removed device? */
|
/* Resend of notification concerning removed device? */
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +58,8 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event,
|
||||||
|
|
||||||
if (port->type == HSR_PT_SLAVE_A) {
|
if (port->type == HSR_PT_SLAVE_A) {
|
||||||
ether_addr_copy(master->dev->dev_addr, dev->dev_addr);
|
ether_addr_copy(master->dev->dev_addr, dev->dev_addr);
|
||||||
call_netdevice_notifiers(NETDEV_CHANGEADDR, master->dev);
|
call_netdevice_notifiers(NETDEV_CHANGEADDR,
|
||||||
|
master->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure we recognize frames from ourselves in hsr_rcv() */
|
/* Make sure we recognize frames from ourselves in hsr_rcv() */
|
||||||
|
@ -97,7 +93,6 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event,
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt)
|
struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt)
|
||||||
{
|
{
|
||||||
struct hsr_port *port;
|
struct hsr_port *port;
|
||||||
|
@ -112,7 +107,6 @@ static struct notifier_block hsr_nb = {
|
||||||
.notifier_call = hsr_netdev_notify, /* Slave event notifications */
|
.notifier_call = hsr_netdev_notify, /* Slave event notifications */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int __init hsr_init(void)
|
static int __init hsr_init(void)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/* Copyright 2011-2014 Autronica Fire and Security AS
|
/* Copyright 2011-2014 Autronica Fire and Security AS
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
||||||
|
@ -15,7 +11,6 @@
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
|
||||||
|
|
||||||
/* Time constants as specified in the HSR specification (IEC-62439-3 2010)
|
/* Time constants as specified in the HSR specification (IEC-62439-3 2010)
|
||||||
* Table 8.
|
* Table 8.
|
||||||
* All values in milliseconds.
|
* All values in milliseconds.
|
||||||
|
@ -24,7 +19,6 @@
|
||||||
#define HSR_NODE_FORGET_TIME 60000 /* ms */
|
#define HSR_NODE_FORGET_TIME 60000 /* ms */
|
||||||
#define HSR_ANNOUNCE_INTERVAL 100 /* ms */
|
#define HSR_ANNOUNCE_INTERVAL 100 /* ms */
|
||||||
|
|
||||||
|
|
||||||
/* By how much may slave1 and slave2 timestamps of latest received frame from
|
/* By how much may slave1 and slave2 timestamps of latest received frame from
|
||||||
* each node differ before we notify of communication problem?
|
* each node differ before we notify of communication problem?
|
||||||
*/
|
*/
|
||||||
|
@ -32,17 +26,14 @@
|
||||||
#define HSR_SEQNR_START (USHRT_MAX - 1024)
|
#define HSR_SEQNR_START (USHRT_MAX - 1024)
|
||||||
#define HSR_SUP_SEQNR_START (HSR_SEQNR_START / 2)
|
#define HSR_SUP_SEQNR_START (HSR_SEQNR_START / 2)
|
||||||
|
|
||||||
|
|
||||||
/* How often shall we check for broken ring and remove node entries older than
|
/* How often shall we check for broken ring and remove node entries older than
|
||||||
* HSR_NODE_FORGET_TIME?
|
* HSR_NODE_FORGET_TIME?
|
||||||
*/
|
*/
|
||||||
#define PRUNE_PERIOD 3000 /* ms */
|
#define PRUNE_PERIOD 3000 /* ms */
|
||||||
|
|
||||||
|
|
||||||
#define HSR_TLV_ANNOUNCE 22
|
#define HSR_TLV_ANNOUNCE 22
|
||||||
#define HSR_TLV_LIFE_CHECK 23
|
#define HSR_TLV_LIFE_CHECK 23
|
||||||
|
|
||||||
|
|
||||||
/* HSR Tag.
|
/* HSR Tag.
|
||||||
* As defined in IEC-62439-3:2010, the HSR tag is really { ethertype = 0x88FB,
|
* As defined in IEC-62439-3:2010, the HSR tag is really { ethertype = 0x88FB,
|
||||||
* path, LSDU_size, sequence Nr }. But we let eth_header() create { h_dest,
|
* path, LSDU_size, sequence Nr }. But we let eth_header() create { h_dest,
|
||||||
|
@ -83,15 +74,14 @@ static inline u16 get_hsr_tag_LSDU_size(struct hsr_tag *ht)
|
||||||
|
|
||||||
static inline void set_hsr_tag_path(struct hsr_tag *ht, u16 path)
|
static inline void set_hsr_tag_path(struct hsr_tag *ht, u16 path)
|
||||||
{
|
{
|
||||||
ht->path_and_LSDU_size = htons(
|
ht->path_and_LSDU_size =
|
||||||
(ntohs(ht->path_and_LSDU_size) & 0x0FFF) | (path << 12));
|
htons((ntohs(ht->path_and_LSDU_size) & 0x0FFF) | (path << 12));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void set_hsr_tag_LSDU_size(struct hsr_tag *ht, u16 LSDU_size)
|
static inline void set_hsr_tag_LSDU_size(struct hsr_tag *ht, u16 LSDU_size)
|
||||||
{
|
{
|
||||||
ht->path_and_LSDU_size = htons(
|
ht->path_and_LSDU_size = htons((ntohs(ht->path_and_LSDU_size) &
|
||||||
(ntohs(ht->path_and_LSDU_size) & 0xF000) |
|
0xF000) | (LSDU_size & 0x0FFF));
|
||||||
(LSDU_size & 0x0FFF));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hsr_ethhdr {
|
struct hsr_ethhdr {
|
||||||
|
@ -99,19 +89,18 @@ struct hsr_ethhdr {
|
||||||
struct hsr_tag hsr_tag;
|
struct hsr_tag hsr_tag;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
|
||||||
/* HSR Supervision Frame data types.
|
/* HSR Supervision Frame data types.
|
||||||
* Field names as defined in the IEC:2010 standard for HSR.
|
* Field names as defined in the IEC:2010 standard for HSR.
|
||||||
*/
|
*/
|
||||||
struct hsr_sup_tag {
|
struct hsr_sup_tag {
|
||||||
__be16 path_and_HSR_Ver;
|
__be16 path_and_HSR_ver;
|
||||||
__be16 sequence_nr;
|
__be16 sequence_nr;
|
||||||
__u8 HSR_TLV_Type;
|
__u8 HSR_TLV_type;
|
||||||
__u8 HSR_TLV_Length;
|
__u8 HSR_TLV_length;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct hsr_sup_payload {
|
struct hsr_sup_payload {
|
||||||
unsigned char MacAddressA[ETH_ALEN];
|
unsigned char macaddress_A[ETH_ALEN];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
static inline u16 get_hsr_stag_path(struct hsr_sup_tag *hst)
|
static inline u16 get_hsr_stag_path(struct hsr_sup_tag *hst)
|
||||||
|
@ -129,9 +118,9 @@ static inline void set_hsr_stag_path(struct hsr_sup_tag *hst, u16 path)
|
||||||
set_hsr_tag_path((struct hsr_tag *)hst, path);
|
set_hsr_tag_path((struct hsr_tag *)hst, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void set_hsr_stag_HSR_Ver(struct hsr_sup_tag *hst, u16 HSR_Ver)
|
static inline void set_hsr_stag_HSR_ver(struct hsr_sup_tag *hst, u16 HSR_ver)
|
||||||
{
|
{
|
||||||
set_hsr_tag_LSDU_size((struct hsr_tag *) hst, HSR_Ver);
|
set_hsr_tag_LSDU_size((struct hsr_tag *)hst, HSR_ver);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hsrv0_ethhdr_sp {
|
struct hsrv0_ethhdr_sp {
|
||||||
|
@ -145,7 +134,6 @@ struct hsrv1_ethhdr_sp {
|
||||||
struct hsr_sup_tag hsr_sup;
|
struct hsr_sup_tag hsr_sup;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
|
||||||
enum hsr_port_type {
|
enum hsr_port_type {
|
||||||
HSR_PT_NONE = 0, /* Must be 0, used by framereg */
|
HSR_PT_NONE = 0, /* Must be 0, used by framereg */
|
||||||
HSR_PT_SLAVE_A,
|
HSR_PT_SLAVE_A,
|
||||||
|
@ -172,9 +160,13 @@ struct hsr_priv {
|
||||||
int announce_count;
|
int announce_count;
|
||||||
u16 sequence_nr;
|
u16 sequence_nr;
|
||||||
u16 sup_sequence_nr; /* For HSRv1 separate seq_nr for supervision */
|
u16 sup_sequence_nr; /* For HSRv1 separate seq_nr for supervision */
|
||||||
u8 protVersion; /* Indicate if HSRv0 or HSRv1. */
|
u8 prot_version; /* Indicate if HSRv0 or HSRv1. */
|
||||||
spinlock_t seqnr_lock; /* locking for sequence_nr */
|
spinlock_t seqnr_lock; /* locking for sequence_nr */
|
||||||
unsigned char sup_multicast_addr[ETH_ALEN];
|
unsigned char sup_multicast_addr[ETH_ALEN];
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
struct dentry *node_tbl_root;
|
||||||
|
struct dentry *node_tbl_file;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define hsr_for_each_port(hsr, port) \
|
#define hsr_for_each_port(hsr, port) \
|
||||||
|
@ -191,4 +183,17 @@ static inline u16 hsr_get_skb_sequence_nr(struct sk_buff *skb)
|
||||||
return ntohs(hsr_ethhdr->hsr_tag.sequence_nr);
|
return ntohs(hsr_ethhdr->hsr_tag.sequence_nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_DEBUG_FS)
|
||||||
|
int hsr_prp_debugfs_init(struct hsr_priv *priv);
|
||||||
|
void hsr_prp_debugfs_term(struct hsr_priv *priv);
|
||||||
|
#else
|
||||||
|
static inline int hsr_prp_debugfs_init(struct hsr_priv *priv)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hsr_prp_debugfs_term(struct hsr_priv *priv)
|
||||||
|
{}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __HSR_PRIVATE_H */
|
#endif /* __HSR_PRIVATE_H */
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/* Copyright 2011-2014 Autronica Fire and Security AS
|
/* Copyright 2011-2014 Autronica Fire and Security AS
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
||||||
|
@ -28,7 +24,6 @@ static const struct nla_policy hsr_policy[IFLA_HSR_MAX + 1] = {
|
||||||
[IFLA_HSR_SEQ_NR] = { .type = NLA_U16 },
|
[IFLA_HSR_SEQ_NR] = { .type = NLA_U16 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Here, it seems a netdevice has already been allocated for us, and the
|
/* Here, it seems a netdevice has already been allocated for us, and the
|
||||||
* hsr_dev_setup routine has been executed. Nice!
|
* hsr_dev_setup routine has been executed. Nice!
|
||||||
*/
|
*/
|
||||||
|
@ -47,12 +42,14 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev,
|
||||||
netdev_info(dev, "HSR: Slave1 device not specified\n");
|
netdev_info(dev, "HSR: Slave1 device not specified\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
link[0] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE1]));
|
link[0] = __dev_get_by_index(src_net,
|
||||||
|
nla_get_u32(data[IFLA_HSR_SLAVE1]));
|
||||||
if (!data[IFLA_HSR_SLAVE2]) {
|
if (!data[IFLA_HSR_SLAVE2]) {
|
||||||
netdev_info(dev, "HSR: Slave2 device not specified\n");
|
netdev_info(dev, "HSR: Slave2 device not specified\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
link[1] = __dev_get_by_index(src_net, nla_get_u32(data[IFLA_HSR_SLAVE2]));
|
link[1] = __dev_get_by_index(src_net,
|
||||||
|
nla_get_u32(data[IFLA_HSR_SLAVE2]));
|
||||||
|
|
||||||
if (!link[0] || !link[1])
|
if (!link[0] || !link[1])
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -119,8 +116,6 @@ static struct rtnl_link_ops hsr_link_ops __read_mostly = {
|
||||||
.fill_info = hsr_fill_info,
|
.fill_info = hsr_fill_info,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* attribute policy */
|
/* attribute policy */
|
||||||
static const struct nla_policy hsr_genl_policy[HSR_A_MAX + 1] = {
|
static const struct nla_policy hsr_genl_policy[HSR_A_MAX + 1] = {
|
||||||
[HSR_A_NODE_ADDR] = { .len = ETH_ALEN },
|
[HSR_A_NODE_ADDR] = { .len = ETH_ALEN },
|
||||||
|
@ -138,8 +133,6 @@ static const struct genl_multicast_group hsr_mcgrps[] = {
|
||||||
{ .name = "hsr-network", },
|
{ .name = "hsr-network", },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* This is called if for some node with MAC address addr, we only get frames
|
/* This is called if for some node with MAC address addr, we only get frames
|
||||||
* over one of the slave interfaces. This would indicate an open network ring
|
* over one of the slave interfaces. This would indicate an open network ring
|
||||||
* (i.e. a link has failed somewhere).
|
* (i.e. a link has failed somewhere).
|
||||||
|
@ -156,7 +149,8 @@ void hsr_nl_ringerror(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN],
|
||||||
if (!skb)
|
if (!skb)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
msg_head = genlmsg_put(skb, 0, 0, &hsr_genl_family, 0, HSR_C_RING_ERROR);
|
msg_head = genlmsg_put(skb, 0, 0, &hsr_genl_family, 0,
|
||||||
|
HSR_C_RING_ERROR);
|
||||||
if (!msg_head)
|
if (!msg_head)
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
@ -201,7 +195,6 @@ void hsr_nl_nodedown(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN])
|
||||||
if (!msg_head)
|
if (!msg_head)
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
|
||||||
res = nla_put(skb, HSR_A_NODE_ADDR, ETH_ALEN, addr);
|
res = nla_put(skb, HSR_A_NODE_ADDR, ETH_ALEN, addr);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
@ -221,7 +214,6 @@ fail:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* HSR_C_GET_NODE_STATUS lets userspace query the internal HSR node table
|
/* HSR_C_GET_NODE_STATUS lets userspace query the internal HSR node table
|
||||||
* about the status of a specific node in the network, defined by its MAC
|
* about the status of a specific node in the network, defined by its MAC
|
||||||
* address.
|
* address.
|
||||||
|
@ -266,9 +258,7 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
|
||||||
if (!is_hsr_master(hsr_dev))
|
if (!is_hsr_master(hsr_dev))
|
||||||
goto invalid;
|
goto invalid;
|
||||||
|
|
||||||
|
|
||||||
/* Send reply */
|
/* Send reply */
|
||||||
|
|
||||||
skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
|
skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
|
||||||
if (!skb_out) {
|
if (!skb_out) {
|
||||||
res = -ENOMEM;
|
res = -ENOMEM;
|
||||||
|
@ -289,7 +279,8 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
|
||||||
|
|
||||||
hsr = netdev_priv(hsr_dev);
|
hsr = netdev_priv(hsr_dev);
|
||||||
res = hsr_get_node_data(hsr,
|
res = hsr_get_node_data(hsr,
|
||||||
(unsigned char *) nla_data(info->attrs[HSR_A_NODE_ADDR]),
|
(unsigned char *)
|
||||||
|
nla_data(info->attrs[HSR_A_NODE_ADDR]),
|
||||||
hsr_node_addr_b,
|
hsr_node_addr_b,
|
||||||
&addr_b_ifindex,
|
&addr_b_ifindex,
|
||||||
&hsr_node_if1_age,
|
&hsr_node_if1_age,
|
||||||
|
@ -310,7 +301,8 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
|
||||||
res = nla_put_u32(skb_out, HSR_A_ADDR_B_IFINDEX, addr_b_ifindex);
|
res = nla_put_u32(skb_out, HSR_A_ADDR_B_IFINDEX,
|
||||||
|
addr_b_ifindex);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
}
|
}
|
||||||
|
@ -392,9 +384,7 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
|
||||||
if (!is_hsr_master(hsr_dev))
|
if (!is_hsr_master(hsr_dev))
|
||||||
goto invalid;
|
goto invalid;
|
||||||
|
|
||||||
|
|
||||||
/* Send reply */
|
/* Send reply */
|
||||||
|
|
||||||
skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
|
skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
|
||||||
if (!skb_out) {
|
if (!skb_out) {
|
||||||
res = -ENOMEM;
|
res = -ENOMEM;
|
||||||
|
@ -444,7 +434,6 @@ fail:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const struct genl_ops hsr_ops[] = {
|
static const struct genl_ops hsr_ops[] = {
|
||||||
{
|
{
|
||||||
.cmd = HSR_C_GET_NODE_STATUS,
|
.cmd = HSR_C_GET_NODE_STATUS,
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/* Copyright 2011-2014 Autronica Fire and Security AS
|
/* Copyright 2011-2014 Autronica Fire and Security AS
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
||||||
|
|
120
net/hsr/hsr_prp_debugfs.c
Normal file
120
net/hsr/hsr_prp_debugfs.c
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* hsr_prp_debugfs code
|
||||||
|
* Copyright (C) 2017 Texas Instruments Incorporated
|
||||||
|
*
|
||||||
|
* Author(s):
|
||||||
|
* Murali Karicheri <m-karicheri2@ti.com?
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation version 2.
|
||||||
|
*
|
||||||
|
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||||
|
* kind, whether express or implied; without even the implied warranty
|
||||||
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/debugfs.h>
|
||||||
|
#include "hsr_main.h"
|
||||||
|
#include "hsr_framereg.h"
|
||||||
|
|
||||||
|
static void print_mac_address(struct seq_file *sfp, unsigned char *mac)
|
||||||
|
{
|
||||||
|
seq_printf(sfp, "%02x:%02x:%02x:%02x:%02x:%02x:",
|
||||||
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hsr_prp_node_table_show - Formats and prints node_table entries */
|
||||||
|
static int
|
||||||
|
hsr_prp_node_table_show(struct seq_file *sfp, void *data)
|
||||||
|
{
|
||||||
|
struct hsr_priv *priv = (struct hsr_priv *)sfp->private;
|
||||||
|
struct hsr_node *node;
|
||||||
|
|
||||||
|
seq_puts(sfp, "Node Table entries\n");
|
||||||
|
seq_puts(sfp, "MAC-Address-A, MAC-Address-B, time_in[A], ");
|
||||||
|
seq_puts(sfp, "time_in[B], Address-B port\n");
|
||||||
|
rcu_read_lock();
|
||||||
|
list_for_each_entry_rcu(node, &priv->node_db, mac_list) {
|
||||||
|
/* skip self node */
|
||||||
|
if (hsr_addr_is_self(priv, node->macaddress_A))
|
||||||
|
continue;
|
||||||
|
print_mac_address(sfp, &node->macaddress_A[0]);
|
||||||
|
seq_puts(sfp, " ");
|
||||||
|
print_mac_address(sfp, &node->macaddress_B[0]);
|
||||||
|
seq_printf(sfp, "0x%lx, ", node->time_in[HSR_PT_SLAVE_A]);
|
||||||
|
seq_printf(sfp, "0x%lx ", node->time_in[HSR_PT_SLAVE_B]);
|
||||||
|
seq_printf(sfp, "0x%x\n", node->addr_B_port);
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hsr_prp_node_table_open - Open the node_table file
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This routine opens a debugfs file node_table of specific hsr device
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
hsr_prp_node_table_open(struct inode *inode, struct file *filp)
|
||||||
|
{
|
||||||
|
return single_open(filp, hsr_prp_node_table_show, inode->i_private);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations hsr_prp_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = hsr_prp_node_table_open,
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* hsr_prp_debugfs_init - create hsr-prp node_table file for dumping
|
||||||
|
* the node table
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* When debugfs is configured this routine sets up the node_table file per
|
||||||
|
* hsr/prp device for dumping the node_table entries
|
||||||
|
*/
|
||||||
|
int hsr_prp_debugfs_init(struct hsr_priv *priv)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
struct dentry *de = NULL;
|
||||||
|
|
||||||
|
de = debugfs_create_dir("hsr", NULL);
|
||||||
|
if (!de) {
|
||||||
|
pr_err("Cannot create hsr-prp debugfs root\n");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->node_tbl_root = de;
|
||||||
|
|
||||||
|
de = debugfs_create_file("node_table", S_IFREG | 0444,
|
||||||
|
priv->node_tbl_root, priv,
|
||||||
|
&hsr_prp_fops);
|
||||||
|
if (!de) {
|
||||||
|
pr_err("Cannot create hsr-prp node_table directory\n");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
priv->node_tbl_file = de;
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hsr_prp_debugfs_term - Tear down debugfs intrastructure
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* When Debufs is configured this routine removes debugfs file system
|
||||||
|
* elements that are specific to hsr-prp
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
hsr_prp_debugfs_term(struct hsr_priv *priv)
|
||||||
|
{
|
||||||
|
debugfs_remove(priv->node_tbl_file);
|
||||||
|
priv->node_tbl_file = NULL;
|
||||||
|
debugfs_remove(priv->node_tbl_root);
|
||||||
|
priv->node_tbl_root = NULL;
|
||||||
|
}
|
|
@ -1,9 +1,5 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/* Copyright 2011-2014 Autronica Fire and Security AS
|
/* Copyright 2011-2014 Autronica Fire and Security AS
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
*
|
||||||
* Author(s):
|
* Author(s):
|
||||||
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
||||||
|
@ -18,7 +14,6 @@
|
||||||
#include "hsr_forward.h"
|
#include "hsr_forward.h"
|
||||||
#include "hsr_framereg.h"
|
#include "hsr_framereg.h"
|
||||||
|
|
||||||
|
|
||||||
static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb)
|
static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb = *pskb;
|
struct sk_buff *skb = *pskb;
|
||||||
|
@ -61,12 +56,11 @@ bool hsr_port_exists(const struct net_device *dev)
|
||||||
return rcu_access_pointer(dev->rx_handler) == hsr_handle_frame;
|
return rcu_access_pointer(dev->rx_handler) == hsr_handle_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int hsr_check_dev_ok(struct net_device *dev)
|
static int hsr_check_dev_ok(struct net_device *dev)
|
||||||
{
|
{
|
||||||
/* Don't allow HSR on non-ethernet like devices */
|
/* Don't allow HSR on non-ethernet like devices */
|
||||||
if ((dev->flags & IFF_LOOPBACK) || (dev->type != ARPHRD_ETHER) ||
|
if ((dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER ||
|
||||||
(dev->addr_len != ETH_ALEN)) {
|
dev->addr_len != ETH_ALEN) {
|
||||||
netdev_info(dev, "Cannot use loopback or non-ethernet device as HSR slave.\n");
|
netdev_info(dev, "Cannot use loopback or non-ethernet device as HSR slave.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -99,7 +93,6 @@ static int hsr_check_dev_ok(struct net_device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Setup device to be added to the HSR bridge. */
|
/* Setup device to be added to the HSR bridge. */
|
||||||
static int hsr_portdev_setup(struct net_device *dev, struct hsr_port *port)
|
static int hsr_portdev_setup(struct net_device *dev, struct hsr_port *port)
|
||||||
{
|
{
|
||||||
|
@ -143,11 +136,11 @@ int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
port = hsr_port_get_hsr(hsr, type);
|
port = hsr_port_get_hsr(hsr, type);
|
||||||
if (port != NULL)
|
if (port)
|
||||||
return -EBUSY; /* This port already exists */
|
return -EBUSY; /* This port already exists */
|
||||||
|
|
||||||
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
||||||
if (port == NULL)
|
if (!port)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (type != HSR_PT_MASTER) {
|
if (type != HSR_PT_MASTER) {
|
||||||
|
@ -184,7 +177,7 @@ void hsr_del_port(struct hsr_port *port)
|
||||||
list_del_rcu(&port->port_list);
|
list_del_rcu(&port->port_list);
|
||||||
|
|
||||||
if (port != master) {
|
if (port != master) {
|
||||||
if (master != NULL) {
|
if (master) {
|
||||||
netdev_update_features(master->dev);
|
netdev_update_features(master->dev);
|
||||||
dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
|
dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/* Copyright 2011-2014 Autronica Fire and Security AS
|
/* Copyright 2011-2014 Autronica Fire and Security AS
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation; either version 2 of the License, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* Author(s):
|
|
||||||
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
* 2011-2014 Arvid Brodin, arvid.brodin@alten.se
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue