[VLAN]: Fix link state propagation When the queue of the underlying device is stopped at initialization time or the device is marked "not present", the state will be propagated to the vlan device and never change. The queue state doesn't need to be propagated at all and shouldn't be without using netif_wake_queue/netif_stop_queue, the present state needs to be kept up to date by the NETDEV_CHANGE notifier. Signed-off-by: Patrick McHardy --- commit 87d93ab26dd0c29d3f6dd3cddfd4eeea21c139f8 tree 9e3777ce697fa4c09f814967f53cb0bd142ff92c parent 4c2d0d9de3da2b2d420d91dd654ecf1551e24eca author Patrick McHardy Thu, 06 Jul 2006 09:37:33 +0200 committer Patrick McHardy Thu, 06 Jul 2006 09:37:33 +0200 net/8021q/vlan.c | 13 ++++++++++--- 1 files changed, 10 insertions(+), 3 deletions(-) diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 458031b..8b26227 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -68,8 +68,9 @@ static struct packet_type vlan_packet_ty }; /* Bits of netdev state that are propagated from real device to virtual */ -#define VLAN_LINK_STATE_MASK \ - ((1<<__LINK_STATE_PRESENT)|(1<<__LINK_STATE_NOCARRIER)|(1<<__LINK_STATE_DORMANT)) +#define VLAN_LINK_STATE_MASK ((1<<__LINK_STATE_PRESENT)) +#define VLAN_LINK_STATE_INITIAL_MASK \ + (VLAN_LINK_STATE_MASK | (1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT)) /* End of global variables definitions. */ @@ -479,7 +480,7 @@ #endif new_dev->flags = real_dev->flags; new_dev->flags &= ~IFF_UP; - new_dev->state = real_dev->state & ~(1<<__LINK_STATE_START); + new_dev->state = real_dev->state & VLAN_LINK_STATE_INITIAL_MASK; /* need 4 bytes for extra VLAN header info, * hope the underlying device can handle it. @@ -608,11 +609,17 @@ static int vlan_device_event(struct noti switch (event) { case NETDEV_CHANGE: /* Propagate real device state to vlan devices */ + flgs = dev->state & VLAN_LINK_STATE_MASK; for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { vlandev = grp->vlan_devices[i]; if (!vlandev) continue; + if ((vlandev->state & VLAN_LINK_STATE_MASK) != flgs) { + vlandev->state &= ~VLAN_LINK_STATE_MASK; + vlandev->state |= flgs; + netdev_state_change(vlandev); + } vlan_transfer_operstate(dev, vlandev); } break;