cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vlan_netlink.c (7908B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *	VLAN netlink control interface
      4 *
      5 * 	Copyright (c) 2007 Patrick McHardy <kaber@trash.net>
      6 */
      7
      8#include <linux/kernel.h>
      9#include <linux/netdevice.h>
     10#include <linux/if_vlan.h>
     11#include <linux/module.h>
     12#include <net/net_namespace.h>
     13#include <net/netlink.h>
     14#include <net/rtnetlink.h>
     15#include "vlan.h"
     16
     17
     18static const struct nla_policy vlan_policy[IFLA_VLAN_MAX + 1] = {
     19	[IFLA_VLAN_ID]		= { .type = NLA_U16 },
     20	[IFLA_VLAN_FLAGS]	= { .len = sizeof(struct ifla_vlan_flags) },
     21	[IFLA_VLAN_EGRESS_QOS]	= { .type = NLA_NESTED },
     22	[IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
     23	[IFLA_VLAN_PROTOCOL]	= { .type = NLA_U16 },
     24};
     25
     26static const struct nla_policy vlan_map_policy[IFLA_VLAN_QOS_MAX + 1] = {
     27	[IFLA_VLAN_QOS_MAPPING] = { .len = sizeof(struct ifla_vlan_qos_mapping) },
     28};
     29
     30
     31static inline int vlan_validate_qos_map(struct nlattr *attr)
     32{
     33	if (!attr)
     34		return 0;
     35	return nla_validate_nested_deprecated(attr, IFLA_VLAN_QOS_MAX,
     36					      vlan_map_policy, NULL);
     37}
     38
     39static int vlan_validate(struct nlattr *tb[], struct nlattr *data[],
     40			 struct netlink_ext_ack *extack)
     41{
     42	struct ifla_vlan_flags *flags;
     43	u16 id;
     44	int err;
     45
     46	if (tb[IFLA_ADDRESS]) {
     47		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) {
     48			NL_SET_ERR_MSG_MOD(extack, "Invalid link address");
     49			return -EINVAL;
     50		}
     51		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) {
     52			NL_SET_ERR_MSG_MOD(extack, "Invalid link address");
     53			return -EADDRNOTAVAIL;
     54		}
     55	}
     56
     57	if (!data) {
     58		NL_SET_ERR_MSG_MOD(extack, "VLAN properties not specified");
     59		return -EINVAL;
     60	}
     61
     62	if (data[IFLA_VLAN_PROTOCOL]) {
     63		switch (nla_get_be16(data[IFLA_VLAN_PROTOCOL])) {
     64		case htons(ETH_P_8021Q):
     65		case htons(ETH_P_8021AD):
     66			break;
     67		default:
     68			NL_SET_ERR_MSG_MOD(extack, "Invalid VLAN protocol");
     69			return -EPROTONOSUPPORT;
     70		}
     71	}
     72
     73	if (data[IFLA_VLAN_ID]) {
     74		id = nla_get_u16(data[IFLA_VLAN_ID]);
     75		if (id >= VLAN_VID_MASK) {
     76			NL_SET_ERR_MSG_MOD(extack, "Invalid VLAN id");
     77			return -ERANGE;
     78		}
     79	}
     80	if (data[IFLA_VLAN_FLAGS]) {
     81		flags = nla_data(data[IFLA_VLAN_FLAGS]);
     82		if ((flags->flags & flags->mask) &
     83		    ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
     84		      VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP |
     85		      VLAN_FLAG_BRIDGE_BINDING)) {
     86			NL_SET_ERR_MSG_MOD(extack, "Invalid VLAN flags");
     87			return -EINVAL;
     88		}
     89	}
     90
     91	err = vlan_validate_qos_map(data[IFLA_VLAN_INGRESS_QOS]);
     92	if (err < 0) {
     93		NL_SET_ERR_MSG_MOD(extack, "Invalid ingress QOS map");
     94		return err;
     95	}
     96	err = vlan_validate_qos_map(data[IFLA_VLAN_EGRESS_QOS]);
     97	if (err < 0) {
     98		NL_SET_ERR_MSG_MOD(extack, "Invalid egress QOS map");
     99		return err;
    100	}
    101	return 0;
    102}
    103
    104static int vlan_changelink(struct net_device *dev, struct nlattr *tb[],
    105			   struct nlattr *data[],
    106			   struct netlink_ext_ack *extack)
    107{
    108	struct ifla_vlan_flags *flags;
    109	struct ifla_vlan_qos_mapping *m;
    110	struct nlattr *attr;
    111	int rem, err;
    112
    113	if (data[IFLA_VLAN_FLAGS]) {
    114		flags = nla_data(data[IFLA_VLAN_FLAGS]);
    115		err = vlan_dev_change_flags(dev, flags->flags, flags->mask);
    116		if (err)
    117			return err;
    118	}
    119	if (data[IFLA_VLAN_INGRESS_QOS]) {
    120		nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) {
    121			m = nla_data(attr);
    122			vlan_dev_set_ingress_priority(dev, m->to, m->from);
    123		}
    124	}
    125	if (data[IFLA_VLAN_EGRESS_QOS]) {
    126		nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) {
    127			m = nla_data(attr);
    128			err = vlan_dev_set_egress_priority(dev, m->from, m->to);
    129			if (err)
    130				return err;
    131		}
    132	}
    133	return 0;
    134}
    135
    136static int vlan_newlink(struct net *src_net, struct net_device *dev,
    137			struct nlattr *tb[], struct nlattr *data[],
    138			struct netlink_ext_ack *extack)
    139{
    140	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
    141	struct net_device *real_dev;
    142	unsigned int max_mtu;
    143	__be16 proto;
    144	int err;
    145
    146	if (!data[IFLA_VLAN_ID]) {
    147		NL_SET_ERR_MSG_MOD(extack, "VLAN id not specified");
    148		return -EINVAL;
    149	}
    150
    151	if (!tb[IFLA_LINK]) {
    152		NL_SET_ERR_MSG_MOD(extack, "link not specified");
    153		return -EINVAL;
    154	}
    155
    156	real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
    157	if (!real_dev) {
    158		NL_SET_ERR_MSG_MOD(extack, "link does not exist");
    159		return -ENODEV;
    160	}
    161
    162	if (data[IFLA_VLAN_PROTOCOL])
    163		proto = nla_get_be16(data[IFLA_VLAN_PROTOCOL]);
    164	else
    165		proto = htons(ETH_P_8021Q);
    166
    167	vlan->vlan_proto = proto;
    168	vlan->vlan_id	 = nla_get_u16(data[IFLA_VLAN_ID]);
    169	vlan->real_dev	 = real_dev;
    170	dev->priv_flags |= (real_dev->priv_flags & IFF_XMIT_DST_RELEASE);
    171	vlan->flags	 = VLAN_FLAG_REORDER_HDR;
    172
    173	err = vlan_check_real_dev(real_dev, vlan->vlan_proto, vlan->vlan_id,
    174				  extack);
    175	if (err < 0)
    176		return err;
    177
    178	max_mtu = netif_reduces_vlan_mtu(real_dev) ? real_dev->mtu - VLAN_HLEN :
    179						     real_dev->mtu;
    180	if (!tb[IFLA_MTU])
    181		dev->mtu = max_mtu;
    182	else if (dev->mtu > max_mtu)
    183		return -EINVAL;
    184
    185	err = vlan_changelink(dev, tb, data, extack);
    186	if (err)
    187		return err;
    188	err = register_vlan_dev(dev, extack);
    189	if (err)
    190		vlan_dev_free_egress_priority(dev);
    191	return err;
    192}
    193
    194static inline size_t vlan_qos_map_size(unsigned int n)
    195{
    196	if (n == 0)
    197		return 0;
    198	/* IFLA_VLAN_{EGRESS,INGRESS}_QOS + n * IFLA_VLAN_QOS_MAPPING */
    199	return nla_total_size(sizeof(struct nlattr)) +
    200	       nla_total_size(sizeof(struct ifla_vlan_qos_mapping)) * n;
    201}
    202
    203static size_t vlan_get_size(const struct net_device *dev)
    204{
    205	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
    206
    207	return nla_total_size(2) +	/* IFLA_VLAN_PROTOCOL */
    208	       nla_total_size(2) +	/* IFLA_VLAN_ID */
    209	       nla_total_size(sizeof(struct ifla_vlan_flags)) + /* IFLA_VLAN_FLAGS */
    210	       vlan_qos_map_size(vlan->nr_ingress_mappings) +
    211	       vlan_qos_map_size(vlan->nr_egress_mappings);
    212}
    213
    214static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
    215{
    216	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
    217	struct vlan_priority_tci_mapping *pm;
    218	struct ifla_vlan_flags f;
    219	struct ifla_vlan_qos_mapping m;
    220	struct nlattr *nest;
    221	unsigned int i;
    222
    223	if (nla_put_be16(skb, IFLA_VLAN_PROTOCOL, vlan->vlan_proto) ||
    224	    nla_put_u16(skb, IFLA_VLAN_ID, vlan->vlan_id))
    225		goto nla_put_failure;
    226	if (vlan->flags) {
    227		f.flags = vlan->flags;
    228		f.mask  = ~0;
    229		if (nla_put(skb, IFLA_VLAN_FLAGS, sizeof(f), &f))
    230			goto nla_put_failure;
    231	}
    232	if (vlan->nr_ingress_mappings) {
    233		nest = nla_nest_start_noflag(skb, IFLA_VLAN_INGRESS_QOS);
    234		if (nest == NULL)
    235			goto nla_put_failure;
    236
    237		for (i = 0; i < ARRAY_SIZE(vlan->ingress_priority_map); i++) {
    238			if (!vlan->ingress_priority_map[i])
    239				continue;
    240
    241			m.from = i;
    242			m.to   = vlan->ingress_priority_map[i];
    243			if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
    244				    sizeof(m), &m))
    245				goto nla_put_failure;
    246		}
    247		nla_nest_end(skb, nest);
    248	}
    249
    250	if (vlan->nr_egress_mappings) {
    251		nest = nla_nest_start_noflag(skb, IFLA_VLAN_EGRESS_QOS);
    252		if (nest == NULL)
    253			goto nla_put_failure;
    254
    255		for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
    256			for (pm = vlan->egress_priority_map[i]; pm;
    257			     pm = pm->next) {
    258				if (!pm->vlan_qos)
    259					continue;
    260
    261				m.from = pm->priority;
    262				m.to   = (pm->vlan_qos >> 13) & 0x7;
    263				if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
    264					    sizeof(m), &m))
    265					goto nla_put_failure;
    266			}
    267		}
    268		nla_nest_end(skb, nest);
    269	}
    270	return 0;
    271
    272nla_put_failure:
    273	return -EMSGSIZE;
    274}
    275
    276static struct net *vlan_get_link_net(const struct net_device *dev)
    277{
    278	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
    279
    280	return dev_net(real_dev);
    281}
    282
    283struct rtnl_link_ops vlan_link_ops __read_mostly = {
    284	.kind		= "vlan",
    285	.maxtype	= IFLA_VLAN_MAX,
    286	.policy		= vlan_policy,
    287	.priv_size	= sizeof(struct vlan_dev_priv),
    288	.setup		= vlan_setup,
    289	.validate	= vlan_validate,
    290	.newlink	= vlan_newlink,
    291	.changelink	= vlan_changelink,
    292	.dellink	= unregister_vlan_dev,
    293	.get_size	= vlan_get_size,
    294	.fill_info	= vlan_fill_info,
    295	.get_link_net	= vlan_get_link_net,
    296};
    297
    298int __init vlan_netlink_init(void)
    299{
    300	return rtnl_link_register(&vlan_link_ops);
    301}
    302
    303void __exit vlan_netlink_fini(void)
    304{
    305	rtnl_link_unregister(&vlan_link_ops);
    306}
    307
    308MODULE_ALIAS_RTNL_LINK("vlan");