Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vlan_netlink.c
Go to the documentation of this file.
1 /*
2  * VLAN netlink control interface
3  *
4  * Copyright (c) 2007 Patrick McHardy <[email protected]>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  */
10 
11 #include <linux/kernel.h>
12 #include <linux/netdevice.h>
13 #include <linux/if_vlan.h>
14 #include <linux/module.h>
15 #include <net/net_namespace.h>
16 #include <net/netlink.h>
17 #include <net/rtnetlink.h>
18 #include "vlan.h"
19 
20 
21 static const struct nla_policy vlan_policy[IFLA_VLAN_MAX + 1] = {
22  [IFLA_VLAN_ID] = { .type = NLA_U16 },
23  [IFLA_VLAN_FLAGS] = { .len = sizeof(struct ifla_vlan_flags) },
24  [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED },
25  [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
26 };
27 
28 static const struct nla_policy vlan_map_policy[IFLA_VLAN_QOS_MAX + 1] = {
29  [IFLA_VLAN_QOS_MAPPING] = { .len = sizeof(struct ifla_vlan_qos_mapping) },
30 };
31 
32 
33 static inline int vlan_validate_qos_map(struct nlattr *attr)
34 {
35  if (!attr)
36  return 0;
37  return nla_validate_nested(attr, IFLA_VLAN_QOS_MAX, vlan_map_policy);
38 }
39 
40 static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])
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  return -EINVAL;
49  if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
50  return -EADDRNOTAVAIL;
51  }
52 
53  if (!data)
54  return -EINVAL;
55 
56  if (data[IFLA_VLAN_ID]) {
57  id = nla_get_u16(data[IFLA_VLAN_ID]);
58  if (id >= VLAN_VID_MASK)
59  return -ERANGE;
60  }
61  if (data[IFLA_VLAN_FLAGS]) {
62  flags = nla_data(data[IFLA_VLAN_FLAGS]);
63  if ((flags->flags & flags->mask) &
66  return -EINVAL;
67  }
68 
69  err = vlan_validate_qos_map(data[IFLA_VLAN_INGRESS_QOS]);
70  if (err < 0)
71  return err;
72  err = vlan_validate_qos_map(data[IFLA_VLAN_EGRESS_QOS]);
73  if (err < 0)
74  return err;
75  return 0;
76 }
77 
78 static int vlan_changelink(struct net_device *dev,
79  struct nlattr *tb[], struct nlattr *data[])
80 {
81  struct ifla_vlan_flags *flags;
82  struct ifla_vlan_qos_mapping *m;
83  struct nlattr *attr;
84  int rem;
85 
86  if (data[IFLA_VLAN_FLAGS]) {
87  flags = nla_data(data[IFLA_VLAN_FLAGS]);
88  vlan_dev_change_flags(dev, flags->flags, flags->mask);
89  }
90  if (data[IFLA_VLAN_INGRESS_QOS]) {
91  nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) {
92  m = nla_data(attr);
94  }
95  }
96  if (data[IFLA_VLAN_EGRESS_QOS]) {
97  nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) {
98  m = nla_data(attr);
100  }
101  }
102  return 0;
103 }
104 
105 static int vlan_newlink(struct net *src_net, struct net_device *dev,
106  struct nlattr *tb[], struct nlattr *data[])
107 {
108  struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
109  struct net_device *real_dev;
110  int err;
111 
112  if (!data[IFLA_VLAN_ID])
113  return -EINVAL;
114 
115  if (!tb[IFLA_LINK])
116  return -EINVAL;
117  real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
118  if (!real_dev)
119  return -ENODEV;
120 
121  vlan->vlan_id = nla_get_u16(data[IFLA_VLAN_ID]);
122  vlan->real_dev = real_dev;
124 
125  err = vlan_check_real_dev(real_dev, vlan->vlan_id);
126  if (err < 0)
127  return err;
128 
129  if (!tb[IFLA_MTU])
130  dev->mtu = real_dev->mtu;
131  else if (dev->mtu > real_dev->mtu)
132  return -EINVAL;
133 
134  err = vlan_changelink(dev, tb, data);
135  if (err < 0)
136  return err;
137 
138  return register_vlan_dev(dev);
139 }
140 
141 static inline size_t vlan_qos_map_size(unsigned int n)
142 {
143  if (n == 0)
144  return 0;
145  /* IFLA_VLAN_{EGRESS,INGRESS}_QOS + n * IFLA_VLAN_QOS_MAPPING */
146  return nla_total_size(sizeof(struct nlattr)) +
147  nla_total_size(sizeof(struct ifla_vlan_qos_mapping)) * n;
148 }
149 
150 static size_t vlan_get_size(const struct net_device *dev)
151 {
152  struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
153 
154  return nla_total_size(2) + /* IFLA_VLAN_ID */
155  sizeof(struct ifla_vlan_flags) + /* IFLA_VLAN_FLAGS */
156  vlan_qos_map_size(vlan->nr_ingress_mappings) +
157  vlan_qos_map_size(vlan->nr_egress_mappings);
158 }
159 
160 static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
161 {
162  struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
164  struct ifla_vlan_flags f;
165  struct ifla_vlan_qos_mapping m;
166  struct nlattr *nest;
167  unsigned int i;
168 
169  if (nla_put_u16(skb, IFLA_VLAN_ID, vlan_dev_priv(dev)->vlan_id))
170  goto nla_put_failure;
171  if (vlan->flags) {
172  f.flags = vlan->flags;
173  f.mask = ~0;
174  if (nla_put(skb, IFLA_VLAN_FLAGS, sizeof(f), &f))
175  goto nla_put_failure;
176  }
177  if (vlan->nr_ingress_mappings) {
178  nest = nla_nest_start(skb, IFLA_VLAN_INGRESS_QOS);
179  if (nest == NULL)
180  goto nla_put_failure;
181 
182  for (i = 0; i < ARRAY_SIZE(vlan->ingress_priority_map); i++) {
183  if (!vlan->ingress_priority_map[i])
184  continue;
185 
186  m.from = i;
187  m.to = vlan->ingress_priority_map[i];
189  sizeof(m), &m))
190  goto nla_put_failure;
191  }
192  nla_nest_end(skb, nest);
193  }
194 
195  if (vlan->nr_egress_mappings) {
196  nest = nla_nest_start(skb, IFLA_VLAN_EGRESS_QOS);
197  if (nest == NULL)
198  goto nla_put_failure;
199 
200  for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
201  for (pm = vlan->egress_priority_map[i]; pm;
202  pm = pm->next) {
203  if (!pm->vlan_qos)
204  continue;
205 
206  m.from = pm->priority;
207  m.to = (pm->vlan_qos >> 13) & 0x7;
209  sizeof(m), &m))
210  goto nla_put_failure;
211  }
212  }
213  nla_nest_end(skb, nest);
214  }
215  return 0;
216 
217 nla_put_failure:
218  return -EMSGSIZE;
219 }
220 
222  .kind = "vlan",
223  .maxtype = IFLA_VLAN_MAX,
224  .policy = vlan_policy,
225  .priv_size = sizeof(struct vlan_dev_priv),
226  .setup = vlan_setup,
227  .validate = vlan_validate,
228  .newlink = vlan_newlink,
229  .changelink = vlan_changelink,
230  .dellink = unregister_vlan_dev,
231  .get_size = vlan_get_size,
232  .fill_info = vlan_fill_info,
233 };
234 
236 {
238 }
239 
241 {
243 }
244 
245 MODULE_ALIAS_RTNL_LINK("vlan");