root/net/bridge/br_private_cfm.h
/* SPDX-License-Identifier: GPL-2.0-or-later */

#ifndef _BR_PRIVATE_CFM_H_
#define _BR_PRIVATE_CFM_H_

#include "br_private.h"
#include <uapi/linux/cfm_bridge.h>

struct br_cfm_mep_create {
        enum br_cfm_domain domain; /* Domain for this MEP */
        enum br_cfm_mep_direction direction; /* Up or Down MEP direction */
        u32 ifindex; /* Residence port */
};

int br_cfm_mep_create(struct net_bridge *br,
                      const u32 instance,
                      struct br_cfm_mep_create *const create,
                      struct netlink_ext_ack *extack);

int br_cfm_mep_delete(struct net_bridge *br,
                      const u32 instance,
                      struct netlink_ext_ack *extack);

struct br_cfm_mep_config {
        u32 mdlevel;
        u32 mepid; /* MEPID for this MEP */
        struct mac_addr unicast_mac; /* The MEP unicast MAC */
};

int br_cfm_mep_config_set(struct net_bridge *br,
                          const u32 instance,
                          const struct br_cfm_mep_config *const config,
                          struct netlink_ext_ack *extack);

struct br_cfm_maid {
        u8 data[CFM_MAID_LENGTH];
};

struct br_cfm_cc_config {
        /* Expected received CCM PDU MAID. */
        struct br_cfm_maid exp_maid;

        /* Expected received CCM PDU interval. */
        /* Transmitting CCM PDU interval when CCM tx is enabled. */
        enum br_cfm_ccm_interval exp_interval;

        bool enable; /* Enable/disable CCM PDU handling */
};

int br_cfm_cc_config_set(struct net_bridge *br,
                         const u32 instance,
                         const struct br_cfm_cc_config *const config,
                         struct netlink_ext_ack *extack);

int br_cfm_cc_peer_mep_add(struct net_bridge *br, const u32 instance,
                           u32 peer_mep_id,
                           struct netlink_ext_ack *extack);
int br_cfm_cc_peer_mep_remove(struct net_bridge *br, const u32 instance,
                              u32 peer_mep_id,
                              struct netlink_ext_ack *extack);

/* Transmitted CCM Remote Defect Indication status set.
 * This RDI is inserted in transmitted CCM PDUs if CCM transmission is enabled.
 * See br_cfm_cc_ccm_tx() with interval != BR_CFM_CCM_INTERVAL_NONE
 */
int br_cfm_cc_rdi_set(struct net_bridge *br, const u32 instance,
                      const bool rdi, struct netlink_ext_ack *extack);

/* OAM PDU Tx information */
struct br_cfm_cc_ccm_tx_info {
        struct mac_addr dmac;
        /* The CCM will be transmitted for this period in seconds.
         * Call br_cfm_cc_ccm_tx before timeout to keep transmission alive.
         * When period is zero any ongoing transmission will be stopped.
         */
        u32 period;

        bool seq_no_update; /* Update Tx CCM sequence number */
        bool if_tlv; /* Insert Interface Status TLV */
        u8 if_tlv_value; /* Interface Status TLV value */
        bool port_tlv; /* Insert Port Status TLV */
        u8 port_tlv_value; /* Port Status TLV value */
        /* Sender ID TLV ??
         * Organization-Specific TLV ??
         */
};

int br_cfm_cc_ccm_tx(struct net_bridge *br, const u32 instance,
                     const struct br_cfm_cc_ccm_tx_info *const tx_info,
                     struct netlink_ext_ack *extack);

struct br_cfm_mep_status {
        /* Indications that an OAM PDU has been seen. */
        bool opcode_unexp_seen; /* RX of OAM PDU with unexpected opcode */
        bool version_unexp_seen; /* RX of OAM PDU with unexpected version */
        bool rx_level_low_seen; /* Rx of OAM PDU with level low */
};

struct br_cfm_cc_peer_status {
        /* This CCM related status is based on the latest received CCM PDU. */
        u8 port_tlv_value; /* Port Status TLV value */
        u8 if_tlv_value; /* Interface Status TLV value */

        /* CCM has not been received for 3.25 intervals */
        u8 ccm_defect:1;

        /* (RDI == 1) for last received CCM PDU */
        u8 rdi:1;

        /* Indications that a CCM PDU has been seen. */
        u8 seen:1; /* CCM PDU received */
        u8 tlv_seen:1; /* CCM PDU with TLV received */
        /* CCM PDU with unexpected sequence number received */
        u8 seq_unexp_seen:1;
};

struct br_cfm_mep {
        /* list header of MEP instances */
        struct hlist_node               head;
        u32                             instance;
        struct br_cfm_mep_create        create;
        struct br_cfm_mep_config        config;
        struct br_cfm_cc_config         cc_config;
        struct br_cfm_cc_ccm_tx_info    cc_ccm_tx_info;
        /* List of multiple peer MEPs */
        struct hlist_head               peer_mep_list;
        struct net_bridge_port __rcu    *b_port;
        unsigned long                   ccm_tx_end;
        struct delayed_work             ccm_tx_dwork;
        u32                             ccm_tx_snumber;
        u32                             ccm_rx_snumber;
        struct br_cfm_mep_status        status;
        bool                            rdi;
        struct rcu_head                 rcu;
};

struct br_cfm_peer_mep {
        struct hlist_node               head;
        struct br_cfm_mep               *mep;
        struct delayed_work             ccm_rx_dwork;
        u32                             mepid;
        struct br_cfm_cc_peer_status    cc_status;
        u32                             ccm_rx_count_miss;
        struct rcu_head                 rcu;
};

#endif /* _BR_PRIVATE_CFM_H_ */