+
+ if (is_vlan_dev(real_dev))
+ subclass = 1;
+
+ vlan_dev_set_lockdep_class(dev, subclass);
+ return 0;
+}
+
+static void vlan_dev_uninit(struct net_device *dev)
+{
+ struct vlan_priority_tci_mapping *pm;
+ struct vlan_dev_info *vlan = vlan_dev_info(dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
+ while ((pm = vlan->egress_priority_map[i]) != NULL) {
+ vlan->egress_priority_map[i] = pm->next;
+ kfree(pm);
+ }
+ }
+}
+
+static u32 vlan_ethtool_get_rx_csum(struct net_device *dev)
+{
+ const struct vlan_dev_info *vlan = vlan_dev_info(dev);
+ struct net_device *real_dev = vlan->real_dev;
+
+ if (real_dev->ethtool_ops == NULL ||
+ real_dev->ethtool_ops->get_rx_csum == NULL)
+ return 0;
+ return real_dev->ethtool_ops->get_rx_csum(real_dev);
+}
+
+static u32 vlan_ethtool_get_flags(struct net_device *dev)
+{
+ const struct vlan_dev_info *vlan = vlan_dev_info(dev);
+ struct net_device *real_dev = vlan->real_dev;
+
+ if (!(real_dev->features & NETIF_F_HW_VLAN_RX) ||
+ real_dev->ethtool_ops == NULL ||
+ real_dev->ethtool_ops->get_flags == NULL)
+ return 0;
+ return real_dev->ethtool_ops->get_flags(real_dev);
+}
+
+static const struct ethtool_ops vlan_ethtool_ops = {
+ .get_link = ethtool_op_get_link,
+ .get_rx_csum = vlan_ethtool_get_rx_csum,
+ .get_flags = vlan_ethtool_get_flags,
+};
+
+void vlan_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+
+ dev->priv_flags |= IFF_802_1Q_VLAN;
+ dev->tx_queue_len = 0;
+
+ dev->change_mtu = vlan_dev_change_mtu;
+ dev->init = vlan_dev_init;
+ dev->uninit = vlan_dev_uninit;
+ dev->open = vlan_dev_open;
+ dev->stop = vlan_dev_stop;
+ dev->set_mac_address = vlan_dev_set_mac_address;
+ dev->set_rx_mode = vlan_dev_set_rx_mode;
+ dev->set_multicast_list = vlan_dev_set_rx_mode;
+ dev->change_rx_flags = vlan_dev_change_rx_flags;
+ dev->do_ioctl = vlan_dev_ioctl;
+ dev->destructor = free_netdev;
+ dev->ethtool_ops = &vlan_ethtool_ops;
+
+ memset(dev->broadcast, 0, ETH_ALEN);