3527 lines · 84.7 KB · C
RawDownload
/* * drivers/net/macsec.c - MACsec device * * Copyright (c) 2015 Sabrina Dubroca <sd@queasysnail.net> * * 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. */ #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/rtnetlink.h>#include <net/genetlink.h>#include <net/sock.h>#include <net/gro_cells.h> #include <uapi/linux/if_macsec.h> typedef u64 __bitwise sci_t; #define MACSEC_SCI_LEN 8 /* 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; #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) /* 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 DEFAULT_ICV_LEN 16 #define MACSEC_NUM_AN 4 /* 2 bits for the association number */ #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)) struct gcm_iv {	union {		u8 secure_channel_id[8];		sci_t sci;	};	__be32 pn;}; /** * struct macsec_key - SA key * @id: user-provided key identifier * @tfm: crypto struct, key storage */struct macsec_key {	u8 id[MACSEC_KEYID_LEN];	struct crypto_aead *tfm;}; 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 * @stats: per-SA stats */struct macsec_rx_sa {	struct macsec_key key;	spinlock_t lock;	u32 next_pn;	atomic_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 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;	atomic_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 * @stats: per-SA stats */struct macsec_tx_sa {	struct macsec_key key;	spinlock_t lock;	u32 next_pn;	atomic_t refcnt;	bool active;	struct macsec_tx_sa_stats __percpu *stats;	struct rcu_head rcu;}; struct pcpu_tx_sc_stats {	struct macsec_tx_sc_stats stats;	struct u64_stats_sync syncp;}; /** * 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 */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;}; #define MACSEC_VALIDATE_DEFAULT MACSEC_VALIDATE_STRICT /** * 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 * @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 operational;	bool protect_frames;	bool replay_protect;	u32 replay_window;	struct macsec_tx_sc tx_sc;	struct macsec_rx_sc __rcu *rx_sc;}; 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 * @stats: MACsec device stats * @secys: linked list of SecY's on the underlying device */struct macsec_dev {	struct macsec_secy secy;	struct net_device *real_dev;	struct pcpu_secy_stats __percpu *stats;	struct list_head secys;	struct gro_cells gro_cells;	unsigned int nest_level;}; /** * 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 (!atomic_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 atomic_inc_not_zero(&sc->refcnt) ? sc : NULL;} static void macsec_rxsc_put(struct macsec_rx_sc *sc){	if (atomic_dec_and_test(&sc->refcnt))		call_rcu(&sc->rcu_head, free_rx_sc_rcu);} static void free_rxsa(struct rcu_head *head){	struct macsec_rx_sa *sa = container_of(head, struct macsec_rx_sa, rcu); 	crypto_free_aead(sa->key.tfm);	free_percpu(sa->stats);	kfree(sa);} static void macsec_rxsa_put(struct macsec_rx_sa *sa){	if (atomic_dec_and_test(&sa->refcnt))		call_rcu(&sa->rcu, free_rxsa);} 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 (!atomic_inc_not_zero(&sa->refcnt))		return NULL; 	return sa;} static void free_txsa(struct rcu_head *head){	struct macsec_tx_sa *sa = container_of(head, struct macsec_tx_sa, rcu); 	crypto_free_aead(sa->key.tfm);	free_percpu(sa->stats);	kfree(sa);} static void macsec_txsa_put(struct macsec_tx_sa *sa){	if (atomic_dec_and_test(&sa->refcnt))		call_rcu(&sa->rcu, free_txsa);} 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_ES (htons(0x0001))#define MACSEC_PORT_SCB (0x0000)#define MACSEC_UNDEF_SCI ((__force sci_t)0xffffffffffffffffULL) #define DEFAULT_SAK_LEN 16#define DEFAULT_SEND_SCI true#define DEFAULT_ENCRYPT false#define DEFAULT_ENCODING_SA 0 static bool 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);} static sci_t make_sci(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_frame_sci(struct macsec_eth_header *hdr, bool sci_present){	sci_t sci; 	if (sci_present)		memcpy(&sci, hdr->secure_channel_id,		       sizeof(hdr->secure_channel_id));	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 != 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;} /* validate MACsec packet according to IEEE 802.1AE-2006 9.12 */static bool macsec_validate_skb(struct sk_buff *skb, u16 icv_len){	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; 

Lines 1–500 of 3527.