net/8021q/vlan_netlink.c

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

File Facts

System
Linux kernel
Corpus path
net/8021q/vlan_netlink.c
Extension
.c
Size
8203 bytes
Lines
314
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source 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

if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) {
			NL_SET_ERR_MSG_MOD(extack, "Invalid link address");
			return -EINVAL;
		}
		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) {
			NL_SET_ERR_MSG_MOD(extack, "Invalid link address");
			return -EADDRNOTAVAIL;
		}
	}

	if (!data) {
		NL_SET_ERR_MSG_MOD(extack, "VLAN properties not specified");
		return -EINVAL;
	}

	if (data[IFLA_VLAN_PROTOCOL]) {
		switch (nla_get_be16(data[IFLA_VLAN_PROTOCOL])) {
		case htons(ETH_P_8021Q):
		case htons(ETH_P_8021AD):
			break;
		default:
			NL_SET_ERR_MSG_MOD(extack, "Invalid VLAN protocol");
			return -EPROTONOSUPPORT;
		}
	}

	if (data[IFLA_VLAN_ID]) {
		id = nla_get_u16(data[IFLA_VLAN_ID]);
		if (id >= VLAN_VID_MASK) {
			NL_SET_ERR_MSG_MOD(extack, "Invalid VLAN id");
			return -ERANGE;
		}
	}
	if (data[IFLA_VLAN_FLAGS]) {
		flags = nla_data(data[IFLA_VLAN_FLAGS]);
		if ((flags->flags & flags->mask) &
		    ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
		      VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP |
		      VLAN_FLAG_BRIDGE_BINDING)) {
			NL_SET_ERR_MSG_MOD(extack, "Invalid VLAN flags");
			return -EINVAL;
		}
	}

	err = vlan_validate_qos_map(data[IFLA_VLAN_INGRESS_QOS]);
	if (err < 0) {
		NL_SET_ERR_MSG_MOD(extack, "Invalid ingress QOS map");
		return err;
	}
	err = vlan_validate_qos_map(data[IFLA_VLAN_EGRESS_QOS]);
	if (err < 0) {
		NL_SET_ERR_MSG_MOD(extack, "Invalid egress QOS map");
		return err;
	}
	return 0;
}

static int vlan_changelink(struct net_device *dev, struct nlattr *tb[],
			   struct nlattr *data[],
			   struct netlink_ext_ack *extack)
{
	struct ifla_vlan_flags *flags;
	struct ifla_vlan_qos_mapping *m;
	struct nlattr *attr;
	int rem, err;

	if (data[IFLA_VLAN_FLAGS]) {
		flags = nla_data(data[IFLA_VLAN_FLAGS]);
		err = vlan_dev_change_flags(dev, flags->flags, flags->mask);
		if (err)
			return err;
	}
	if (data[IFLA_VLAN_INGRESS_QOS]) {
		nla_for_each_nested_type(attr, IFLA_VLAN_QOS_MAPPING,
					 data[IFLA_VLAN_INGRESS_QOS], rem) {
			m = nla_data(attr);
			vlan_dev_set_ingress_priority(dev, m->to, m->from);
		}
	}
	if (data[IFLA_VLAN_EGRESS_QOS]) {
		nla_for_each_nested_type(attr, IFLA_VLAN_QOS_MAPPING,
					 data[IFLA_VLAN_EGRESS_QOS], rem) {
			m = nla_data(attr);
			err = vlan_dev_set_egress_priority(dev, m->from, m->to);
			if (err)
				return err;
		}
	}
	return 0;
}

Annotation

Implementation Notes