net/8021q/vlan_core.c

Source file repositories/reference/linux-study-clean/net/8021q/vlan_core.c

File Facts

System
Linux kernel
Corpus path
net/8021q/vlan_core.c
Extension
.c
Size
13096 bytes
Lines
561
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct vlan_vid_info {
	struct list_head list;
	__be16 proto;
	u16 vid;
	int refcount;
};

static bool vlan_hw_filter_capable(const struct net_device *dev, __be16 proto)
{
	if (proto == htons(ETH_P_8021Q) &&
	    dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
		return true;
	if (proto == htons(ETH_P_8021AD) &&
	    dev->features & NETIF_F_HW_VLAN_STAG_FILTER)
		return true;
	return false;
}

static struct vlan_vid_info *vlan_vid_info_get(struct vlan_info *vlan_info,
					       __be16 proto, u16 vid)
{
	struct vlan_vid_info *vid_info;

	list_for_each_entry(vid_info, &vlan_info->vid_list, list) {
		if (vid_info->proto == proto && vid_info->vid == vid)
			return vid_info;
	}
	return NULL;
}

static struct vlan_vid_info *vlan_vid_info_alloc(__be16 proto, u16 vid)
{
	struct vlan_vid_info *vid_info;

	vid_info = kzalloc_obj(struct vlan_vid_info);
	if (!vid_info)
		return NULL;
	vid_info->proto = proto;
	vid_info->vid = vid;

	return vid_info;
}

static int vlan_add_rx_filter_info(struct net_device *dev, __be16 proto, u16 vid)
{
	if (!vlan_hw_filter_capable(dev, proto))
		return 0;

	if (netif_device_present(dev))
		return dev->netdev_ops->ndo_vlan_rx_add_vid(dev, proto, vid);
	else
		return -ENODEV;
}

static int vlan_kill_rx_filter_info(struct net_device *dev, __be16 proto, u16 vid)
{
	if (!vlan_hw_filter_capable(dev, proto))
		return 0;

	if (netif_device_present(dev))
		return dev->netdev_ops->ndo_vlan_rx_kill_vid(dev, proto, vid);
	else
		return -ENODEV;
}

int vlan_for_each(struct net_device *dev,
		  int (*action)(struct net_device *dev, int vid, void *arg),
		  void *arg)
{
	struct vlan_vid_info *vid_info;
	struct vlan_info *vlan_info;
	struct net_device *vdev;
	int ret;

	ASSERT_RTNL();

	vlan_info = rtnl_dereference(dev->vlan_info);
	if (!vlan_info)
		return 0;

	list_for_each_entry(vid_info, &vlan_info->vid_list, list) {
		vdev = vlan_group_get_device(&vlan_info->grp, vid_info->proto,
					     vid_info->vid);
		ret = action(vdev, vid_info->vid, arg);
		if (ret)
			return ret;
	}

	return 0;
}

Annotation

Implementation Notes