]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
net: macsec: support multicast/broadcast when offloading
authorMark Starovoytov <mstarovoitov@marvell.com>
Wed, 25 Mar 2020 12:52:36 +0000 (15:52 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 27 Mar 2020 03:17:36 +0000 (20:17 -0700)
The idea is simple. If the frame is an exact match for the controlled port
(based on DA comparison), then we simply divert this skb to matching port.

Multicast/broadcast messages are delivered to all ports.

Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/macsec.c

index 146a7881a20ac61042fe5717ea8cbb16f3e3ce97..c7ad7c6f1d1ec325e7e339c6af3acf7c32172e11 100644 (file)
@@ -1006,22 +1006,53 @@ static enum rx_handler_result handle_not_macsec(struct sk_buff *skb)
 {
        /* Deliver to the uncontrolled port by default */
        enum rx_handler_result ret = RX_HANDLER_PASS;
+       struct ethhdr *hdr = eth_hdr(skb);
        struct macsec_rxh_data *rxd;
        struct macsec_dev *macsec;
 
        rcu_read_lock();
        rxd = macsec_data_rcu(skb->dev);
 
-       /* 10.6 If the management control validateFrames is not
-        * Strict, frames without a SecTAG are received, counted, and
-        * delivered to the Controlled Port
-        */
        list_for_each_entry_rcu(macsec, &rxd->secys, secys) {
                struct sk_buff *nskb;
                struct pcpu_secy_stats *secy_stats = this_cpu_ptr(macsec->stats);
+               struct net_device *ndev = macsec->secy.netdev;
 
-               if (!macsec_is_offloaded(macsec) &&
-                   macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) {
+               /* If h/w offloading is enabled, HW decodes frames and strips
+                * the SecTAG, so we have to deduce which port to deliver to.
+                */
+               if (macsec_is_offloaded(macsec) && netif_running(ndev)) {
+                       if (ether_addr_equal_64bits(hdr->h_dest,
+                                                   ndev->dev_addr)) {
+                               /* exact match, divert skb to this port */
+                               skb->dev = ndev;
+                               skb->pkt_type = PACKET_HOST;
+                               ret = RX_HANDLER_ANOTHER;
+                               goto out;
+                       } else if (is_multicast_ether_addr_64bits(
+                                          hdr->h_dest)) {
+                               /* multicast frame, deliver on this port too */
+                               nskb = skb_clone(skb, GFP_ATOMIC);
+                               if (!nskb)
+                                       break;
+
+                               nskb->dev = ndev;
+                               if (ether_addr_equal_64bits(hdr->h_dest,
+                                                           ndev->broadcast))
+                                       nskb->pkt_type = PACKET_BROADCAST;
+                               else
+                                       nskb->pkt_type = PACKET_MULTICAST;
+
+                               netif_rx(nskb);
+                       }
+                       continue;
+               }
+
+               /* 10.6 If the management control validateFrames is not
+                * Strict, frames without a SecTAG are received, counted, and
+                * delivered to the Controlled Port
+                */
+               if (macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) {
                        u64_stats_update_begin(&secy_stats->syncp);
                        secy_stats->stats.InPktsNoTag++;
                        u64_stats_update_end(&secy_stats->syncp);
@@ -1033,19 +1064,13 @@ static enum rx_handler_result handle_not_macsec(struct sk_buff *skb)
                if (!nskb)
                        break;
 
-               nskb->dev = macsec->secy.netdev;
+               nskb->dev = ndev;
 
                if (netif_rx(nskb) == NET_RX_SUCCESS) {
                        u64_stats_update_begin(&secy_stats->syncp);
                        secy_stats->stats.InPktsUntagged++;
                        u64_stats_update_end(&secy_stats->syncp);
                }
-
-               if (netif_running(macsec->secy.netdev) &&
-                   macsec_is_offloaded(macsec)) {
-                       ret = RX_HANDLER_EXACT;
-                       goto out;
-               }
        }
 
 out: