linux-stable/include/net/macsec.h
Radu Pirea (NXP OSS) 0412cc846a net: macsec: indicate next pn update when offloading
Indicate next PN update using update_pn flag in macsec_context.
Offloaded MACsec implementations does not know whether or not the
MACSEC_SA_ATTR_PN attribute was passed for an SA update and assume
that next PN should always updated, but this is not always true.

The PN can be reset to its initial value using the following command:
$ ip macsec set macsec0 tx sa 0 off #octeontx2-pf case

Or, the update PN command will succeed even if the driver does not support
PN updates.
$ ip macsec set macsec0 tx sa 0 pn 1 on #mscc phy driver case

Comparing the initial PN with the new PN value is not a solution. When
the user updates the PN using its initial value the command will
succeed, even if the driver does not support it. Like this:
$ ip macsec add macsec0 tx sa 0 pn 1 on key 00 \
ead3664f508eb06c40ac7104cdae4ce5
$ ip macsec set macsec0 tx sa 0 pn 1 on #mlx5 case

Signed-off-by: Radu Pirea (NXP OSS) <radu-nicolae.pirea@oss.nxp.com>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2023-10-10 10:30:30 +02:00

328 lines
8 KiB
C

/* SPDX-License-Identifier: GPL-2.0+ */
/*
* MACsec netdev header, used for h/w accelerated implementations.
*
* Copyright (c) 2015 Sabrina Dubroca <sd@queasysnail.net>
*/
#ifndef _NET_MACSEC_H_
#define _NET_MACSEC_H_
#include <linux/u64_stats_sync.h>
#include <linux/if_vlan.h>
#include <uapi/linux/if_link.h>
#include <uapi/linux/if_macsec.h>
#define MACSEC_DEFAULT_PN_LEN 4
#define MACSEC_XPN_PN_LEN 8
#define MACSEC_NUM_AN 4 /* 2 bits for the association number */
#define MACSEC_SCI_LEN 8
#define MACSEC_PORT_ES (htons(0x0001))
#define MACSEC_TCI_VERSION 0x80
#define MACSEC_TCI_ES 0x40 /* end station */
#define MACSEC_TCI_SC 0x20 /* SCI present */
#define MACSEC_TCI_SCB 0x10 /* epon */
#define MACSEC_TCI_E 0x08 /* encryption */
#define MACSEC_TCI_C 0x04 /* changed text */
#define MACSEC_AN_MASK 0x03 /* association number */
#define MACSEC_TCI_CONFID (MACSEC_TCI_E | MACSEC_TCI_C)
#define MACSEC_DEFAULT_ICV_LEN 16
typedef u64 __bitwise sci_t;
typedef u32 __bitwise ssci_t;
struct metadata_dst;
typedef union salt {
struct {
u32 ssci;
u64 pn;
} __packed;
u8 bytes[MACSEC_SALT_LEN];
} __packed salt_t;
typedef union pn {
struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
u32 lower;
u32 upper;
#elif defined(__BIG_ENDIAN_BITFIELD)
u32 upper;
u32 lower;
#else
#error "Please fix <asm/byteorder.h>"
#endif
};
u64 full64;
} pn_t;
/**
* struct macsec_key - SA key
* @id: user-provided key identifier
* @tfm: crypto struct, key storage
* @salt: salt used to generate IV in XPN cipher suites
*/
struct macsec_key {
u8 id[MACSEC_KEYID_LEN];
struct crypto_aead *tfm;
salt_t salt;
};
struct macsec_rx_sc_stats {
__u64 InOctetsValidated;
__u64 InOctetsDecrypted;
__u64 InPktsUnchecked;
__u64 InPktsDelayed;
__u64 InPktsOK;
__u64 InPktsInvalid;
__u64 InPktsLate;
__u64 InPktsNotValid;
__u64 InPktsNotUsingSA;
__u64 InPktsUnusedSA;
};
struct macsec_rx_sa_stats {
__u32 InPktsOK;
__u32 InPktsInvalid;
__u32 InPktsNotValid;
__u32 InPktsNotUsingSA;
__u32 InPktsUnusedSA;
};
struct macsec_tx_sa_stats {
__u32 OutPktsProtected;
__u32 OutPktsEncrypted;
};
struct macsec_tx_sc_stats {
__u64 OutPktsProtected;
__u64 OutPktsEncrypted;
__u64 OutOctetsProtected;
__u64 OutOctetsEncrypted;
};
struct macsec_dev_stats {
__u64 OutPktsUntagged;
__u64 InPktsUntagged;
__u64 OutPktsTooLong;
__u64 InPktsNoTag;
__u64 InPktsBadTag;
__u64 InPktsUnknownSCI;
__u64 InPktsNoSCI;
__u64 InPktsOverrun;
};
/**
* struct macsec_rx_sa - receive secure association
* @active:
* @next_pn: packet number expected for the next packet
* @lock: protects next_pn manipulations
* @key: key structure
* @ssci: short secure channel identifier
* @stats: per-SA stats
*/
struct macsec_rx_sa {
struct macsec_key key;
ssci_t ssci;
spinlock_t lock;
union {
pn_t next_pn_halves;
u64 next_pn;
};
refcount_t refcnt;
bool active;
struct macsec_rx_sa_stats __percpu *stats;
struct macsec_rx_sc *sc;
struct rcu_head rcu;
};
struct pcpu_rx_sc_stats {
struct macsec_rx_sc_stats stats;
struct u64_stats_sync syncp;
};
struct pcpu_tx_sc_stats {
struct macsec_tx_sc_stats stats;
struct u64_stats_sync syncp;
};
/**
* struct macsec_rx_sc - receive secure channel
* @sci: secure channel identifier for this SC
* @active: channel is active
* @sa: array of secure associations
* @stats: per-SC stats
*/
struct macsec_rx_sc {
struct macsec_rx_sc __rcu *next;
sci_t sci;
bool active;
struct macsec_rx_sa __rcu *sa[MACSEC_NUM_AN];
struct pcpu_rx_sc_stats __percpu *stats;
refcount_t refcnt;
struct rcu_head rcu_head;
};
/**
* struct macsec_tx_sa - transmit secure association
* @active:
* @next_pn: packet number to use for the next packet
* @lock: protects next_pn manipulations
* @key: key structure
* @ssci: short secure channel identifier
* @stats: per-SA stats
*/
struct macsec_tx_sa {
struct macsec_key key;
ssci_t ssci;
spinlock_t lock;
union {
pn_t next_pn_halves;
u64 next_pn;
};
refcount_t refcnt;
bool active;
struct macsec_tx_sa_stats __percpu *stats;
struct rcu_head rcu;
};
/**
* struct macsec_tx_sc - transmit secure channel
* @active:
* @encoding_sa: association number of the SA currently in use
* @encrypt: encrypt packets on transmit, or authenticate only
* @send_sci: always include the SCI in the SecTAG
* @end_station:
* @scb: single copy broadcast flag
* @sa: array of secure associations
* @stats: stats for this TXSC
* @md_dst: MACsec offload metadata dst
*/
struct macsec_tx_sc {
bool active;
u8 encoding_sa;
bool encrypt;
bool send_sci;
bool end_station;
bool scb;
struct macsec_tx_sa __rcu *sa[MACSEC_NUM_AN];
struct pcpu_tx_sc_stats __percpu *stats;
struct metadata_dst *md_dst;
};
/**
* struct macsec_secy - MACsec Security Entity
* @netdev: netdevice for this SecY
* @n_rx_sc: number of receive secure channels configured on this SecY
* @sci: secure channel identifier used for tx
* @key_len: length of keys used by the cipher suite
* @icv_len: length of ICV used by the cipher suite
* @validate_frames: validation mode
* @xpn: enable XPN for this SecY
* @operational: MAC_Operational flag
* @protect_frames: enable protection for this SecY
* @replay_protect: enable packet number checks on receive
* @replay_window: size of the replay window
* @tx_sc: transmit secure channel
* @rx_sc: linked list of receive secure channels
*/
struct macsec_secy {
struct net_device *netdev;
unsigned int n_rx_sc;
sci_t sci;
u16 key_len;
u16 icv_len;
enum macsec_validation_type validate_frames;
bool xpn;
bool operational;
bool protect_frames;
bool replay_protect;
u32 replay_window;
struct macsec_tx_sc tx_sc;
struct macsec_rx_sc __rcu *rx_sc;
};
/**
* struct macsec_context - MACsec context for hardware offloading
*/
struct macsec_context {
union {
struct net_device *netdev;
struct phy_device *phydev;
};
enum macsec_offload offload;
struct macsec_secy *secy;
struct macsec_rx_sc *rx_sc;
struct {
bool update_pn;
unsigned char assoc_num;
u8 key[MACSEC_MAX_KEY_LEN];
union {
struct macsec_rx_sa *rx_sa;
struct macsec_tx_sa *tx_sa;
};
} sa;
union {
struct macsec_tx_sc_stats *tx_sc_stats;
struct macsec_tx_sa_stats *tx_sa_stats;
struct macsec_rx_sc_stats *rx_sc_stats;
struct macsec_rx_sa_stats *rx_sa_stats;
struct macsec_dev_stats *dev_stats;
} stats;
};
/**
* struct macsec_ops - MACsec offloading operations
*/
struct macsec_ops {
/* Device wide */
int (*mdo_dev_open)(struct macsec_context *ctx);
int (*mdo_dev_stop)(struct macsec_context *ctx);
/* SecY */
int (*mdo_add_secy)(struct macsec_context *ctx);
int (*mdo_upd_secy)(struct macsec_context *ctx);
int (*mdo_del_secy)(struct macsec_context *ctx);
/* Security channels */
int (*mdo_add_rxsc)(struct macsec_context *ctx);
int (*mdo_upd_rxsc)(struct macsec_context *ctx);
int (*mdo_del_rxsc)(struct macsec_context *ctx);
/* Security associations */
int (*mdo_add_rxsa)(struct macsec_context *ctx);
int (*mdo_upd_rxsa)(struct macsec_context *ctx);
int (*mdo_del_rxsa)(struct macsec_context *ctx);
int (*mdo_add_txsa)(struct macsec_context *ctx);
int (*mdo_upd_txsa)(struct macsec_context *ctx);
int (*mdo_del_txsa)(struct macsec_context *ctx);
/* Statistics */
int (*mdo_get_dev_stats)(struct macsec_context *ctx);
int (*mdo_get_tx_sc_stats)(struct macsec_context *ctx);
int (*mdo_get_tx_sa_stats)(struct macsec_context *ctx);
int (*mdo_get_rx_sc_stats)(struct macsec_context *ctx);
int (*mdo_get_rx_sa_stats)(struct macsec_context *ctx);
};
void macsec_pn_wrapped(struct macsec_secy *secy, struct macsec_tx_sa *tx_sa);
static inline bool macsec_send_sci(const struct macsec_secy *secy)
{
const struct macsec_tx_sc *tx_sc = &secy->tx_sc;
return tx_sc->send_sci ||
(secy->n_rx_sc > 1 && !tx_sc->end_station && !tx_sc->scb);
}
struct net_device *macsec_get_real_dev(const struct net_device *dev);
bool macsec_netdev_is_offloaded(struct net_device *dev);
static inline void *macsec_netdev_priv(const struct net_device *dev)
{
#if IS_ENABLED(CONFIG_VLAN_8021Q)
if (is_vlan_dev(dev))
return netdev_priv(vlan_dev_priv(dev)->real_dev);
#endif
return netdev_priv(dev);
}
#endif /* _NET_MACSEC_H_ */