4568 lines · 112.4 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * drivers/net/macsec.c - MACsec device * * Copyright (c) 2015 Sabrina Dubroca <sd@queasysnail.net> */ #include <linux/types.h>#include <linux/skbuff.h>#include <linux/socket.h>#include <linux/module.h>#include <crypto/aead.h>#include <linux/etherdevice.h>#include <linux/netdevice.h>#include <linux/rtnetlink.h>#include <linux/refcount.h>#include <net/genetlink.h>#include <net/sock.h>#include <net/gro_cells.h>#include <net/macsec.h>#include <net/dst_metadata.h>#include <net/netdev_lock.h>#include <linux/phy.h>#include <linux/byteorder/generic.h>#include <linux/if_arp.h> #include <uapi/linux/if_macsec.h> static struct workqueue_struct *macsec_wq; /* SecTAG length = macsec_eth_header without the optional SCI */#define MACSEC_TAG_LEN 6 struct macsec_eth_header {	struct ethhdr eth;	/* SecTAG */	u8  tci_an;#if defined(__LITTLE_ENDIAN_BITFIELD)	u8  short_length:6,		  unused:2;#elif defined(__BIG_ENDIAN_BITFIELD)	u8        unused:2,	    short_length:6;#else#error	"Please fix <asm/byteorder.h>"#endif	__be32 packet_number;	u8 secure_channel_id[8]; /* optional */} __packed; /* minimum secure data length deemed "not short", see IEEE 802.1AE-2006 9.7 */#define MIN_NON_SHORT_LEN 48 #define GCM_AES_IV_LEN 12 #define for_each_rxsc(secy, sc)				\	for (sc = rcu_dereference_bh(secy->rx_sc);	\	     sc;					\	     sc = rcu_dereference_bh(sc->next))#define for_each_rxsc_rtnl(secy, sc)			\	for (sc = rtnl_dereference(secy->rx_sc);	\	     sc;					\	     sc = rtnl_dereference(sc->next)) #define pn_same_half(pn1, pn2) (!(((pn1) >> 31) ^ ((pn2) >> 31))) struct gcm_iv_xpn {	union {		u8 short_secure_channel_id[4];		ssci_t ssci;	};	__be64 pn;} __packed; struct gcm_iv {	union {		u8 secure_channel_id[8];		sci_t sci;	};	__be32 pn;}; #define MACSEC_VALIDATE_DEFAULT MACSEC_VALIDATE_STRICT struct pcpu_secy_stats {	struct macsec_dev_stats stats;	struct u64_stats_sync syncp;}; /** * struct macsec_dev - private data * @secy: SecY config * @real_dev: pointer to underlying netdevice * @dev_tracker: refcount tracker for @real_dev reference * @stats: MACsec device stats * @secys: linked list of SecY's on the underlying device * @gro_cells: pointer to the Generic Receive Offload cell * @offload: status of offloading on the MACsec device * @insert_tx_tag: when offloading, device requires to insert an *	additional tag */struct macsec_dev {	struct macsec_secy secy;	struct net_device *real_dev;	netdevice_tracker dev_tracker;	struct pcpu_secy_stats __percpu *stats;	struct list_head secys;	struct gro_cells gro_cells;	enum macsec_offload offload;	bool insert_tx_tag;}; /** * struct macsec_rxh_data - rx_handler private argument * @secys: linked list of SecY's on this underlying device */struct macsec_rxh_data {	struct list_head secys;}; static struct macsec_dev *macsec_priv(const struct net_device *dev){	return (struct macsec_dev *)netdev_priv(dev);} static struct macsec_rxh_data *macsec_data_rcu(const struct net_device *dev){	return rcu_dereference_bh(dev->rx_handler_data);} static struct macsec_rxh_data *macsec_data_rtnl(const struct net_device *dev){	return rtnl_dereference(dev->rx_handler_data);} struct macsec_cb {	struct aead_request *req;	union {		struct macsec_tx_sa *tx_sa;		struct macsec_rx_sa *rx_sa;	};	u8 assoc_num;	bool valid;	bool has_sci;}; static struct macsec_rx_sa *macsec_rxsa_get(struct macsec_rx_sa __rcu *ptr){	struct macsec_rx_sa *sa = rcu_dereference_bh(ptr); 	if (!sa || !sa->active)		return NULL; 	if (!refcount_inc_not_zero(&sa->refcnt))		return NULL; 	return sa;} static void free_rx_sc_rcu(struct rcu_head *head){	struct macsec_rx_sc *rx_sc = container_of(head, struct macsec_rx_sc, rcu_head); 	free_percpu(rx_sc->stats);	kfree(rx_sc);} static struct macsec_rx_sc *macsec_rxsc_get(struct macsec_rx_sc *sc){	return refcount_inc_not_zero(&sc->refcnt) ? sc : NULL;} static void macsec_rxsc_put(struct macsec_rx_sc *sc){	if (refcount_dec_and_test(&sc->refcnt))		call_rcu(&sc->rcu_head, free_rx_sc_rcu);} static void free_rxsa_work(struct work_struct *work){	struct macsec_rx_sa *sa =		container_of(to_rcu_work(work), struct macsec_rx_sa, destroy_work); 	crypto_free_aead(sa->key.tfm);	free_percpu(sa->stats);	kfree(sa);} static void macsec_rxsa_put(struct macsec_rx_sa *sa){	if (refcount_dec_and_test(&sa->refcnt))		queue_rcu_work(macsec_wq, &sa->destroy_work);} static struct macsec_tx_sa *macsec_txsa_get(struct macsec_tx_sa __rcu *ptr){	struct macsec_tx_sa *sa = rcu_dereference_bh(ptr); 	if (!sa || !sa->active)		return NULL; 	if (!refcount_inc_not_zero(&sa->refcnt))		return NULL; 	return sa;} static void free_txsa_work(struct work_struct *work){	struct macsec_tx_sa *sa =		container_of(to_rcu_work(work), struct macsec_tx_sa, destroy_work); 	crypto_free_aead(sa->key.tfm);	free_percpu(sa->stats);	kfree(sa);} static void macsec_txsa_put(struct macsec_tx_sa *sa){	if (refcount_dec_and_test(&sa->refcnt))		queue_rcu_work(macsec_wq, &sa->destroy_work);} static struct macsec_cb *macsec_skb_cb(struct sk_buff *skb){	BUILD_BUG_ON(sizeof(struct macsec_cb) > sizeof(skb->cb));	return (struct macsec_cb *)skb->cb;} #define MACSEC_PORT_SCB (0x0000)#define MACSEC_UNDEF_SCI ((__force sci_t)0xffffffffffffffffULL)#define MACSEC_UNDEF_SSCI ((__force ssci_t)0xffffffff) #define MACSEC_GCM_AES_128_SAK_LEN 16#define MACSEC_GCM_AES_256_SAK_LEN 32 #define DEFAULT_SAK_LEN MACSEC_GCM_AES_128_SAK_LEN#define DEFAULT_XPN false#define DEFAULT_SEND_SCI true#define DEFAULT_ENCRYPT false#define DEFAULT_ENCODING_SA 0#define MACSEC_XPN_MAX_REPLAY_WINDOW (((1 << 30) - 1)) static sci_t make_sci(const u8 *addr, __be16 port){	sci_t sci; 	memcpy(&sci, addr, ETH_ALEN);	memcpy(((char *)&sci) + ETH_ALEN, &port, sizeof(port)); 	return sci;} static sci_t macsec_active_sci(struct macsec_secy *secy){	struct macsec_rx_sc *rx_sc = rcu_dereference_bh(secy->rx_sc); 	/* Case single RX SC */	if (rx_sc && !rcu_dereference_bh(rx_sc->next))		return (rx_sc->active) ? rx_sc->sci : 0;	/* Case no RX SC or multiple */	else		return 0;} static sci_t macsec_frame_sci(struct macsec_eth_header *hdr, bool sci_present,			      struct macsec_rxh_data *rxd){	struct macsec_dev *macsec;	sci_t sci = 0; 	/* SC = 1 */	if (sci_present) {		memcpy(&sci, hdr->secure_channel_id,		       sizeof(hdr->secure_channel_id));	/* SC = 0; ES = 0 */	} else if ((!(hdr->tci_an & (MACSEC_TCI_ES | MACSEC_TCI_SC))) &&		   (list_is_singular(&rxd->secys))) {		/* Only one SECY should exist on this scenario */		macsec = list_first_or_null_rcu(&rxd->secys, struct macsec_dev,						secys);		if (macsec)			return macsec_active_sci(&macsec->secy);	} else {		sci = make_sci(hdr->eth.h_source, MACSEC_PORT_ES);	} 	return sci;} static unsigned int macsec_sectag_len(bool sci_present){	return MACSEC_TAG_LEN + (sci_present ? MACSEC_SCI_LEN : 0);} static unsigned int macsec_hdr_len(bool sci_present){	return macsec_sectag_len(sci_present) + ETH_HLEN;} static unsigned int macsec_extra_len(bool sci_present){	return macsec_sectag_len(sci_present) + sizeof(__be16);} /* Fill SecTAG according to IEEE 802.1AE-2006 10.5.3 */static void macsec_fill_sectag(struct macsec_eth_header *h,			       const struct macsec_secy *secy, u32 pn,			       bool sci_present){	const struct macsec_tx_sc *tx_sc = &secy->tx_sc; 	memset(&h->tci_an, 0, macsec_sectag_len(sci_present));	h->eth.h_proto = htons(ETH_P_MACSEC); 	if (sci_present) {		h->tci_an |= MACSEC_TCI_SC;		memcpy(&h->secure_channel_id, &secy->sci,		       sizeof(h->secure_channel_id));	} else {		if (tx_sc->end_station)			h->tci_an |= MACSEC_TCI_ES;		if (tx_sc->scb)			h->tci_an |= MACSEC_TCI_SCB;	} 	h->packet_number = htonl(pn); 	/* with GCM, C/E clear for !encrypt, both set for encrypt */	if (tx_sc->encrypt)		h->tci_an |= MACSEC_TCI_CONFID;	else if (secy->icv_len != MACSEC_DEFAULT_ICV_LEN)		h->tci_an |= MACSEC_TCI_C; 	h->tci_an |= tx_sc->encoding_sa;} static void macsec_set_shortlen(struct macsec_eth_header *h, size_t data_len){	if (data_len < MIN_NON_SHORT_LEN)		h->short_length = data_len;} /* Checks if a MACsec interface is being offloaded to an hardware engine */static bool macsec_is_offloaded(struct macsec_dev *macsec){	if (macsec->offload == MACSEC_OFFLOAD_MAC ||	    macsec->offload == MACSEC_OFFLOAD_PHY)		return true; 	return false;} /* Checks if underlying layers implement MACsec offloading functions. */static bool macsec_check_offload(enum macsec_offload offload,				 struct macsec_dev *macsec){	if (!macsec || !macsec->real_dev)		return false; 	if (offload == MACSEC_OFFLOAD_PHY)		return macsec->real_dev->phydev &&		       macsec->real_dev->phydev->macsec_ops;	else if (offload == MACSEC_OFFLOAD_MAC)		return macsec->real_dev->features & NETIF_F_HW_MACSEC &&		       macsec->real_dev->macsec_ops; 	return false;} static const struct macsec_ops *__macsec_get_ops(enum macsec_offload offload,						 struct macsec_dev *macsec,						 struct macsec_context *ctx){	if (ctx) {		memset(ctx, 0, sizeof(*ctx));		ctx->offload = offload; 		if (offload == MACSEC_OFFLOAD_PHY)			ctx->phydev = macsec->real_dev->phydev;		else if (offload == MACSEC_OFFLOAD_MAC)			ctx->netdev = macsec->real_dev;	} 	if (offload == MACSEC_OFFLOAD_PHY)		return macsec->real_dev->phydev->macsec_ops;	else		return macsec->real_dev->macsec_ops;} /* Returns a pointer to the MACsec ops struct if any and updates the MACsec * context device reference if provided. */static const struct macsec_ops *macsec_get_ops(struct macsec_dev *macsec,					       struct macsec_context *ctx){	if (!macsec_check_offload(macsec->offload, macsec))		return NULL; 	return __macsec_get_ops(macsec->offload, macsec, ctx);} /* validate MACsec packet according to IEEE 802.1AE-2018 9.12 */static bool macsec_validate_skb(struct sk_buff *skb, u16 icv_len, bool xpn){	struct macsec_eth_header *h = (struct macsec_eth_header *)skb->data;	int len = skb->len - 2 * ETH_ALEN;	int extra_len = macsec_extra_len(!!(h->tci_an & MACSEC_TCI_SC)) + icv_len; 	/* a) It comprises at least 17 octets */	if (skb->len <= 16)		return false; 	/* b) MACsec EtherType: already checked */ 	/* c) V bit is clear */	if (h->tci_an & MACSEC_TCI_VERSION)		return false; 	/* d) ES or SCB => !SC */	if ((h->tci_an & MACSEC_TCI_ES || h->tci_an & MACSEC_TCI_SCB) &&	    (h->tci_an & MACSEC_TCI_SC))		return false; 	/* e) Bits 7 and 8 of octet 4 of the SecTAG are clear */	if (h->unused)		return false; 	/* rx.pn != 0 if not XPN (figure 10-5 with 802.11AEbw-2013 amendment) */	if (!h->packet_number && !xpn)		return false; 	/* length check, f) g) h) i) */	if (h->short_length)		return len == extra_len + h->short_length;	return len >= extra_len + MIN_NON_SHORT_LEN;} #define MACSEC_NEEDED_HEADROOM (macsec_extra_len(true))#define MACSEC_NEEDED_TAILROOM MACSEC_STD_ICV_LEN static void macsec_fill_iv_xpn(unsigned char *iv, ssci_t ssci, u64 pn,			       salt_t salt){	struct gcm_iv_xpn *gcm_iv = (struct gcm_iv_xpn *)iv; 	gcm_iv->ssci = ssci ^ salt.ssci;	gcm_iv->pn = cpu_to_be64(pn) ^ salt.pn;} static void macsec_fill_iv(unsigned char *iv, sci_t sci, u32 pn){	struct gcm_iv *gcm_iv = (struct gcm_iv *)iv; 	gcm_iv->sci = sci;	gcm_iv->pn = htonl(pn);} static struct macsec_eth_header *macsec_ethhdr(struct sk_buff *skb){	return (struct macsec_eth_header *)skb_mac_header(skb);} static void __macsec_pn_wrapped(struct macsec_secy *secy,				struct macsec_tx_sa *tx_sa){	pr_debug("PN wrapped, transitioning to !oper\n");	tx_sa->active = false;	if (secy->protect_frames)		secy->operational = false;} void macsec_pn_wrapped(struct macsec_secy *secy, struct macsec_tx_sa *tx_sa){	spin_lock_bh(&tx_sa->lock);	__macsec_pn_wrapped(secy, tx_sa);	spin_unlock_bh(&tx_sa->lock);}EXPORT_SYMBOL_GPL(macsec_pn_wrapped); static pn_t tx_sa_update_pn(struct macsec_tx_sa *tx_sa,			    struct macsec_secy *secy){	pn_t pn; 	spin_lock_bh(&tx_sa->lock); 	pn = tx_sa->next_pn_halves;	if (secy->xpn)		tx_sa->next_pn++;	else		tx_sa->next_pn_halves.lower++; 	if (tx_sa->next_pn == 0)		__macsec_pn_wrapped(secy, tx_sa);	spin_unlock_bh(&tx_sa->lock); 	return pn;} 

Lines 1–500 of 4568.