drivers/net/macsec.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-)
From: Carlos Fernandez <carlos.fernandez@technica-engineering.de>
According to 802.1AE standard, when ES and SC flags in TCI are zero,
used SCI should be the current active SC_RX. Current code uses the
header MAC address. Without this patch, when ES flag is 0 (using a
bridge or switch), header MAC will not fit the SCI and MACSec frames
will be discarted.
Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver")
Co-developed-by: Andreu Montiel <Andreu.Montiel@technica-engineering.de>
Signed-off-by: Andreu Montiel <Andreu.Montiel@technica-engineering.de>
Signed-off-by: Carlos Fernandez <carlos.fernandez@technica-engineering.de>
---
v3:
* Wrong drop frame afer macsec_frame_sci
* Wrong Fixes tag in message
v2: https://patchwork.kernel.org/project/netdevbpf/patch/20250604113213.2595524-1-carlos.fernandez@technica-engineering.de/
* Active sci lookup logic in a separate helper.
* Unnecessary loops avoided.
* Check RXSC is exactly one for lower device.
* Drops frame in case of error.
v1: https://patchwork.kernel.org/project/netdevbpf/patch/20250529124455.2761783-1-carlos.fernandez@technica-engineering.de/
drivers/net/macsec.c | 40 ++++++++++++++++++++++++++++++++++------
1 file changed, 34 insertions(+), 6 deletions(-)
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 3d315e30ee47..7edbe76b5455 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -247,15 +247,39 @@ static sci_t make_sci(const u8 *addr, __be16 port)
return sci;
}
-static sci_t macsec_frame_sci(struct macsec_eth_header *hdr, bool sci_present)
+static sci_t macsec_active_sci(struct macsec_secy *secy)
{
- sci_t sci;
+ 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;
- if (sci_present)
+ /* SC = 1 */
+ if (sci_present) {
memcpy(&sci, hdr->secure_channel_id,
sizeof(hdr->secure_channel_id));
- else
+ /* 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;
}
@@ -1109,7 +1133,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
struct macsec_rxh_data *rxd;
struct macsec_dev *macsec;
unsigned int len;
- sci_t sci;
+ sci_t sci = 0;
u32 hdr_pn;
bool cbit;
struct pcpu_rx_sc_stats *rxsc_stats;
@@ -1156,11 +1180,14 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
macsec_skb_cb(skb)->has_sci = !!(hdr->tci_an & MACSEC_TCI_SC);
macsec_skb_cb(skb)->assoc_num = hdr->tci_an & MACSEC_AN_MASK;
- sci = macsec_frame_sci(hdr, macsec_skb_cb(skb)->has_sci);
rcu_read_lock();
rxd = macsec_data_rcu(skb->dev);
+ sci = macsec_frame_sci(hdr, macsec_skb_cb(skb)->has_sci, rxd);
+ if (!sci)
+ goto drop_nosc;
+
list_for_each_entry_rcu(macsec, &rxd->secys, secys) {
struct macsec_rx_sc *sc = find_rx_sc(&macsec->secy, sci);
@@ -1283,6 +1310,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
macsec_rxsa_put(rx_sa);
drop_nosa:
macsec_rxsc_put(rx_sc);
+drop_nosc:
rcu_read_unlock();
drop_direct:
kfree_skb(skb);
--
2.43.0
Hi Simon, I've added the test explanation in a new v4 of the patch. https://patchwork.kernel.org/project/netdevbpf/patch/20250609064707.773982-1-carlos.fernandez@technica-engineering.de/ Thanks,
Hi Sundeep, In order to test this scenario, ES and SC flags must be 0 and port identifier should be different than 1. In order to test it, I runned the following commands that configure two network interfaces on qemu over different namespaces. After applying this configuration, MACsec ping works in the patched version but fails with the original code. I'll paste the script commands here. Hope it helps your testing. PORT=11 SEND_SCI="off" ETH1_MAC="52:54:00:12:34:57" ETH0_MAC="52:54:00:12:34:56" ENCRYPT="on" ip netns add macsec1 ip netns add macsec0 ip link set eth0 netns macsec0 ip link set eth1 netns macsec1 ip netns exec macsec0 ip link add link eth0 macsec0 type macsec port $PORT send_sci $SEND_SCI end_station off encrypt $ENCRYPT ip netns exec macsec0 ip macsec add macsec0 tx sa 0 pn 2 on key 01 12345678901234567890123456789012 ip netns exec macsec0 ip macsec add macsec0 rx port $PORT address $ETH1_MAC ip netns exec macsec0 ip macsec add macsec0 rx port $PORT address $ETH1_MAC sa 0 pn 2 on key 02 09876543210987654321098765432109 ip netns exec macsec0 ip link set dev macsec0 up ip netns exec macsec0 ip addr add 10.10.12.1/24 dev macsec0 ip netns exec macsec1 ip link add link eth1 macsec1 type macsec port $PORT send_sci $SEND_SCI end_station off encrypt $ENCRYPT ip netns exec macsec1 ip macsec add macsec1 tx sa 0 pn 2 on key 02 09876543210987654321098765432109 ip netns exec macsec1 ip macsec add macsec1 rx port $PORT address $ETH0_MAC ip netns exec macsec1 ip macsec add macsec1 rx port $PORT address $ETH0_MAC sa 0 pn 2 on key 01 12345678901234567890123456789012 ip netns exec macsec1 ip link set dev macsec1 up ip netns exec macsec1 ip addr add 10.10.12.2/24 dev macsec1 ip netns exec macsec1 ping 10.10.12.1 #Ping works on patched version. Thanks, Carlos
On Thu, Jun 05, 2025 at 03:21:04PM +0200, Carlos Fernandez wrote: > Hi Sundeep, > > In order to test this scenario, ES and SC flags must be 0 and > port identifier should be different than 1. > > In order to test it, I runned the following commands that configure > two network interfaces on qemu over different namespaces. > > After applying this configuration, MACsec ping works in the patched version > but fails with the original code. > > I'll paste the script commands here. Hope it helps your testing. > > PORT=11 > SEND_SCI="off" > ETH1_MAC="52:54:00:12:34:57" > ETH0_MAC="52:54:00:12:34:56" > ENCRYPT="on" > > ip netns add macsec1 > ip netns add macsec0 > ip link set eth0 netns macsec0 > ip link set eth1 netns macsec1 > > ip netns exec macsec0 ip link add link eth0 macsec0 type macsec port $PORT send_sci $SEND_SCI end_station off encrypt $ENCRYPT > ip netns exec macsec0 ip macsec add macsec0 tx sa 0 pn 2 on key 01 12345678901234567890123456789012 > ip netns exec macsec0 ip macsec add macsec0 rx port $PORT address $ETH1_MAC > ip netns exec macsec0 ip macsec add macsec0 rx port $PORT address $ETH1_MAC sa 0 pn 2 on key 02 09876543210987654321098765432109 > ip netns exec macsec0 ip link set dev macsec0 up > ip netns exec macsec0 ip addr add 10.10.12.1/24 dev macsec0 > > ip netns exec macsec1 ip link add link eth1 macsec1 type macsec port $PORT send_sci $SEND_SCI end_station off encrypt $ENCRYPT > ip netns exec macsec1 ip macsec add macsec1 tx sa 0 pn 2 on key 02 09876543210987654321098765432109 > ip netns exec macsec1 ip macsec add macsec1 rx port $PORT address $ETH0_MAC > ip netns exec macsec1 ip macsec add macsec1 rx port $PORT address $ETH0_MAC sa 0 pn 2 on key 01 12345678901234567890123456789012 > ip netns exec macsec1 ip link set dev macsec1 up > ip netns exec macsec1 ip addr add 10.10.12.2/24 dev macsec1 > > ip netns exec macsec1 ping 10.10.12.1 #Ping works on patched version. It seems to me that it would be useful to include these instructions in the commit message. Or better still, add a selftests.
On 2025-06-05 at 13:21:04, Carlos Fernandez (carlos.fernandez@technica-engineering.de) wrote: > Hi Sundeep, > > In order to test this scenario, ES and SC flags must be 0 and > port identifier should be different than 1. > > In order to test it, I runned the following commands that configure > two network interfaces on qemu over different namespaces. > > After applying this configuration, MACsec ping works in the patched version > but fails with the original code. > > I'll paste the script commands here. Hope it helps your testing. > > PORT=11 > SEND_SCI="off" > ETH1_MAC="52:54:00:12:34:57" > ETH0_MAC="52:54:00:12:34:56" > ENCRYPT="on" > > ip netns add macsec1 > ip netns add macsec0 > ip link set eth0 netns macsec0 > ip link set eth1 netns macsec1 > > ip netns exec macsec0 ip link add link eth0 macsec0 type macsec port $PORT send_sci $SEND_SCI end_station off encrypt $ENCRYPT > ip netns exec macsec0 ip macsec add macsec0 tx sa 0 pn 2 on key 01 12345678901234567890123456789012 > ip netns exec macsec0 ip macsec add macsec0 rx port $PORT address $ETH1_MAC > ip netns exec macsec0 ip macsec add macsec0 rx port $PORT address $ETH1_MAC sa 0 pn 2 on key 02 09876543210987654321098765432109 > ip netns exec macsec0 ip link set dev macsec0 up > ip netns exec macsec0 ip addr add 10.10.12.1/24 dev macsec0 > > ip netns exec macsec1 ip link add link eth1 macsec1 type macsec port $PORT send_sci $SEND_SCI end_station off encrypt $ENCRYPT > ip netns exec macsec1 ip macsec add macsec1 tx sa 0 pn 2 on key 02 09876543210987654321098765432109 > ip netns exec macsec1 ip macsec add macsec1 rx port $PORT address $ETH0_MAC > ip netns exec macsec1 ip macsec add macsec1 rx port $PORT address $ETH0_MAC sa 0 pn 2 on key 01 12345678901234567890123456789012 > ip netns exec macsec1 ip link set dev macsec1 up > ip netns exec macsec1 ip addr add 10.10.12.2/24 dev macsec1 > > ip netns exec macsec1 ping 10.10.12.1 #Ping works on patched version. > > Thanks, > Carlos Clear for me now. Thanks for the steps. Sundeep
Hi Sundeep, In order to test this scenario, ES and SC flags must be 0 and port identifier should be different than 1. In order to test it, I runned the following commands that configure two network interfaces on qemu over different namespaces. After applying this configuration, MACsec ping works in the patched version but fails with the original code. I'll paste the script commands here. Hope it helps your testing. PORT=11 SEND_SCI="off" ETH1_MAC="52:54:00:12:34:57" ETH0_MAC="52:54:00:12:34:56" ENCRYPT="on" ip netns add macsec1 ip netns add macsec0 ip link set eth0 netns macsec0 ip link set eth1 netns macsec1 ip netns exec macsec0 ip link add link eth0 macsec0 type macsec port $PORT send_sci $SEND_SCI end_station off encrypt $ENCRYPT ip netns exec macsec0 ip macsec add macsec0 tx sa 0 pn 2 on key 01 12345678901234567890123456789012 ip netns exec macsec0 ip macsec add macsec0 rx port $PORT address $ETH1_MAC ip netns exec macsec0 ip macsec add macsec0 rx port $PORT address $ETH1_MAC sa 0 pn 2 on key 02 09876543210987654321098765432109 ip netns exec macsec0 ip link set dev macsec0 up ip netns exec macsec0 ip addr add 10.10.12.1/24 dev macsec0 ip netns exec macsec1 ip link add link eth1 macsec1 type macsec port $PORT send_sci $SEND_SCI end_station off encrypt $ENCRYPT ip netns exec macsec1 ip macsec add macsec1 tx sa 0 pn 2 on key 02 09876543210987654321098765432109 ip netns exec macsec1 ip macsec add macsec1 rx port $PORT address $ETH0_MAC ip netns exec macsec1 ip macsec add macsec1 rx port $PORT address $ETH0_MAC sa 0 pn 2 on key 01 12345678901234567890123456789012 ip netns exec macsec1 ip link set dev macsec1 up ip netns exec macsec1 ip addr add 10.10.12.2/24 dev macsec1 ip netns exec macsec1 ping 10.10.12.1 #Ping works on patched version. Thanks, Carlos
On 2025-06-04 at 12:33:55, carlos.fernandez@technica-engineering.de (carlos.fernandez@technica-engineering.de) wrote:
> From: Carlos Fernandez <carlos.fernandez@technica-engineering.de>
>
> According to 802.1AE standard, when ES and SC flags in TCI are zero,
> used SCI should be the current active SC_RX. Current code uses the
> header MAC address. Without this patch, when ES flag is 0 (using a
> bridge or switch), header MAC will not fit the SCI and MACSec frames
> will be discarted.
>
> Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver")
> Co-developed-by: Andreu Montiel <Andreu.Montiel@technica-engineering.de>
> Signed-off-by: Andreu Montiel <Andreu.Montiel@technica-engineering.de>
> Signed-off-by: Carlos Fernandez <carlos.fernandez@technica-engineering.de>
Reviewed-by: Subbaraya Sundeep <sbhatta@marvell.com>
Also please let me know how to test this single secy and single
RXSC for my understanding.
Thanks,
Sundeep
> ---
> v3:
> * Wrong drop frame afer macsec_frame_sci
> * Wrong Fixes tag in message
>
> v2: https://patchwork.kernel.org/project/netdevbpf/patch/20250604113213.2595524-1-carlos.fernandez@technica-engineering.de/
> * Active sci lookup logic in a separate helper.
> * Unnecessary loops avoided.
> * Check RXSC is exactly one for lower device.
> * Drops frame in case of error.
>
>
> v1: https://patchwork.kernel.org/project/netdevbpf/patch/20250529124455.2761783-1-carlos.fernandez@technica-engineering.de/
>
> drivers/net/macsec.c | 40 ++++++++++++++++++++++++++++++++++------
> 1 file changed, 34 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
> index 3d315e30ee47..7edbe76b5455 100644
> --- a/drivers/net/macsec.c
> +++ b/drivers/net/macsec.c
> @@ -247,15 +247,39 @@ static sci_t make_sci(const u8 *addr, __be16 port)
> return sci;
> }
>
> -static sci_t macsec_frame_sci(struct macsec_eth_header *hdr, bool sci_present)
> +static sci_t macsec_active_sci(struct macsec_secy *secy)
> {
> - sci_t sci;
> + 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;
>
> - if (sci_present)
> + /* SC = 1 */
> + if (sci_present) {
> memcpy(&sci, hdr->secure_channel_id,
> sizeof(hdr->secure_channel_id));
> - else
> + /* 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;
> }
> @@ -1109,7 +1133,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
> struct macsec_rxh_data *rxd;
> struct macsec_dev *macsec;
> unsigned int len;
> - sci_t sci;
> + sci_t sci = 0;
> u32 hdr_pn;
> bool cbit;
> struct pcpu_rx_sc_stats *rxsc_stats;
> @@ -1156,11 +1180,14 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
>
> macsec_skb_cb(skb)->has_sci = !!(hdr->tci_an & MACSEC_TCI_SC);
> macsec_skb_cb(skb)->assoc_num = hdr->tci_an & MACSEC_AN_MASK;
> - sci = macsec_frame_sci(hdr, macsec_skb_cb(skb)->has_sci);
>
> rcu_read_lock();
> rxd = macsec_data_rcu(skb->dev);
>
> + sci = macsec_frame_sci(hdr, macsec_skb_cb(skb)->has_sci, rxd);
> + if (!sci)
> + goto drop_nosc;
> +
> list_for_each_entry_rcu(macsec, &rxd->secys, secys) {
> struct macsec_rx_sc *sc = find_rx_sc(&macsec->secy, sci);
>
> @@ -1283,6 +1310,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
> macsec_rxsa_put(rx_sa);
> drop_nosa:
> macsec_rxsc_put(rx_sc);
> +drop_nosc:
> rcu_read_unlock();
> drop_direct:
> kfree_skb(skb);
> --
> 2.43.0
>
© 2016 - 2025 Red Hat, Inc.