From mboxrd@z Thu Jan 1 00:00:00 1970 From: Radu Rendec Subject: [PATCH 1/1] macsec: reflect the master interface state Date: Tue, 18 Sep 2018 20:16:12 -0400 Message-ID: <20180919001612.2636-2-radu.rendec@gmail.com> References: <20180919001612.2636-1-radu.rendec@gmail.com> Cc: David Miller , Sabrina Dubroca , Radu Rendec To: netdev@vger.kernel.org Return-path: Received: from mail-it0-f67.google.com ([209.85.214.67]:50966 "EHLO mail-it0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727099AbeISFvw (ORCPT ); Wed, 19 Sep 2018 01:51:52 -0400 Received: by mail-it0-f67.google.com with SMTP id j81-v6so5944496ite.0 for ; Tue, 18 Sep 2018 17:16:47 -0700 (PDT) In-Reply-To: <20180919001612.2636-1-radu.rendec@gmail.com> Sender: netdev-owner@vger.kernel.org List-ID: This patch makes macsec interfaces reflect the state of the underlying interface: if the master interface changes state to up/down, the macsec interface changes its state accordingly. This closes a loophole in the macsec interface state logic: the macsec interface cannot be brought up if the master interface is down (the operation is rejected with ENETDOWN); however, if the macsec interface is brought up while the master interface is up and then the master interface goes down, the macsec interface stays up. Reflecting the master interface state can also be useful if the macsec interface is used as a bridge port: if the master (physical) interface goes down, the state propagates through the macsec interface to the bridge module, which can react to the state change (for example if it runs STP). The patch does nothing original. The same logic is implemented for vlan interfaces in vlan_device_event() in net/8021q/vlan.c. In fact, the code was copied and adapted from there. Signed-off-by: Radu Rendec --- drivers/net/macsec.c | 57 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 7de88b33d5b9..cb93a1290f85 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -3486,20 +3486,21 @@ static int macsec_notify(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *real_dev = netdev_notifier_info_to_dev(ptr); - LIST_HEAD(head); + struct macsec_dev *m; + struct macsec_rxh_data *rxd; if (!is_macsec_master(real_dev)) return NOTIFY_DONE; + rxd = macsec_data_rtnl(real_dev); + switch (event) { case NETDEV_UNREGISTER: { - struct macsec_dev *m, *n; - struct macsec_rxh_data *rxd; + struct macsec_dev *n; + LIST_HEAD(head); - rxd = macsec_data_rtnl(real_dev); - list_for_each_entry_safe(m, n, &rxd->secys, secys) { + list_for_each_entry_safe(m, n, &rxd->secys, secys) macsec_common_dellink(m->secy.netdev, &head); - } netdev_rx_handler_unregister(real_dev); kfree(rxd); @@ -3507,11 +3508,7 @@ static int macsec_notify(struct notifier_block *this, unsigned long event, unregister_netdevice_many(&head); break; } - case NETDEV_CHANGEMTU: { - struct macsec_dev *m; - struct macsec_rxh_data *rxd; - - rxd = macsec_data_rtnl(real_dev); + case NETDEV_CHANGEMTU: list_for_each_entry(m, &rxd->secys, secys) { struct net_device *dev = m->secy.netdev; unsigned int mtu = real_dev->mtu - (m->secy.icv_len + @@ -3520,7 +3517,45 @@ static int macsec_notify(struct notifier_block *this, unsigned long event, if (dev->mtu > mtu) dev_set_mtu(dev, mtu); } + break; + case NETDEV_CHANGE: + list_for_each_entry(m, &rxd->secys, secys) { + struct net_device *dev = m->secy.netdev; + + netif_stacked_transfer_operstate(real_dev, dev); + } + break; + case NETDEV_DOWN: { + struct net_device *dev, *tmp; + LIST_HEAD(close_list); + + list_for_each_entry(m, &rxd->secys, secys) { + dev = m->secy.netdev; + + if (dev->flags & IFF_UP) + list_add(&dev->close_list, &close_list); + } + + dev_close_many(&close_list, false); + + list_for_each_entry_safe(dev, tmp, &close_list, close_list) { + netif_stacked_transfer_operstate(real_dev, dev); + list_del_init(&dev->close_list); + } + list_del(&close_list); + break; } + case NETDEV_UP: + list_for_each_entry(m, &rxd->secys, secys) { + struct net_device *dev = m->secy.netdev; + int flags = dev_get_flags(dev); + + if (!(flags & IFF_UP)) { + dev_change_flags(dev, flags | IFF_UP); + netif_stacked_transfer_operstate(real_dev, dev); + } + } + break; } return NOTIFY_OK; -- 2.17.1