#ifdef __KERNEL__
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
#define VLAN_HLEN 4 /* The additional bytes (on top of the Ethernet header)
* that VLAN requires.
#define vlan_tx_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT)
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+/* Must be invoked with rcu_read_lock or with RTNL. */
+static inline struct net_device *vlan_find_dev(struct net_device *real_dev,
+ u16 vlan_id)
+{
+ struct vlan_group *grp = rcu_dereference_rtnl(real_dev->vlgrp);
+
+ if (grp)
+ return vlan_group_get_device(grp, vlan_id);
+
+ return NULL;
+}
+
extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
extern u16 vlan_dev_vlan_id(const struct net_device *dev);
unsigned int vlan_tci);
#else
+static inline struct net_device *vlan_find_dev(struct net_device *real_dev,
+ u16 vlan_id)
+{
+ return NULL;
+}
+
static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev)
{
BUG();
int vlan_net_id __read_mostly;
-/* Our listing of VLAN group(s) */
-static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE];
-
const char vlan_fullname[] = "802.1Q VLAN Support";
const char vlan_version[] = DRV_VERSION;
static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
/* End of global variables definitions. */
-static inline unsigned int vlan_grp_hashfn(unsigned int idx)
-{
- return ((idx >> VLAN_GRP_HASH_SHIFT) ^ idx) & VLAN_GRP_HASH_MASK;
-}
-
-/* Must be invoked with RCU read lock (no preempt) */
-static struct vlan_group *__vlan_find_group(struct net_device *real_dev)
-{
- struct vlan_group *grp;
- struct hlist_node *n;
- int hash = vlan_grp_hashfn(real_dev->ifindex);
-
- hlist_for_each_entry_rcu(grp, n, &vlan_group_hash[hash], hlist) {
- if (grp->real_dev == real_dev)
- return grp;
- }
-
- return NULL;
-}
-
-/* Find the protocol handler. Assumes VID < VLAN_VID_MASK.
- *
- * Must be invoked with RCU read lock (no preempt)
- */
-struct net_device *__find_vlan_dev(struct net_device *real_dev, u16 vlan_id)
-{
- struct vlan_group *grp = __vlan_find_group(real_dev);
-
- if (grp)
- return vlan_group_get_device(grp, vlan_id);
-
- return NULL;
-}
-
static void vlan_group_free(struct vlan_group *grp)
{
int i;
return NULL;
grp->real_dev = real_dev;
- hlist_add_head_rcu(&grp->hlist,
- &vlan_group_hash[vlan_grp_hashfn(real_dev->ifindex)]);
return grp;
}
ASSERT_RTNL();
- grp = __vlan_find_group(real_dev);
+ grp = real_dev->vlgrp;
BUG_ON(!grp);
/* Take it out of our own structures, but be sure to interlock with
if (grp->nr_vlans == 0) {
vlan_gvrp_uninit_applicant(real_dev);
+ rcu_assign_pointer(real_dev->vlgrp, NULL);
if (real_dev->features & NETIF_F_HW_VLAN_RX)
ops->ndo_vlan_rx_register(real_dev, NULL);
- hlist_del_rcu(&grp->hlist);
-
/* Free the group, after all cpu's are done. */
call_rcu(&grp->rcu, vlan_rcu_free);
}
return -EOPNOTSUPP;
}
- if (__find_vlan_dev(real_dev, vlan_id) != NULL)
+ if (vlan_find_dev(real_dev, vlan_id) != NULL)
return -EEXIST;
return 0;
struct vlan_group *grp, *ngrp = NULL;
int err;
- grp = __vlan_find_group(real_dev);
+ grp = real_dev->vlgrp;
if (!grp) {
ngrp = grp = vlan_group_alloc(real_dev);
if (!grp)
vlan_group_set_device(grp, vlan_id, dev);
grp->nr_vlans++;
- if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX)
- ops->ndo_vlan_rx_register(real_dev, ngrp);
+ if (ngrp) {
+ if (real_dev->features & NETIF_F_HW_VLAN_RX)
+ ops->ndo_vlan_rx_register(real_dev, ngrp);
+ rcu_assign_pointer(real_dev->vlgrp, ngrp);
+ }
if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
ops->ndo_vlan_rx_add_vid(real_dev, vlan_id);
vlan_gvrp_uninit_applicant(real_dev);
out_free_group:
if (ngrp) {
- hlist_del_rcu(&ngrp->hlist);
/* Free the group, after all cpu's are done. */
call_rcu(&ngrp->rcu, vlan_rcu_free);
}
dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0);
}
- grp = __vlan_find_group(dev);
+ grp = dev->vlgrp;
if (!grp)
goto out;
static void __exit vlan_cleanup_module(void)
{
- unsigned int i;
-
vlan_ioctl_set(NULL);
vlan_netlink_fini();
dev_remove_pack(&vlan_packet_type);
- /* This table must be empty if there are no module references left. */
- for (i = 0; i < VLAN_GRP_HASH_SIZE; i++)
- BUG_ON(!hlist_empty(&vlan_group_hash[i]));
-
unregister_pernet_subsys(&vlan_net_ops);
rcu_barrier(); /* Wait for completion of call_rcu()'s */
return netdev_priv(dev);
}
-#define VLAN_GRP_HASH_SHIFT 5
-#define VLAN_GRP_HASH_SIZE (1 << VLAN_GRP_HASH_SHIFT)
-#define VLAN_GRP_HASH_MASK (VLAN_GRP_HASH_SIZE - 1)
-
-/* Find a VLAN device by the MAC address of its Ethernet device, and
- * it's VLAN ID. The default configuration is to have VLAN's scope
- * to be box-wide, so the MAC will be ignored. The mac will only be
- * looked at if we are configured to have a separate set of VLANs per
- * each MAC addressable interface. Note that this latter option does
- * NOT follow the spec for VLANs, but may be useful for doing very
- * large quantities of VLAN MUX/DEMUX onto FrameRelay or ATM PVCs.
- *
- * Must be invoked with rcu_read_lock (ie preempt disabled)
- * or with RTNL.
- */
-struct net_device *__find_vlan_dev(struct net_device *real_dev, u16 vlan_id);
-
/* found in vlan_dev.c */
int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype, struct net_device *orig_dev);