Branch data Line data Source code
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 : :
18 : : static 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 : :
26 : : static 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 : :
31 : 0 : static inline int vlan_validate_qos_map(struct nlattr *attr)
32 : : {
33 [ # # ]: 0 : if (!attr)
34 : : return 0;
35 : 0 : return nla_validate_nested_deprecated(attr, IFLA_VLAN_QOS_MAX,
36 : : vlan_map_policy, NULL);
37 : : }
38 : :
39 : 0 : static 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 [ # # ]: 0 : if (tb[IFLA_ADDRESS]) {
47 [ # # ]: 0 : if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) {
48 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "Invalid link address");
49 : : return -EINVAL;
50 : : }
51 [ # # ]: 0 : if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) {
52 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "Invalid link address");
53 : : return -EADDRNOTAVAIL;
54 : : }
55 : : }
56 : :
57 [ # # ]: 0 : if (!data) {
58 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "VLAN properties not specified");
59 : : return -EINVAL;
60 : : }
61 : :
62 [ # # ]: 0 : if (data[IFLA_VLAN_PROTOCOL]) {
63 [ # # ]: 0 : 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 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "Invalid VLAN protocol");
69 : : return -EPROTONOSUPPORT;
70 : : }
71 : : }
72 : :
73 [ # # ]: 0 : if (data[IFLA_VLAN_ID]) {
74 : : id = nla_get_u16(data[IFLA_VLAN_ID]);
75 [ # # ]: 0 : if (id >= VLAN_VID_MASK) {
76 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "Invalid VLAN id");
77 : : return -ERANGE;
78 : : }
79 : : }
80 [ # # ]: 0 : if (data[IFLA_VLAN_FLAGS]) {
81 : : flags = nla_data(data[IFLA_VLAN_FLAGS]);
82 [ # # ]: 0 : 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 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "Invalid VLAN flags");
87 : : return -EINVAL;
88 : : }
89 : : }
90 : :
91 : 0 : err = vlan_validate_qos_map(data[IFLA_VLAN_INGRESS_QOS]);
92 [ # # ]: 0 : if (err < 0) {
93 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "Invalid ingress QOS map");
94 : 0 : return err;
95 : : }
96 : 0 : err = vlan_validate_qos_map(data[IFLA_VLAN_EGRESS_QOS]);
97 [ # # ]: 0 : if (err < 0) {
98 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "Invalid egress QOS map");
99 : 0 : return err;
100 : : }
101 : : return 0;
102 : : }
103 : :
104 : 0 : static 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 [ # # ]: 0 : if (data[IFLA_VLAN_FLAGS]) {
114 : : flags = nla_data(data[IFLA_VLAN_FLAGS]);
115 : 0 : err = vlan_dev_change_flags(dev, flags->flags, flags->mask);
116 [ # # ]: 0 : if (err)
117 : : return err;
118 : : }
119 [ # # ]: 0 : if (data[IFLA_VLAN_INGRESS_QOS]) {
120 [ # # ]: 0 : nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) {
121 : : m = nla_data(attr);
122 : 0 : vlan_dev_set_ingress_priority(dev, m->to, m->from);
123 : : }
124 : : }
125 [ # # ]: 0 : if (data[IFLA_VLAN_EGRESS_QOS]) {
126 [ # # ]: 0 : nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) {
127 : : m = nla_data(attr);
128 : 0 : err = vlan_dev_set_egress_priority(dev, m->from, m->to);
129 [ # # ]: 0 : if (err)
130 : 0 : return err;
131 : : }
132 : : }
133 : : return 0;
134 : : }
135 : :
136 : 0 : static 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 [ # # ]: 0 : if (!data[IFLA_VLAN_ID]) {
147 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "VLAN id not specified");
148 : : return -EINVAL;
149 : : }
150 : :
151 [ # # ]: 0 : if (!tb[IFLA_LINK]) {
152 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "link not specified");
153 : : return -EINVAL;
154 : : }
155 : :
156 : 0 : real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
157 [ # # ]: 0 : if (!real_dev) {
158 [ # # ]: 0 : NL_SET_ERR_MSG_MOD(extack, "link does not exist");
159 : : return -ENODEV;
160 : : }
161 : :
162 [ # # ]: 0 : if (data[IFLA_VLAN_PROTOCOL])
163 : : proto = nla_get_be16(data[IFLA_VLAN_PROTOCOL]);
164 : : else
165 : : proto = htons(ETH_P_8021Q);
166 : :
167 : 0 : vlan->vlan_proto = proto;
168 : 0 : vlan->vlan_id = nla_get_u16(data[IFLA_VLAN_ID]);
169 : 0 : vlan->real_dev = real_dev;
170 : 0 : dev->priv_flags |= (real_dev->priv_flags & IFF_XMIT_DST_RELEASE);
171 : 0 : vlan->flags = VLAN_FLAG_REORDER_HDR;
172 : :
173 : 0 : err = vlan_check_real_dev(real_dev, vlan->vlan_proto, vlan->vlan_id,
174 : : extack);
175 [ # # ]: 0 : if (err < 0)
176 : : return err;
177 : :
178 [ # # ]: 0 : max_mtu = netif_reduces_vlan_mtu(real_dev) ? real_dev->mtu - VLAN_HLEN :
179 : : real_dev->mtu;
180 [ # # ]: 0 : if (!tb[IFLA_MTU])
181 : 0 : dev->mtu = max_mtu;
182 [ # # ]: 0 : else if (dev->mtu > max_mtu)
183 : : return -EINVAL;
184 : :
185 : 0 : err = vlan_changelink(dev, tb, data, extack);
186 [ # # ]: 0 : if (!err)
187 : 0 : err = register_vlan_dev(dev, extack);
188 [ # # ]: 0 : if (err)
189 : 0 : vlan_dev_uninit(dev);
190 : 0 : return err;
191 : : }
192 : :
193 : : static inline size_t vlan_qos_map_size(unsigned int n)
194 : : {
195 [ # # # # ]: 0 : if (n == 0)
196 : : return 0;
197 : : /* IFLA_VLAN_{EGRESS,INGRESS}_QOS + n * IFLA_VLAN_QOS_MAPPING */
198 : 0 : return nla_total_size(sizeof(struct nlattr)) +
199 : 0 : nla_total_size(sizeof(struct ifla_vlan_qos_mapping)) * n;
200 : : }
201 : :
202 : 0 : static size_t vlan_get_size(const struct net_device *dev)
203 : : {
204 : : struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
205 : :
206 : 0 : return nla_total_size(2) + /* IFLA_VLAN_PROTOCOL */
207 : : nla_total_size(2) + /* IFLA_VLAN_ID */
208 : 0 : nla_total_size(sizeof(struct ifla_vlan_flags)) + /* IFLA_VLAN_FLAGS */
209 : 0 : vlan_qos_map_size(vlan->nr_ingress_mappings) +
210 : 0 : vlan_qos_map_size(vlan->nr_egress_mappings);
211 : : }
212 : :
213 : 0 : static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
214 : : {
215 : : struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
216 : : struct vlan_priority_tci_mapping *pm;
217 : : struct ifla_vlan_flags f;
218 : : struct ifla_vlan_qos_mapping m;
219 : : struct nlattr *nest;
220 : : unsigned int i;
221 : :
222 [ # # # # ]: 0 : if (nla_put_be16(skb, IFLA_VLAN_PROTOCOL, vlan->vlan_proto) ||
223 : 0 : nla_put_u16(skb, IFLA_VLAN_ID, vlan->vlan_id))
224 : : goto nla_put_failure;
225 [ # # ]: 0 : if (vlan->flags) {
226 : 0 : f.flags = vlan->flags;
227 : 0 : f.mask = ~0;
228 [ # # ]: 0 : if (nla_put(skb, IFLA_VLAN_FLAGS, sizeof(f), &f))
229 : : goto nla_put_failure;
230 : : }
231 [ # # ]: 0 : if (vlan->nr_ingress_mappings) {
232 : : nest = nla_nest_start_noflag(skb, IFLA_VLAN_INGRESS_QOS);
233 [ # # ]: 0 : if (nest == NULL)
234 : : goto nla_put_failure;
235 : :
236 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(vlan->ingress_priority_map); i++) {
237 [ # # ]: 0 : if (!vlan->ingress_priority_map[i])
238 : 0 : continue;
239 : :
240 : 0 : m.from = i;
241 : 0 : m.to = vlan->ingress_priority_map[i];
242 [ # # ]: 0 : if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
243 : : sizeof(m), &m))
244 : : goto nla_put_failure;
245 : : }
246 : : nla_nest_end(skb, nest);
247 : : }
248 : :
249 [ # # ]: 0 : if (vlan->nr_egress_mappings) {
250 : : nest = nla_nest_start_noflag(skb, IFLA_VLAN_EGRESS_QOS);
251 [ # # ]: 0 : if (nest == NULL)
252 : : goto nla_put_failure;
253 : :
254 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
255 [ # # ]: 0 : for (pm = vlan->egress_priority_map[i]; pm;
256 : 0 : pm = pm->next) {
257 [ # # ]: 0 : if (!pm->vlan_qos)
258 : 0 : continue;
259 : :
260 : 0 : m.from = pm->priority;
261 : 0 : m.to = (pm->vlan_qos >> 13) & 0x7;
262 [ # # ]: 0 : if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
263 : : sizeof(m), &m))
264 : : goto nla_put_failure;
265 : : }
266 : : }
267 : : nla_nest_end(skb, nest);
268 : : }
269 : : return 0;
270 : :
271 : : nla_put_failure:
272 : : return -EMSGSIZE;
273 : : }
274 : :
275 : 0 : static struct net *vlan_get_link_net(const struct net_device *dev)
276 : : {
277 : 0 : struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
278 : :
279 : 0 : return dev_net(real_dev);
280 : : }
281 : :
282 : : struct rtnl_link_ops vlan_link_ops __read_mostly = {
283 : : .kind = "vlan",
284 : : .maxtype = IFLA_VLAN_MAX,
285 : : .policy = vlan_policy,
286 : : .priv_size = sizeof(struct vlan_dev_priv),
287 : : .setup = vlan_setup,
288 : : .validate = vlan_validate,
289 : : .newlink = vlan_newlink,
290 : : .changelink = vlan_changelink,
291 : : .dellink = unregister_vlan_dev,
292 : : .get_size = vlan_get_size,
293 : : .fill_info = vlan_fill_info,
294 : : .get_link_net = vlan_get_link_net,
295 : : };
296 : :
297 : 207 : int __init vlan_netlink_init(void)
298 : : {
299 : 207 : return rtnl_link_register(&vlan_link_ops);
300 : : }
301 : :
302 : 0 : void __exit vlan_netlink_fini(void)
303 : : {
304 : 0 : rtnl_link_unregister(&vlan_link_ops);
305 : 0 : }
306 : :
307 : : MODULE_ALIAS_RTNL_LINK("vlan");
|