2019-04-05 20:31:34 +03:00
// SPDX-License-Identifier: GPL-2.0
2014-07-05 01:41:03 +04:00
/* Copyright 2011-2014 Autronica Fire and Security AS
*
* Author ( s ) :
* 2011 - 2014 Arvid Brodin , arvid . brodin @ alten . se
2020-07-22 17:40:16 +03:00
*
* Frame router for HSR and PRP .
2014-07-05 01:41:03 +04:00
*/
# include "hsr_forward.h"
# include <linux/types.h>
# include <linux/skbuff.h>
# include <linux/etherdevice.h>
# include <linux/if_vlan.h>
# include "hsr_main.h"
# include "hsr_framereg.h"
struct hsr_node ;
/* The uses I can see for these HSR supervision frames are:
* 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
* the other node ' s counter has been reset for some reason .
* - -
* Or not - resetting the counter and bridging the frame would create a
* loop , unfortunately .
*
* 2 ) Use the LifeCheck frames to detect ring breaks . I . e . if no LifeCheck
* frame is received from a particular node , we know something is wrong .
* We just register these ( as with normal frames ) and throw them away .
*
* 3 ) Allow different MAC addresses for the two slave interfaces , using the
* MacAddressA field .
*/
static bool is_supervision_frame ( struct hsr_priv * hsr , struct sk_buff * skb )
{
2019-04-05 20:31:32 +03:00
struct ethhdr * eth_hdr ;
struct hsr_sup_tag * hsr_sup_tag ;
struct hsrv1_ethhdr_sp * hsr_V1_hdr ;
2014-07-05 01:41:03 +04:00
WARN_ON_ONCE ( ! skb_mac_header_was_set ( skb ) ) ;
2019-04-05 20:31:32 +03:00
eth_hdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
2014-07-05 01:41:03 +04:00
2016-04-13 14:52:22 +03:00
/* Correct addr? */
2019-04-05 20:31:32 +03:00
if ( ! ether_addr_equal ( eth_hdr - > h_dest ,
2014-07-05 01:41:03 +04:00
hsr - > sup_multicast_addr ) )
return false ;
2016-04-13 14:52:22 +03:00
/* Correct ether type?. */
2019-04-05 20:31:32 +03:00
if ( ! ( eth_hdr - > h_proto = = htons ( ETH_P_PRP ) | |
eth_hdr - > h_proto = = htons ( ETH_P_HSR ) ) )
2014-07-05 01:41:03 +04:00
return false ;
2016-04-13 14:52:22 +03:00
/* Get the supervision header from correct location. */
2019-04-05 20:31:32 +03:00
if ( eth_hdr - > h_proto = = htons ( ETH_P_HSR ) ) { /* Okay HSRv1. */
hsr_V1_hdr = ( struct hsrv1_ethhdr_sp * ) skb_mac_header ( skb ) ;
if ( hsr_V1_hdr - > hsr . encap_proto ! = htons ( ETH_P_PRP ) )
2016-04-13 14:52:22 +03:00
return false ;
2019-04-05 20:31:32 +03:00
hsr_sup_tag = & hsr_V1_hdr - > hsr_sup ;
2016-04-13 14:52:22 +03:00
} else {
2019-04-05 20:31:32 +03:00
hsr_sup_tag =
2019-04-05 20:31:29 +03:00
& ( ( struct hsrv0_ethhdr_sp * ) skb_mac_header ( skb ) ) - > hsr_sup ;
2016-04-13 14:52:22 +03:00
}
2019-04-05 20:31:32 +03:00
if ( hsr_sup_tag - > HSR_TLV_type ! = HSR_TLV_ANNOUNCE & &
2020-07-22 17:40:19 +03:00
hsr_sup_tag - > HSR_TLV_type ! = HSR_TLV_LIFE_CHECK & &
hsr_sup_tag - > HSR_TLV_type ! = PRP_TLV_LIFE_CHECK_DD & &
hsr_sup_tag - > HSR_TLV_type ! = PRP_TLV_LIFE_CHECK_DA )
2014-07-05 01:41:03 +04:00
return false ;
2019-04-05 20:31:32 +03:00
if ( hsr_sup_tag - > HSR_TLV_length ! = 12 & &
hsr_sup_tag - > HSR_TLV_length ! = sizeof ( struct hsr_sup_payload ) )
2014-07-05 01:41:03 +04:00
return false ;
return true ;
}
2020-07-22 17:40:21 +03:00
static struct sk_buff * create_stripped_skb_hsr ( struct sk_buff * skb_in ,
struct hsr_frame_info * frame )
2014-07-05 01:41:03 +04:00
{
struct sk_buff * skb ;
int copylen ;
unsigned char * dst , * src ;
skb_pull ( skb_in , HSR_HLEN ) ;
skb = __pskb_copy ( skb_in , skb_headroom ( skb_in ) - HSR_HLEN , GFP_ATOMIC ) ;
skb_push ( skb_in , HSR_HLEN ) ;
2019-04-05 20:31:28 +03:00
if ( ! skb )
2014-07-05 01:41:03 +04:00
return NULL ;
skb_reset_mac_header ( skb ) ;
if ( skb - > ip_summed = = CHECKSUM_PARTIAL )
skb - > csum_start - = HSR_HLEN ;
2019-04-05 20:31:31 +03:00
copylen = 2 * ETH_ALEN ;
2014-07-05 01:41:03 +04:00
if ( frame - > is_vlan )
copylen + = VLAN_HLEN ;
src = skb_mac_header ( skb_in ) ;
dst = skb_mac_header ( skb ) ;
memcpy ( dst , src , copylen ) ;
skb - > protocol = eth_hdr ( skb ) - > h_proto ;
return skb ;
}
2020-07-22 17:40:20 +03:00
struct sk_buff * hsr_get_untagged_frame ( struct hsr_frame_info * frame ,
struct hsr_port * port )
2014-07-05 01:41:03 +04:00
{
2020-07-22 17:40:21 +03:00
if ( ! frame - > skb_std ) {
if ( frame - > skb_hsr ) {
frame - > skb_std =
create_stripped_skb_hsr ( frame - > skb_hsr , frame ) ;
} else {
/* Unexpected */
WARN_ONCE ( 1 , " %s:%d: Unexpected frame received (port_src %s) \n " ,
__FILE__ , __LINE__ , port - > dev - > name ) ;
return NULL ;
}
}
2014-07-05 01:41:03 +04:00
return skb_clone ( frame - > skb_std , GFP_ATOMIC ) ;
}
2020-07-22 17:40:21 +03:00
struct sk_buff * prp_get_untagged_frame ( struct hsr_frame_info * frame ,
struct hsr_port * port )
{
if ( ! frame - > skb_std ) {
if ( frame - > skb_prp ) {
/* trim the skb by len - HSR_HLEN to exclude RCT */
skb_trim ( frame - > skb_prp ,
frame - > skb_prp - > len - HSR_HLEN ) ;
frame - > skb_std =
__pskb_copy ( frame - > skb_prp ,
skb_headroom ( frame - > skb_prp ) ,
GFP_ATOMIC ) ;
} else {
/* Unexpected */
WARN_ONCE ( 1 , " %s:%d: Unexpected frame received (port_src %s) \n " ,
__FILE__ , __LINE__ , port - > dev - > name ) ;
return NULL ;
}
}
return skb_clone ( frame - > skb_std , GFP_ATOMIC ) ;
}
static void prp_set_lan_id ( struct prp_rct * trailer ,
struct hsr_port * port )
{
int lane_id ;
if ( port - > type = = HSR_PT_SLAVE_A )
lane_id = 0 ;
else
lane_id = 1 ;
/* Add net_id in the upper 3 bits of lane_id */
lane_id | = port - > hsr - > net_id ;
set_prp_lan_id ( trailer , lane_id ) ;
}
/* Tailroom for PRP rct should have been created before calling this */
static struct sk_buff * prp_fill_rct ( struct sk_buff * skb ,
struct hsr_frame_info * frame ,
struct hsr_port * port )
{
struct prp_rct * trailer ;
int min_size = ETH_ZLEN ;
int lsdu_size ;
if ( ! skb )
return skb ;
if ( frame - > is_vlan )
min_size = VLAN_ETH_ZLEN ;
if ( skb_put_padto ( skb , min_size ) )
return NULL ;
trailer = ( struct prp_rct * ) skb_put ( skb , HSR_HLEN ) ;
lsdu_size = skb - > len - 14 ;
if ( frame - > is_vlan )
lsdu_size - = 4 ;
prp_set_lan_id ( trailer , port ) ;
set_prp_LSDU_size ( trailer , lsdu_size ) ;
trailer - > sequence_nr = htons ( frame - > sequence_nr ) ;
trailer - > PRP_suffix = htons ( ETH_P_PRP ) ;
return skb ;
}
static void hsr_set_path_id ( struct hsr_ethhdr * hsr_ethhdr ,
struct hsr_port * port )
{
int path_id ;
if ( port - > type = = HSR_PT_SLAVE_A )
path_id = 0 ;
else
path_id = 1 ;
set_hsr_tag_path ( & hsr_ethhdr - > hsr_tag , path_id ) ;
}
2020-07-20 19:43:27 +03:00
static struct sk_buff * hsr_fill_tag ( struct sk_buff * skb ,
struct hsr_frame_info * frame ,
struct hsr_port * port , u8 proto_version )
2014-07-05 01:41:03 +04:00
{
struct hsr_ethhdr * hsr_ethhdr ;
int lsdu_size ;
2020-07-17 17:55:09 +03:00
/* pad to minimum packet size which is 60 + 6 (HSR tag) */
2020-07-20 19:43:27 +03:00
if ( skb_put_padto ( skb , ETH_ZLEN + HSR_HLEN ) )
return NULL ;
2020-07-17 17:55:09 +03:00
2014-07-05 01:41:03 +04:00
lsdu_size = skb - > len - 14 ;
if ( frame - > is_vlan )
lsdu_size - = 4 ;
2019-04-05 20:31:29 +03:00
hsr_ethhdr = ( struct hsr_ethhdr * ) skb_mac_header ( skb ) ;
2014-07-05 01:41:03 +04:00
2020-07-22 17:40:21 +03:00
hsr_set_path_id ( hsr_ethhdr , port ) ;
2014-07-05 01:41:03 +04:00
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 . encap_proto = hsr_ethhdr - > ethhdr . h_proto ;
2019-04-05 20:31:32 +03:00
hsr_ethhdr - > ethhdr . h_proto = htons ( proto_version ?
2016-04-13 14:52:22 +03:00
ETH_P_HSR : ETH_P_PRP ) ;
2020-07-20 19:43:27 +03:00
return skb ;
2014-07-05 01:41:03 +04:00
}
2020-07-22 17:40:21 +03:00
/* If the original frame was an HSR tagged frame, just clone it to be sent
* unchanged . Otherwise , create a private frame especially tagged for ' port ' .
*/
struct sk_buff * hsr_create_tagged_frame ( struct hsr_frame_info * frame ,
struct hsr_port * port )
2014-07-05 01:41:03 +04:00
{
unsigned char * dst , * src ;
struct sk_buff * skb ;
2020-07-22 17:40:21 +03:00
int movelen ;
if ( frame - > skb_hsr ) {
struct hsr_ethhdr * hsr_ethhdr =
( struct hsr_ethhdr * ) skb_mac_header ( frame - > skb_hsr ) ;
/* set the lane id properly */
hsr_set_path_id ( hsr_ethhdr , port ) ;
return skb_clone ( frame - > skb_hsr , GFP_ATOMIC ) ;
}
2014-07-05 01:41:03 +04:00
/* Create the new skb with enough headroom to fit the HSR tag */
2020-07-22 17:40:21 +03:00
skb = __pskb_copy ( frame - > skb_std ,
skb_headroom ( frame - > skb_std ) + HSR_HLEN , GFP_ATOMIC ) ;
2019-04-05 20:31:28 +03:00
if ( ! skb )
2014-07-05 01:41:03 +04:00
return NULL ;
skb_reset_mac_header ( skb ) ;
if ( skb - > ip_summed = = CHECKSUM_PARTIAL )
skb - > csum_start + = HSR_HLEN ;
movelen = ETH_HLEN ;
if ( frame - > is_vlan )
movelen + = VLAN_HLEN ;
src = skb_mac_header ( skb ) ;
dst = skb_push ( skb , HSR_HLEN ) ;
memmove ( dst , src , movelen ) ;
skb_reset_mac_header ( skb ) ;
2020-07-20 19:43:27 +03:00
/* skb_put_padto free skb on error and hsr_fill_tag returns NULL in
* that case
*/
return hsr_fill_tag ( skb , frame , port , port - > hsr - > prot_version ) ;
2014-07-05 01:41:03 +04:00
}
2020-07-22 17:40:21 +03:00
struct sk_buff * prp_create_tagged_frame ( struct hsr_frame_info * frame ,
2020-07-22 17:40:20 +03:00
struct hsr_port * port )
2014-07-05 01:41:03 +04:00
{
2020-07-22 17:40:21 +03:00
struct sk_buff * skb ;
2014-07-05 01:41:03 +04:00
2020-07-22 17:40:21 +03:00
if ( frame - > skb_prp ) {
struct prp_rct * trailer = skb_get_PRP_rct ( frame - > skb_prp ) ;
if ( trailer ) {
prp_set_lan_id ( trailer , port ) ;
} else {
WARN_ONCE ( ! trailer , " errored PRP skb " ) ;
return NULL ;
}
return skb_clone ( frame - > skb_prp , GFP_ATOMIC ) ;
2014-07-05 01:41:03 +04:00
}
2020-07-22 17:40:21 +03:00
skb = skb_copy_expand ( frame - > skb_std , 0 ,
skb_tailroom ( frame - > skb_std ) + HSR_HLEN ,
GFP_ATOMIC ) ;
prp_fill_rct ( skb , frame , port ) ;
return skb ;
2014-07-05 01:41:03 +04:00
}
static void hsr_deliver_master ( struct sk_buff * skb , struct net_device * dev ,
struct hsr_node * node_src )
{
bool was_multicast_frame ;
int res ;
was_multicast_frame = ( skb - > pkt_type = = PACKET_MULTICAST ) ;
hsr_addr_subst_source ( node_src , skb ) ;
skb_pull ( skb , ETH_HLEN ) ;
res = netif_rx ( skb ) ;
if ( res = = NET_RX_DROP ) {
dev - > stats . rx_dropped + + ;
} else {
dev - > stats . rx_packets + + ;
dev - > stats . rx_bytes + = skb - > len ;
if ( was_multicast_frame )
dev - > stats . multicast + + ;
}
}
static int hsr_xmit ( struct sk_buff * skb , struct hsr_port * port ,
struct hsr_frame_info * frame )
{
if ( frame - > port_rcv - > type = = HSR_PT_MASTER ) {
hsr_addr_subst_dest ( frame - > node_src , skb , port ) ;
/* Address substitution (IEC62439-3 pp 26, 50): replace mac
* address of outgoing frame with that of the outgoing slave ' s .
*/
ether_addr_copy ( eth_hdr ( skb ) - > h_source , port - > dev - > dev_addr ) ;
}
return dev_queue_xmit ( skb ) ;
}
2020-07-22 17:40:21 +03:00
bool prp_drop_frame ( struct hsr_frame_info * frame , struct hsr_port * port )
{
return ( ( frame - > port_rcv - > type = = HSR_PT_SLAVE_A & &
port - > type = = HSR_PT_SLAVE_B ) | |
( frame - > port_rcv - > type = = HSR_PT_SLAVE_B & &
port - > type = = HSR_PT_SLAVE_A ) ) ;
}
2014-07-05 01:41:03 +04:00
/* Forward the frame through all devices except:
* - Back through the receiving device
* - If it ' s a HSR frame : through a device where it has passed before
2020-07-22 17:40:21 +03:00
* - if it ' s a PRP frame : through another PRP slave device ( no bridge )
2014-07-05 01:41:03 +04:00
* - To the local HSR master only if the frame is directly addressed to it , or
* a non - supervision multicast or broadcast frame .
*
* HSR slave devices should insert a HSR tag into the frame , or forward the
* frame unchanged if it ' s already tagged . Interlink devices should strip HSR
* tags if they ' re of the non - HSR type ( but only after duplicate discard ) . The
* master device always strips HSR tags .
*/
static void hsr_forward_do ( struct hsr_frame_info * frame )
{
struct hsr_port * port ;
struct sk_buff * skb ;
hsr_for_each_port ( frame - > port_rcv - > hsr , port ) {
2020-07-22 17:40:20 +03:00
struct hsr_priv * hsr = port - > hsr ;
2014-07-05 01:41:03 +04:00
/* Don't send frame back the way it came */
if ( port = = frame - > port_rcv )
continue ;
/* Don't deliver locally unless we should */
2019-04-05 20:31:25 +03:00
if ( port - > type = = HSR_PT_MASTER & & ! frame - > is_local_dest )
2014-07-05 01:41:03 +04:00
continue ;
/* Deliver frames directly addressed to us to master only */
2019-04-05 20:31:25 +03:00
if ( port - > type ! = HSR_PT_MASTER & & frame - > is_local_exclusive )
2014-07-05 01:41:03 +04:00
continue ;
2020-07-22 17:40:21 +03:00
/* Don't send frame over port where it has been sent before.
* Also fro SAN , this shouldn ' t be done .
*/
if ( ! frame - > is_from_san & &
hsr_register_frame_out ( port , frame - > node_src ,
2014-07-05 01:41:03 +04:00
frame - > sequence_nr ) )
continue ;
2019-04-05 20:31:25 +03:00
if ( frame - > is_supervision & & port - > type = = HSR_PT_MASTER ) {
2020-07-22 17:40:21 +03:00
hsr_handle_sup_frame ( frame ) ;
2014-07-05 01:41:03 +04:00
continue ;
}
2020-07-22 17:40:21 +03:00
/* Check if frame is to be dropped. Eg. for PRP no forward
* between ports .
*/
if ( hsr - > proto_ops - > drop_frame & &
hsr - > proto_ops - > drop_frame ( frame , port ) )
continue ;
2014-07-05 01:41:03 +04:00
if ( port - > type ! = HSR_PT_MASTER )
2020-07-22 17:40:20 +03:00
skb = hsr - > proto_ops - > create_tagged_frame ( frame , port ) ;
2014-07-05 01:41:03 +04:00
else
2020-07-22 17:40:20 +03:00
skb = hsr - > proto_ops - > get_untagged_frame ( frame , port ) ;
2019-04-05 20:31:28 +03:00
if ( ! skb ) {
2020-07-22 17:40:21 +03:00
frame - > port_rcv - > dev - > stats . rx_dropped + + ;
2014-07-05 01:41:03 +04:00
continue ;
}
skb - > dev = port - > dev ;
if ( port - > type = = HSR_PT_MASTER )
hsr_deliver_master ( skb , port - > dev , frame - > node_src ) ;
else
hsr_xmit ( skb , port , frame ) ;
}
}
static void check_local_dest ( struct hsr_priv * hsr , struct sk_buff * skb ,
struct hsr_frame_info * frame )
{
if ( hsr_addr_is_self ( hsr , eth_hdr ( skb ) - > h_dest ) ) {
frame - > is_local_exclusive = true ;
skb - > pkt_type = PACKET_HOST ;
} else {
frame - > is_local_exclusive = false ;
}
2019-04-05 20:31:25 +03:00
if ( skb - > pkt_type = = PACKET_HOST | |
skb - > pkt_type = = PACKET_MULTICAST | |
skb - > pkt_type = = PACKET_BROADCAST ) {
2014-07-05 01:41:03 +04:00
frame - > is_local_dest = true ;
} else {
frame - > is_local_dest = false ;
}
}
2020-07-22 17:40:21 +03:00
static void handle_std_frame ( struct sk_buff * skb ,
struct hsr_frame_info * frame )
2014-07-05 01:41:03 +04:00
{
2020-07-22 17:40:21 +03:00
struct hsr_port * port = frame - > port_rcv ;
struct hsr_priv * hsr = port - > hsr ;
2014-07-05 01:41:03 +04:00
unsigned long irqflags ;
2020-07-22 17:40:21 +03:00
frame - > skb_hsr = NULL ;
frame - > skb_prp = NULL ;
frame - > skb_std = skb ;
if ( port - > type ! = HSR_PT_MASTER ) {
frame - > is_from_san = true ;
2020-07-22 17:40:20 +03:00
} else {
/* Sequence nr for the master node */
spin_lock_irqsave ( & hsr - > seqnr_lock , irqflags ) ;
frame - > sequence_nr = hsr - > sequence_nr ;
hsr - > sequence_nr + + ;
spin_unlock_irqrestore ( & hsr - > seqnr_lock , irqflags ) ;
}
}
2020-07-22 17:40:21 +03:00
void hsr_fill_frame_info ( __be16 proto , struct sk_buff * skb ,
struct hsr_frame_info * frame )
{
if ( proto = = htons ( ETH_P_PRP ) | |
proto = = htons ( ETH_P_HSR ) ) {
/* 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 ;
}
/* Standard frame or PRP from master port */
handle_std_frame ( skb , frame ) ;
}
void 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 ) ;
if ( rct & &
prp_check_lsdu_size ( skb , rct , frame - > is_supervision ) ) {
frame - > skb_hsr = NULL ;
frame - > skb_std = NULL ;
frame - > skb_prp = skb ;
frame - > sequence_nr = prp_get_skb_sequence_nr ( rct ) ;
return ;
}
handle_std_frame ( skb , frame ) ;
}
2020-07-22 17:40:20 +03:00
static int fill_frame_info ( struct hsr_frame_info * frame ,
struct sk_buff * skb , struct hsr_port * port )
{
struct hsr_priv * hsr = port - > hsr ;
2020-07-22 17:40:21 +03:00
struct hsr_vlan_ethhdr * vlan_hdr ;
2020-07-22 17:40:20 +03:00
struct ethhdr * ethhdr ;
__be16 proto ;
2020-07-22 17:40:21 +03:00
memset ( frame , 0 , sizeof ( * frame ) ) ;
2014-07-05 01:41:03 +04:00
frame - > is_supervision = is_supervision_frame ( port - > hsr , skb ) ;
2020-07-22 17:40:21 +03:00
frame - > node_src = hsr_get_node ( port , & hsr - > node_db , skb ,
frame - > is_supervision ,
port - > type ) ;
2019-04-05 20:31:28 +03:00
if ( ! frame - > node_src )
2014-07-05 01:41:03 +04:00
return - 1 ; /* Unknown node and !is_supervision, or no mem */
2019-04-05 20:31:29 +03:00
ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
2014-07-05 01:41:03 +04:00
frame - > is_vlan = false ;
2020-07-22 17:40:21 +03:00
proto = ethhdr - > h_proto ;
if ( proto = = htons ( ETH_P_8021Q ) )
2014-07-05 01:41:03 +04:00
frame - > is_vlan = true ;
2020-07-22 17:40:21 +03:00
if ( frame - > is_vlan ) {
vlan_hdr = ( struct hsr_vlan_ethhdr * ) ethhdr ;
proto = vlan_hdr - > vlanhdr . h_vlan_encapsulated_proto ;
2014-07-05 01:41:03 +04:00
/* FIXME: */
2020-05-06 18:47:45 +03:00
netdev_warn_once ( skb - > dev , " VLAN not yet supported " ) ;
2014-07-05 01:41:03 +04:00
}
2020-07-22 17:40:21 +03:00
frame - > is_from_san = false ;
2014-07-05 01:41:03 +04:00
frame - > port_rcv = port ;
2020-07-22 17:40:20 +03:00
hsr - > proto_ops - > fill_frame_info ( proto , skb , frame ) ;
2020-07-22 17:40:21 +03:00
check_local_dest ( port - > hsr , skb , frame ) ;
2014-07-05 01:41:03 +04:00
return 0 ;
}
/* Must be called holding rcu read lock (because of the port parameter) */
void hsr_forward_skb ( struct sk_buff * skb , struct hsr_port * port )
{
struct hsr_frame_info frame ;
if ( skb_mac_header ( skb ) ! = skb - > data ) {
WARN_ONCE ( 1 , " %s:%d: Malformed frame (port_src %s) \n " ,
__FILE__ , __LINE__ , port - > dev - > name ) ;
goto out_drop ;
}
2020-07-22 17:40:20 +03:00
if ( fill_frame_info ( & frame , skb , port ) < 0 )
2014-07-05 01:41:03 +04:00
goto out_drop ;
2020-07-22 17:40:21 +03:00
2014-07-05 01:41:03 +04:00
hsr_register_frame_in ( frame . node_src , port , frame . sequence_nr ) ;
hsr_forward_do ( & frame ) ;
2019-04-15 18:36:03 +03:00
/* Gets called for ingress frames as well as egress from master port.
* So check and increment stats for master port only here .
*/
if ( port - > type = = HSR_PT_MASTER ) {
port - > dev - > stats . tx_packets + + ;
port - > dev - > stats . tx_bytes + = skb - > len ;
}
2014-07-05 01:41:03 +04:00
2020-07-18 15:53:38 +03:00
kfree_skb ( frame . skb_hsr ) ;
2020-07-22 17:40:21 +03:00
kfree_skb ( frame . skb_prp ) ;
2020-07-18 15:53:38 +03:00
kfree_skb ( frame . skb_std ) ;
2014-07-05 01:41:03 +04:00
return ;
out_drop :
port - > dev - > stats . tx_dropped + + ;
kfree_skb ( skb ) ;
}