OSDN Git Service

bridge: tunnel: fix attribute checks in br_parse_vlan_tunnel_info
[tomoyo/tomoyo-test1.git] / net / bridge / br_netlink_tunnel.c
1 /*
2  *      Bridge per vlan tunnel port dst_metadata netlink control interface
3  *
4  *      Authors:
5  *      Roopa Prabhu            <roopa@cumulusnetworks.com>
6  *
7  *      This program is free software; you can redistribute it and/or
8  *      modify it under the terms of the GNU General Public License
9  *      as published by the Free Software Foundation; either version
10  *      2 of the License, or (at your option) any later version.
11  */
12
13 #include <linux/kernel.h>
14 #include <linux/slab.h>
15 #include <linux/etherdevice.h>
16 #include <net/rtnetlink.h>
17 #include <net/net_namespace.h>
18 #include <net/sock.h>
19 #include <uapi/linux/if_bridge.h>
20 #include <net/dst_metadata.h>
21
22 #include "br_private.h"
23 #include "br_private_tunnel.h"
24
25 static size_t __get_vlan_tinfo_size(void)
26 {
27         return nla_total_size(0) + /* nest IFLA_BRIDGE_VLAN_TUNNEL_INFO */
28                   nla_total_size(sizeof(u32)) + /* IFLA_BRIDGE_VLAN_TUNNEL_ID */
29                   nla_total_size(sizeof(u16)) + /* IFLA_BRIDGE_VLAN_TUNNEL_VID */
30                   nla_total_size(sizeof(u16)); /* IFLA_BRIDGE_VLAN_TUNNEL_FLAGS */
31 }
32
33 static bool vlan_tunnel_id_isrange(struct net_bridge_vlan *v,
34                                    struct net_bridge_vlan *v_end)
35 {
36         __be32 tunid_curr = tunnel_id_to_key32(v->tinfo.tunnel_id);
37         __be32 tunid_end = tunnel_id_to_key32(v_end->tinfo.tunnel_id);
38
39         return (be32_to_cpu(tunid_curr) - be32_to_cpu(tunid_end)) == 1;
40 }
41
42 static int __get_num_vlan_tunnel_infos(struct net_bridge_vlan_group *vg)
43 {
44         struct net_bridge_vlan *v, *v_start = NULL, *v_end = NULL;
45         int num_tinfos = 0;
46
47         /* Count number of vlan infos */
48         list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
49                 /* only a context, bridge vlan not activated */
50                 if (!br_vlan_should_use(v) || !v->tinfo.tunnel_id)
51                         continue;
52
53                 if (!v_start) {
54                         goto initvars;
55                 } else if ((v->vid - v_end->vid) == 1 &&
56                            vlan_tunnel_id_isrange(v_end, v) == 1) {
57                         v_end = v;
58                         continue;
59                 } else {
60                         if ((v_end->vid - v->vid) > 0 &&
61                             vlan_tunnel_id_isrange(v_end, v) > 0)
62                                 num_tinfos += 2;
63                         else
64                                 num_tinfos += 1;
65                 }
66 initvars:
67                 v_start = v;
68                 v_end = v;
69         }
70
71         if (v_start) {
72                 if ((v_end->vid - v->vid) > 0 &&
73                     vlan_tunnel_id_isrange(v_end, v) > 0)
74                         num_tinfos += 2;
75                 else
76                         num_tinfos += 1;
77         }
78
79         return num_tinfos;
80 }
81
82 int br_get_vlan_tunnel_info_size(struct net_bridge_vlan_group *vg)
83 {
84         int num_tinfos;
85
86         if (!vg)
87                 return 0;
88
89         rcu_read_lock();
90         num_tinfos = __get_num_vlan_tunnel_infos(vg);
91         rcu_read_unlock();
92
93         return num_tinfos * __get_vlan_tinfo_size();
94 }
95
96 static int br_fill_vlan_tinfo(struct sk_buff *skb, u16 vid,
97                               __be64 tunnel_id, u16 flags)
98 {
99         __be32 tid = tunnel_id_to_key32(tunnel_id);
100         struct nlattr *tmap;
101
102         tmap = nla_nest_start(skb, IFLA_BRIDGE_VLAN_TUNNEL_INFO);
103         if (!tmap)
104                 return -EMSGSIZE;
105         if (nla_put_u32(skb, IFLA_BRIDGE_VLAN_TUNNEL_ID,
106                         be32_to_cpu(tid)))
107                 goto nla_put_failure;
108         if (nla_put_u16(skb, IFLA_BRIDGE_VLAN_TUNNEL_VID,
109                         vid))
110                 goto nla_put_failure;
111         if (nla_put_u16(skb, IFLA_BRIDGE_VLAN_TUNNEL_FLAGS,
112                         flags))
113                 goto nla_put_failure;
114         nla_nest_end(skb, tmap);
115
116         return 0;
117
118 nla_put_failure:
119         nla_nest_cancel(skb, tmap);
120
121         return -EMSGSIZE;
122 }
123
124 static int br_fill_vlan_tinfo_range(struct sk_buff *skb,
125                                     struct net_bridge_vlan *vtbegin,
126                                     struct net_bridge_vlan *vtend)
127 {
128         int err;
129
130         if (vtbegin && vtend && (vtend->vid - vtbegin->vid) > 0) {
131                 /* add range to skb */
132                 err = br_fill_vlan_tinfo(skb, vtbegin->vid,
133                                          vtbegin->tinfo.tunnel_id,
134                                          BRIDGE_VLAN_INFO_RANGE_BEGIN);
135                 if (err)
136                         return err;
137
138                 err = br_fill_vlan_tinfo(skb, vtend->vid,
139                                          vtend->tinfo.tunnel_id,
140                                          BRIDGE_VLAN_INFO_RANGE_END);
141                 if (err)
142                         return err;
143         } else {
144                 err = br_fill_vlan_tinfo(skb, vtbegin->vid,
145                                          vtbegin->tinfo.tunnel_id,
146                                          0);
147                 if (err)
148                         return err;
149         }
150
151         return 0;
152 }
153
154 int br_fill_vlan_tunnel_info(struct sk_buff *skb,
155                              struct net_bridge_vlan_group *vg)
156 {
157         struct net_bridge_vlan *vtbegin = NULL;
158         struct net_bridge_vlan *vtend = NULL;
159         struct net_bridge_vlan *v;
160         int err;
161
162         /* Count number of vlan infos */
163         list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
164                 /* only a context, bridge vlan not activated */
165                 if (!br_vlan_should_use(v))
166                         continue;
167
168                 if (!v->tinfo.tunnel_dst)
169                         continue;
170
171                 if (!vtbegin) {
172                         goto initvars;
173                 } else if ((v->vid - vtend->vid) == 1 &&
174                             vlan_tunnel_id_isrange(v, vtend)) {
175                         vtend = v;
176                         continue;
177                 } else {
178                         err = br_fill_vlan_tinfo_range(skb, vtbegin, vtend);
179                         if (err)
180                                 return err;
181                 }
182 initvars:
183                 vtbegin = v;
184                 vtend = v;
185         }
186
187         if (vtbegin) {
188                 err = br_fill_vlan_tinfo_range(skb, vtbegin, vtend);
189                 if (err)
190                         return err;
191         }
192
193         return 0;
194 }
195
196 static const struct nla_policy vlan_tunnel_policy[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1] = {
197         [IFLA_BRIDGE_VLAN_TUNNEL_ID] = { .type = NLA_U32 },
198         [IFLA_BRIDGE_VLAN_TUNNEL_VID] = { .type = NLA_U16 },
199         [IFLA_BRIDGE_VLAN_TUNNEL_FLAGS] = { .type = NLA_U16 },
200 };
201
202 static int br_vlan_tunnel_info(struct net_bridge_port *p, int cmd,
203                                u16 vid, u32 tun_id)
204 {
205         int err = 0;
206
207         if (!p)
208                 return -EINVAL;
209
210         switch (cmd) {
211         case RTM_SETLINK:
212                 err = nbp_vlan_tunnel_info_add(p, vid, tun_id);
213                 break;
214         case RTM_DELLINK:
215                 nbp_vlan_tunnel_info_delete(p, vid);
216                 break;
217         }
218
219         return err;
220 }
221
222 int br_parse_vlan_tunnel_info(struct nlattr *attr,
223                               struct vtunnel_info *tinfo)
224 {
225         struct nlattr *tb[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1];
226         u32 tun_id;
227         u16 vid, flags = 0;
228         int err;
229
230         memset(tinfo, 0, sizeof(*tinfo));
231
232         err = nla_parse_nested(tb, IFLA_BRIDGE_VLAN_TUNNEL_MAX,
233                                attr, vlan_tunnel_policy);
234         if (err < 0)
235                 return err;
236
237         if (!tb[IFLA_BRIDGE_VLAN_TUNNEL_ID] ||
238             !tb[IFLA_BRIDGE_VLAN_TUNNEL_VID])
239                 return -EINVAL;
240
241         tun_id = nla_get_u32(tb[IFLA_BRIDGE_VLAN_TUNNEL_ID]);
242         vid = nla_get_u16(tb[IFLA_BRIDGE_VLAN_TUNNEL_VID]);
243         if (vid >= VLAN_VID_MASK)
244                 return -ERANGE;
245
246         if (tb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS])
247                 flags = nla_get_u16(tb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]);
248
249         tinfo->tunid = tun_id;
250         tinfo->vid = vid;
251         tinfo->flags = flags;
252
253         return 0;
254 }
255
256 int br_process_vlan_tunnel_info(struct net_bridge *br,
257                                 struct net_bridge_port *p, int cmd,
258                                 struct vtunnel_info *tinfo_curr,
259                                 struct vtunnel_info *tinfo_last)
260 {
261         int err;
262
263         if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
264                 if (tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
265                         return -EINVAL;
266                 memcpy(tinfo_last, tinfo_curr, sizeof(struct vtunnel_info));
267         } else if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_END) {
268                 int t, v;
269
270                 if (!(tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN))
271                         return -EINVAL;
272                 if ((tinfo_curr->vid - tinfo_last->vid) !=
273                     (tinfo_curr->tunid - tinfo_last->tunid))
274                         return -EINVAL;
275                 t = tinfo_last->tunid;
276                 for (v = tinfo_last->vid; v <= tinfo_curr->vid; v++) {
277                         err = br_vlan_tunnel_info(p, cmd, v, t);
278                         if (err)
279                                 return err;
280                         t++;
281                 }
282                 memset(tinfo_last, 0, sizeof(struct vtunnel_info));
283                 memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
284         } else {
285                 if (tinfo_last->flags)
286                         return -EINVAL;
287                 err = br_vlan_tunnel_info(p, cmd, tinfo_curr->vid,
288                                           tinfo_curr->tunid);
289                 if (err)
290                         return err;
291                 memset(tinfo_last, 0, sizeof(struct vtunnel_info));
292                 memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
293         }
294
295         return 0;
296 }