diff options
-rw-r--r-- | net/ipv6/seg6_local.c | 211 |
1 files changed, 193 insertions, 18 deletions
diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c index 53615d7e0723..ab1fc1b17ddf 100644 --- a/net/ipv6/seg6_local.c +++ b/net/ipv6/seg6_local.c | |||
@@ -104,6 +104,181 @@ static const struct nla_policy seg6_local_policy[SEG6_LOCAL_MAX + 1] = { | |||
104 | [SEG6_LOCAL_OIF] = { .type = NLA_U32 }, | 104 | [SEG6_LOCAL_OIF] = { .type = NLA_U32 }, |
105 | }; | 105 | }; |
106 | 106 | ||
107 | static int parse_nla_srh(struct nlattr **attrs, struct seg6_local_lwt *slwt) | ||
108 | { | ||
109 | struct ipv6_sr_hdr *srh; | ||
110 | int len; | ||
111 | |||
112 | srh = nla_data(attrs[SEG6_LOCAL_SRH]); | ||
113 | len = nla_len(attrs[SEG6_LOCAL_SRH]); | ||
114 | |||
115 | /* SRH must contain at least one segment */ | ||
116 | if (len < sizeof(*srh) + sizeof(struct in6_addr)) | ||
117 | return -EINVAL; | ||
118 | |||
119 | if (!seg6_validate_srh(srh, len)) | ||
120 | return -EINVAL; | ||
121 | |||
122 | slwt->srh = kmalloc(len, GFP_KERNEL); | ||
123 | if (!slwt->srh) | ||
124 | return -ENOMEM; | ||
125 | |||
126 | memcpy(slwt->srh, srh, len); | ||
127 | |||
128 | slwt->headroom += len; | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int put_nla_srh(struct sk_buff *skb, struct seg6_local_lwt *slwt) | ||
134 | { | ||
135 | struct ipv6_sr_hdr *srh; | ||
136 | struct nlattr *nla; | ||
137 | int len; | ||
138 | |||
139 | srh = slwt->srh; | ||
140 | len = (srh->hdrlen + 1) << 3; | ||
141 | |||
142 | nla = nla_reserve(skb, SEG6_LOCAL_SRH, len); | ||
143 | if (!nla) | ||
144 | return -EMSGSIZE; | ||
145 | |||
146 | memcpy(nla_data(nla), srh, len); | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int cmp_nla_srh(struct seg6_local_lwt *a, struct seg6_local_lwt *b) | ||
152 | { | ||
153 | int len = (a->srh->hdrlen + 1) << 3; | ||
154 | |||
155 | if (len != ((b->srh->hdrlen + 1) << 3)) | ||
156 | return 1; | ||
157 | |||
158 | return memcmp(a->srh, b->srh, len); | ||
159 | } | ||
160 | |||
161 | static int parse_nla_table(struct nlattr **attrs, struct seg6_local_lwt *slwt) | ||
162 | { | ||
163 | slwt->table = nla_get_u32(attrs[SEG6_LOCAL_TABLE]); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int put_nla_table(struct sk_buff *skb, struct seg6_local_lwt *slwt) | ||
169 | { | ||
170 | if (nla_put_u32(skb, SEG6_LOCAL_TABLE, slwt->table)) | ||
171 | return -EMSGSIZE; | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int cmp_nla_table(struct seg6_local_lwt *a, struct seg6_local_lwt *b) | ||
177 | { | ||
178 | if (a->table != b->table) | ||
179 | return 1; | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int parse_nla_nh4(struct nlattr **attrs, struct seg6_local_lwt *slwt) | ||
185 | { | ||
186 | memcpy(&slwt->nh4, nla_data(attrs[SEG6_LOCAL_NH4]), | ||
187 | sizeof(struct in_addr)); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static int put_nla_nh4(struct sk_buff *skb, struct seg6_local_lwt *slwt) | ||
193 | { | ||
194 | struct nlattr *nla; | ||
195 | |||
196 | nla = nla_reserve(skb, SEG6_LOCAL_NH4, sizeof(struct in_addr)); | ||
197 | if (!nla) | ||
198 | return -EMSGSIZE; | ||
199 | |||
200 | memcpy(nla_data(nla), &slwt->nh4, sizeof(struct in_addr)); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int cmp_nla_nh4(struct seg6_local_lwt *a, struct seg6_local_lwt *b) | ||
206 | { | ||
207 | return memcmp(&a->nh4, &b->nh4, sizeof(struct in_addr)); | ||
208 | } | ||
209 | |||
210 | static int parse_nla_nh6(struct nlattr **attrs, struct seg6_local_lwt *slwt) | ||
211 | { | ||
212 | memcpy(&slwt->nh6, nla_data(attrs[SEG6_LOCAL_NH6]), | ||
213 | sizeof(struct in6_addr)); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int put_nla_nh6(struct sk_buff *skb, struct seg6_local_lwt *slwt) | ||
219 | { | ||
220 | struct nlattr *nla; | ||
221 | |||
222 | nla = nla_reserve(skb, SEG6_LOCAL_NH6, sizeof(struct in6_addr)); | ||
223 | if (!nla) | ||
224 | return -EMSGSIZE; | ||
225 | |||
226 | memcpy(nla_data(nla), &slwt->nh6, sizeof(struct in6_addr)); | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static int cmp_nla_nh6(struct seg6_local_lwt *a, struct seg6_local_lwt *b) | ||
232 | { | ||
233 | return memcmp(&a->nh6, &b->nh6, sizeof(struct in6_addr)); | ||
234 | } | ||
235 | |||
236 | static int parse_nla_iif(struct nlattr **attrs, struct seg6_local_lwt *slwt) | ||
237 | { | ||
238 | slwt->iif = nla_get_u32(attrs[SEG6_LOCAL_IIF]); | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int put_nla_iif(struct sk_buff *skb, struct seg6_local_lwt *slwt) | ||
244 | { | ||
245 | if (nla_put_u32(skb, SEG6_LOCAL_IIF, slwt->iif)) | ||
246 | return -EMSGSIZE; | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static int cmp_nla_iif(struct seg6_local_lwt *a, struct seg6_local_lwt *b) | ||
252 | { | ||
253 | if (a->iif != b->iif) | ||
254 | return 1; | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int parse_nla_oif(struct nlattr **attrs, struct seg6_local_lwt *slwt) | ||
260 | { | ||
261 | slwt->oif = nla_get_u32(attrs[SEG6_LOCAL_OIF]); | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int put_nla_oif(struct sk_buff *skb, struct seg6_local_lwt *slwt) | ||
267 | { | ||
268 | if (nla_put_u32(skb, SEG6_LOCAL_OIF, slwt->oif)) | ||
269 | return -EMSGSIZE; | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int cmp_nla_oif(struct seg6_local_lwt *a, struct seg6_local_lwt *b) | ||
275 | { | ||
276 | if (a->oif != b->oif) | ||
277 | return 1; | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
107 | struct seg6_action_param { | 282 | struct seg6_action_param { |
108 | int (*parse)(struct nlattr **attrs, struct seg6_local_lwt *slwt); | 283 | int (*parse)(struct nlattr **attrs, struct seg6_local_lwt *slwt); |
109 | int (*put)(struct sk_buff *skb, struct seg6_local_lwt *slwt); | 284 | int (*put)(struct sk_buff *skb, struct seg6_local_lwt *slwt); |
@@ -111,29 +286,29 @@ struct seg6_action_param { | |||
111 | }; | 286 | }; |
112 | 287 | ||
113 | static struct seg6_action_param seg6_action_params[SEG6_LOCAL_MAX + 1] = { | 288 | static struct seg6_action_param seg6_action_params[SEG6_LOCAL_MAX + 1] = { |
114 | [SEG6_LOCAL_SRH] = { .parse = NULL, | 289 | [SEG6_LOCAL_SRH] = { .parse = parse_nla_srh, |
115 | .put = NULL, | 290 | .put = put_nla_srh, |
116 | .cmp = NULL }, | 291 | .cmp = cmp_nla_srh }, |
117 | 292 | ||
118 | [SEG6_LOCAL_TABLE] = { .parse = NULL, | 293 | [SEG6_LOCAL_TABLE] = { .parse = parse_nla_table, |
119 | .put = NULL, | 294 | .put = put_nla_table, |
120 | .cmp = NULL }, | 295 | .cmp = cmp_nla_table }, |
121 | 296 | ||
122 | [SEG6_LOCAL_NH4] = { .parse = NULL, | 297 | [SEG6_LOCAL_NH4] = { .parse = parse_nla_nh4, |
123 | .put = NULL, | 298 | .put = put_nla_nh4, |
124 | .cmp = NULL }, | 299 | .cmp = cmp_nla_nh4 }, |
125 | 300 | ||
126 | [SEG6_LOCAL_NH6] = { .parse = NULL, | 301 | [SEG6_LOCAL_NH6] = { .parse = parse_nla_nh6, |
127 | .put = NULL, | 302 | .put = put_nla_nh6, |
128 | .cmp = NULL }, | 303 | .cmp = cmp_nla_nh6 }, |
129 | 304 | ||
130 | [SEG6_LOCAL_IIF] = { .parse = NULL, | 305 | [SEG6_LOCAL_IIF] = { .parse = parse_nla_iif, |
131 | .put = NULL, | 306 | .put = put_nla_iif, |
132 | .cmp = NULL }, | 307 | .cmp = cmp_nla_iif }, |
133 | 308 | ||
134 | [SEG6_LOCAL_OIF] = { .parse = NULL, | 309 | [SEG6_LOCAL_OIF] = { .parse = parse_nla_oif, |
135 | .put = NULL, | 310 | .put = put_nla_oif, |
136 | .cmp = NULL }, | 311 | .cmp = cmp_nla_oif }, |
137 | }; | 312 | }; |
138 | 313 | ||
139 | static int parse_nla_action(struct nlattr **attrs, struct seg6_local_lwt *slwt) | 314 | static int parse_nla_action(struct nlattr **attrs, struct seg6_local_lwt *slwt) |