--- zzzz-none-000/linux-4.9.279/drivers/net/macsec.c 2021-08-08 06:38:54.000000000 +0000 +++ puma7-arm-6591-750/linux-4.9.279/drivers/net/macsec.c 2023-02-08 10:58:13.000000000 +0000 @@ -9,6 +9,11 @@ * (at your option) any later version. */ + /* +* Includes Intel Corporation's changes dated: 2019. +* Changed portions - Copyright 2019, Intel Corporation. +*/ + #include #include #include @@ -22,270 +27,7 @@ #include #include - -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 " -#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); -} +#include static struct macsec_rxh_data *macsec_data_rcu(const struct net_device *dev) { @@ -1050,7 +792,12 @@ int ret; struct pcpu_secy_stats *secy_stats = this_cpu_ptr(macsec->stats); +#ifdef CONFIG_MACSEC_HW_OFFLOAD + if ((macsec->hw_offload == false) + && (macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT)) { +#else if (macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) { +#endif u64_stats_update_begin(&secy_stats->syncp); secy_stats->stats.InPktsNoTag++; u64_stats_update_end(&secy_stats->syncp); @@ -1066,9 +813,15 @@ ret = netif_rx(nskb); if (ret == NET_RX_SUCCESS) { +#ifdef CONFIG_MACSEC_HW_OFFLOAD + if (macsec->hw_offload == false) { +#endif u64_stats_update_begin(&secy_stats->syncp); secy_stats->stats.InPktsUntagged++; u64_stats_update_end(&secy_stats->syncp); +#ifdef CONFIG_MACSEC_HW_OFFLOAD + } +#endif } else { macsec->secy.netdev->stats.rx_dropped++; } @@ -1100,6 +853,21 @@ goto drop_direct; hdr = macsec_ethhdr(skb); +#ifdef CONFIG_MACSEC_HW_OFFLOAD + if (macsec_priv(dev)->hw_offload) { + if (hdr->eth.h_proto != htons(ETH_P_PAE)) { + handle_not_macsec(skb); + + kfree_skb(skb); + *pskb = NULL; + return RX_HANDLER_CONSUMED; + } + + /* Deliver to the uncontrolled port the authentication packets */ + return RX_HANDLER_PASS; + } +#endif + if (hdr->eth.h_proto != htons(ETH_P_MACSEC)) { handle_not_macsec(skb); @@ -1470,6 +1238,9 @@ .maxattr = MACSEC_ATTR_MAX, .netnsok = true, }; +#ifdef CONFIG_MACSEC_HW_OFFLOAD +static struct macsec_hw_driver *macsec_hw_drv = NULL; +#endif static struct net_device *get_dev_from_nl(struct net *net, struct nlattr **attrs) @@ -1708,6 +1479,16 @@ return -EINVAL; } +#ifdef CONFIG_MACSEC_HW_OFFLOAD + /* HW driver notification */ + if (macsec_hw_drv && macsec_hw_drv->add_rxsa) { + if (macsec_hw_drv->add_rxsa(dev, secy, tb_rxsc, tb_sa)) { + rtnl_unlock(); + return -EIO; + } + } +#endif + rx_sa = rtnl_dereference(rx_sc->sa[assoc_num]); if (rx_sa) { rtnl_unlock(); @@ -1764,6 +1545,9 @@ struct net_device *dev; sci_t sci = MACSEC_UNDEF_SCI; struct nlattr **attrs = info->attrs; +#ifdef CONFIG_MACSEC_HW_OFFLOAD + struct macsec_secy *secy; +#endif struct macsec_rx_sc *rx_sc; struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1]; @@ -1783,6 +1567,17 @@ return PTR_ERR(dev); } +#ifdef CONFIG_MACSEC_HW_OFFLOAD + secy = &macsec_priv(dev)->secy; + /* HW driver notification */ + if (macsec_hw_drv && macsec_hw_drv->add_rxsc) { + if (macsec_hw_drv->add_rxsc(dev, secy, tb_rxsc)) { + rtnl_unlock(); + return -EIO; + } + } +#endif + sci = nla_get_sci(tb_rxsc[MACSEC_RXSC_ATTR_SCI]); rx_sc = create_rx_sc(dev, sci); @@ -1863,6 +1658,16 @@ return -EINVAL; } +#ifdef CONFIG_MACSEC_HW_OFFLOAD + /* HW driver notification */ + if (macsec_hw_drv && macsec_hw_drv->add_txsa) { + if (macsec_hw_drv->add_txsa(dev, secy, tb_sa)) { + rtnl_unlock(); + return -EIO; + } + } +#endif + tx_sa = rtnl_dereference(tx_sc->sa[assoc_num]); if (tx_sa) { rtnl_unlock(); @@ -1938,6 +1743,15 @@ RCU_INIT_POINTER(rx_sc->sa[assoc_num], NULL); clear_rx_sa(rx_sa); +#ifdef CONFIG_MACSEC_HW_OFFLOAD + /* HW driver notification */ + if (macsec_hw_drv && macsec_hw_drv->del_rxsa) { + if (macsec_hw_drv->del_rxsa(dev, secy, tb_rxsc, tb_sa)) { + rtnl_unlock(); + return -EIO; + } + } +#endif rtnl_unlock(); return 0; @@ -1978,6 +1792,16 @@ } free_rx_sc(rx_sc); + +#ifdef CONFIG_MACSEC_HW_OFFLOAD + /* HW driver notification */ + if (macsec_hw_drv && macsec_hw_drv->del_rxsc) { + if (macsec_hw_drv->del_rxsc(dev, secy, tb_rxsc)) { + rtnl_unlock(); + return -EIO; + } + } +#endif rtnl_unlock(); return 0; @@ -2015,6 +1839,15 @@ RCU_INIT_POINTER(tx_sc->sa[assoc_num], NULL); clear_tx_sa(tx_sa); +#ifdef CONFIG_MACSEC_HW_OFFLOAD + /* HW driver notification */ + if (macsec_hw_drv && macsec_hw_drv->del_txsa) { + if (macsec_hw_drv->del_txsa(dev, secy, tb_sa)) { + rtnl_unlock(); + return -EIO; + } + } +#endif rtnl_unlock(); return 0; @@ -2080,6 +1913,15 @@ if (assoc_num == tx_sc->encoding_sa) secy->operational = tx_sa->active; +#ifdef CONFIG_MACSEC_HW_OFFLOAD + /* HW driver notification */ + if (macsec_hw_drv && macsec_hw_drv->upd_txsa) { + if (macsec_hw_drv->upd_txsa(dev, secy, tb_sa)) { + rtnl_unlock(); + return -EIO; + } + } +#endif rtnl_unlock(); return 0; @@ -2125,7 +1967,17 @@ if (tb_sa[MACSEC_SA_ATTR_ACTIVE]) rx_sa->active = nla_get_u8(tb_sa[MACSEC_SA_ATTR_ACTIVE]); +#ifdef CONFIG_MACSEC_HW_OFFLOAD + /* HW driver notification */ + if (macsec_hw_drv && macsec_hw_drv->upd_rxsa) { + if (macsec_hw_drv->upd_rxsa(dev, secy, tb_rxsc, tb_sa)) { + rtnl_unlock(); + return -EIO; + } + } +#endif rtnl_unlock(); + return 0; } @@ -2162,6 +2014,15 @@ rx_sc->active = new; } +#ifdef CONFIG_MACSEC_HW_OFFLOAD + /* HW driver notification */ + if (macsec_hw_drv && macsec_hw_drv->upd_rxsc) { + if (macsec_hw_drv->upd_rxsc(dev, secy, tb_rxsc)) { + rtnl_unlock(); + return -EIO; + } + } +#endif rtnl_unlock(); return 0; @@ -2622,6 +2483,14 @@ goto next; secy = &macsec_priv(dev)->secy; + +#ifdef CONFIG_MACSEC_HW_OFFLOAD + /* HW driver notification */ + if (macsec_hw_drv && macsec_hw_drv->dump) { + if (macsec_hw_drv->dump(dev, secy)) + goto done; + } +#endif if (dump_secy(secy, dev, skb, cb) < 0) goto done; next: @@ -2705,11 +2574,19 @@ int ret, len; /* 10.5 */ +#ifdef CONFIG_MACSEC_HW_OFFLOAD + if (!secy->protect_frames && !macsec->hw_offload) { +#else if (!secy->protect_frames) { +#endif secy_stats = this_cpu_ptr(macsec->stats); u64_stats_update_begin(&secy_stats->syncp); secy_stats->stats.OutPktsUntagged++; u64_stats_update_end(&secy_stats->syncp); +#ifdef CONFIG_MACSEC_HW_OFFLOAD + } + if (!secy->protect_frames || macsec->hw_offload) { +#endif skb->dev = macsec->real_dev; len = skb->len; ret = dev_queue_xmit(skb); @@ -3080,6 +2957,14 @@ macsec_changelink_common(dev, data); +#ifdef CONFIG_MACSEC_HW_OFFLOAD + /* HW driver notification */ + if (macsec_hw_drv && macsec_hw_drv->change_link) { + if (macsec_hw_drv->change_link(dev, &macsec_priv(dev)->secy)) + return -EIO; + } +#endif + return 0; } @@ -3229,6 +3114,9 @@ dev->priv_flags |= IFF_MACSEC; macsec->real_dev = real_dev; +#ifdef CONFIG_MACSEC_HW_OFFLOAD + macsec->hw_offload = false; +#endif if (data && data[IFLA_MACSEC_ICV_LEN]) icv_len = nla_get_u8(data[IFLA_MACSEC_ICV_LEN]); @@ -3240,7 +3128,10 @@ rx_handler = rtnl_dereference(real_dev->rx_handler); if (rx_handler && rx_handler != macsec_handle_frame) + { + pr_info("macsec: rx_handler already registered\n"); return -EBUSY; + } err = register_netdevice(dev); if (err < 0) @@ -3443,10 +3334,11 @@ .get_link_net = macsec_get_link_net, }; -static bool is_macsec_master(struct net_device *dev) +bool is_macsec_master(struct net_device *dev) { return rcu_access_pointer(dev->rx_handler) == macsec_handle_frame; } +EXPORT_SYMBOL(is_macsec_master); static int macsec_notify(struct notifier_block *this, unsigned long event, void *ptr) @@ -3510,6 +3402,34 @@ .notifier_call = macsec_notify, }; +#ifdef CONFIG_MACSEC_HW_OFFLOAD +int macsec_register_hw_driver(struct macsec_hw_driver * hw_driver) +{ + if (!hw_driver) { + return -EINVAL; + } + + rtnl_lock(); + macsec_hw_drv = hw_driver; + rtnl_unlock(); + + pr_info("MACsec hw driver registered\n"); + + return 0; +} +EXPORT_SYMBOL(macsec_register_hw_driver); + +void macsec_unregister_hw_driver(void) +{ + rtnl_lock(); + macsec_hw_drv = NULL; + rtnl_unlock(); + + pr_info("MACsec hw driver unregistered\n"); +} +EXPORT_SYMBOL(macsec_unregister_hw_driver); +#endif /* CONFIG_MACSEC_HW_OFFLOAD */ + static int __init macsec_init(void) { int err;