diff options
Diffstat (limited to 'net/8021q/vlan_netlink.c')
| -rw-r--r-- | net/8021q/vlan_netlink.c | 32 | 
1 files changed, 26 insertions, 6 deletions
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index 1789658b7cd..30912973228 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -23,6 +23,7 @@ static const struct nla_policy vlan_policy[IFLA_VLAN_MAX + 1] = {  	[IFLA_VLAN_FLAGS]	= { .len = sizeof(struct ifla_vlan_flags) },  	[IFLA_VLAN_EGRESS_QOS]	= { .type = NLA_NESTED },  	[IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED }, +	[IFLA_VLAN_PROTOCOL]	= { .type = NLA_U16 },  };  static const struct nla_policy vlan_map_policy[IFLA_VLAN_QOS_MAX + 1] = { @@ -53,6 +54,16 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])  	if (!data)  		return -EINVAL; +	if (data[IFLA_VLAN_PROTOCOL]) { +		switch (nla_get_be16(data[IFLA_VLAN_PROTOCOL])) { +		case __constant_htons(ETH_P_8021Q): +		case __constant_htons(ETH_P_8021AD): +			break; +		default: +			return -EPROTONOSUPPORT; +		} +	} +  	if (data[IFLA_VLAN_ID]) {  		id = nla_get_u16(data[IFLA_VLAN_ID]);  		if (id >= VLAN_VID_MASK) @@ -107,6 +118,7 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,  {  	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);  	struct net_device *real_dev; +	__be16 proto;  	int err;  	if (!data[IFLA_VLAN_ID]) @@ -118,11 +130,17 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,  	if (!real_dev)  		return -ENODEV; -	vlan->vlan_id  = nla_get_u16(data[IFLA_VLAN_ID]); -	vlan->real_dev = real_dev; -	vlan->flags    = VLAN_FLAG_REORDER_HDR; +	if (data[IFLA_VLAN_PROTOCOL]) +		proto = nla_get_be16(data[IFLA_VLAN_PROTOCOL]); +	else +		proto = htons(ETH_P_8021Q); + +	vlan->vlan_proto = proto; +	vlan->vlan_id	 = nla_get_u16(data[IFLA_VLAN_ID]); +	vlan->real_dev	 = real_dev; +	vlan->flags	 = VLAN_FLAG_REORDER_HDR; -	err = vlan_check_real_dev(real_dev, vlan->vlan_id); +	err = vlan_check_real_dev(real_dev, vlan->vlan_proto, vlan->vlan_id);  	if (err < 0)  		return err; @@ -151,7 +169,8 @@ static size_t vlan_get_size(const struct net_device *dev)  {  	struct vlan_dev_priv *vlan = vlan_dev_priv(dev); -	return nla_total_size(2) +	/* IFLA_VLAN_ID */ +	return nla_total_size(2) +	/* IFLA_VLAN_PROTOCOL */ +	       nla_total_size(2) +	/* IFLA_VLAN_ID */  	       sizeof(struct ifla_vlan_flags) + /* IFLA_VLAN_FLAGS */  	       vlan_qos_map_size(vlan->nr_ingress_mappings) +  	       vlan_qos_map_size(vlan->nr_egress_mappings); @@ -166,7 +185,8 @@ static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)  	struct nlattr *nest;  	unsigned int i; -	if (nla_put_u16(skb, IFLA_VLAN_ID, vlan_dev_priv(dev)->vlan_id)) +	if (nla_put_be16(skb, IFLA_VLAN_PROTOCOL, vlan->vlan_proto) || +	    nla_put_u16(skb, IFLA_VLAN_ID, vlan->vlan_id))  		goto nla_put_failure;  	if (vlan->flags) {  		f.flags = vlan->flags;  |