]>
Commit | Line | Data |
---|---|---|
f45fd316 OF |
1 | /* |
2 | * BIRD -- OSPF | |
3 | * | |
6f3203fa | 4 | * (c) 1999--2004 Ondrej Filip <feela@network.cz> |
77edab64 OZ |
5 | * (c) 2009--2015 Ondrej Zajicek <santiago@crfreenet.org> |
6 | * (c) 2009--2015 CZ.NIC z.s.p.o. | |
f45fd316 OF |
7 | * |
8 | * Can be freely distributed and used under the terms of the GNU GPL. | |
9 | */ | |
10 | ||
11 | #include "ospf.h" | |
12 | ||
77edab64 | 13 | #include "lib/fletcher16.h" |
c45f48fb | 14 | |
1a2ad348 OZ |
15 | #define HDRLEN sizeof(struct ospf_lsa_header) |
16 | ||
17 | ||
4e5fb4b6 | 18 | #ifndef CPU_BIG_ENDIAN |
f45fd316 | 19 | void |
70945cb6 | 20 | lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n) |
f45fd316 | 21 | { |
2e10a170 | 22 | n->age = htons(h->age); |
70945cb6 | 23 | n->type_raw = htons(h->type_raw); |
2e10a170 OF |
24 | n->id = htonl(h->id); |
25 | n->rt = htonl(h->rt); | |
26 | n->sn = htonl(h->sn); | |
27 | n->checksum = htons(h->checksum); | |
28 | n->length = htons(h->length); | |
c15e5690 | 29 | } |
f45fd316 OF |
30 | |
31 | void | |
70945cb6 | 32 | lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h) |
f45fd316 | 33 | { |
2e10a170 | 34 | h->age = ntohs(n->age); |
70945cb6 | 35 | h->type_raw = ntohs(n->type_raw); |
2e10a170 OF |
36 | h->id = ntohl(n->id); |
37 | h->rt = ntohl(n->rt); | |
38 | h->sn = ntohl(n->sn); | |
39 | h->checksum = ntohs(n->checksum); | |
40 | h->length = ntohs(n->length); | |
c15e5690 | 41 | } |
f45fd316 OF |
42 | |
43 | void | |
70945cb6 | 44 | lsa_hton_body(void *h, void *n, u16 len) |
f45fd316 | 45 | { |
c15e5690 OZ |
46 | u32 *hid = h; |
47 | u32 *nid = n; | |
70945cb6 | 48 | uint i; |
f45fd316 | 49 | |
c15e5690 OZ |
50 | for (i = 0; i < (len / sizeof(u32)); i++) |
51 | nid[i] = htonl(hid[i]); | |
52 | } | |
f45fd316 OF |
53 | |
54 | void | |
70945cb6 | 55 | lsa_ntoh_body(void *n, void *h, u16 len) |
f45fd316 | 56 | { |
c15e5690 OZ |
57 | u32 *nid = n; |
58 | u32 *hid = h; | |
70945cb6 | 59 | uint i; |
f45fd316 | 60 | |
c15e5690 OZ |
61 | for (i = 0; i < (len / sizeof(u32)); i++) |
62 | hid[i] = ntohl(nid[i]); | |
63 | } | |
4e5fb4b6 | 64 | #endif /* little endian */ |
f45fd316 | 65 | |
70945cb6 | 66 | |
70945cb6 OZ |
67 | int |
68 | lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa) | |
742029eb | 69 | { |
70945cb6 OZ |
70 | /* Handle inactive vlinks */ |
71 | if (ifa->state == OSPF_IS_DOWN) | |
72 | return 0; | |
742029eb | 73 | |
70945cb6 OZ |
74 | /* 4.5.2 (Case 2) */ |
75 | switch (LSA_SCOPE(type)) | |
76 | { | |
77 | case LSA_SCOPE_LINK: | |
78 | return ifa->iface_id == domain; | |
79 | ||
80 | case LSA_SCOPE_AREA: | |
81 | return ifa->oa->areaid == domain; | |
82 | ||
83 | case LSA_SCOPE_AS: | |
84 | if (ifa->type == OSPF_IT_VLINK) | |
85 | return 0; | |
86 | if (!oa_is_ext(ifa->oa)) | |
87 | return 0; | |
88 | return 1; | |
89 | ||
90 | default: | |
91 | log(L_ERR "OSPF: LSA with invalid scope"); | |
92 | return 0; | |
93 | } | |
94 | } | |
95 | ||
5a50a989 OZ |
96 | int |
97 | lsa_is_acceptable(u32 type, struct ospf_neighbor *n, struct ospf_proto *p) | |
98 | { | |
99 | if (ospf_is_v2(p)) | |
100 | { | |
101 | if (type == LSA_T_NSSA) | |
102 | return !!(n->options & OPT_N); | |
103 | ||
104 | if (lsa_is_opaque(type)) | |
105 | return !!(n->options & OPT_O); | |
106 | ||
107 | return 1; | |
108 | } | |
109 | else | |
110 | { | |
111 | /* | |
112 | * There should be check whether receiving router understands that type | |
113 | * of LSA (for LSA types with U-bit == 0). But as we do not support any | |
114 | * optional LSA types, this is not needed yet. | |
115 | */ | |
116 | ||
117 | return 1; | |
118 | } | |
119 | } | |
70945cb6 OZ |
120 | |
121 | static int | |
122 | unknown_lsa_type(u32 type) | |
123 | { | |
124 | switch (type) | |
125 | { | |
126 | case LSA_T_RT: | |
127 | case LSA_T_NET: | |
128 | case LSA_T_SUM_NET: | |
129 | case LSA_T_SUM_RT: | |
130 | case LSA_T_EXT: | |
131 | case LSA_T_NSSA: | |
132 | case LSA_T_LINK: | |
133 | case LSA_T_PREFIX: | |
5a50a989 OZ |
134 | case LSA_T_RI_LINK: |
135 | case LSA_T_RI_AREA: | |
136 | case LSA_T_RI_AS: | |
70945cb6 OZ |
137 | return 0; |
138 | ||
139 | default: | |
140 | return 1; | |
141 | } | |
142 | } | |
143 | ||
5a50a989 OZ |
144 | /* Maps OSPFv2 types to OSPFv3 types */ |
145 | static const u16 lsa_v2_types[] = { | |
146 | 0, LSA_T_RT, LSA_T_NET, LSA_T_SUM_NET, LSA_T_SUM_RT, LSA_T_EXT, 0, LSA_T_NSSA, | |
147 | 0, LSA_T_OPAQUE_LINK, LSA_T_OPAQUE_AREA, LSA_T_OPAQUE_AS | |
148 | }; | |
149 | ||
150 | /* Maps OSPFv2 opaque types to OSPFv3 function codes */ | |
151 | static const u16 opaque_lsa_types[] = { | |
1a2ad348 | 152 | [LSA_OT_GR] = LSA_T_GR, |
5a50a989 OZ |
153 | [LSA_OT_RI] = LSA_T_RI_, |
154 | }; | |
155 | ||
156 | /* Maps (subset of) OSPFv3 function codes to OSPFv2 opaque types */ | |
157 | static const u8 opaque_lsa_types_inv[] = { | |
1a2ad348 | 158 | [LSA_T_GR] = LSA_OT_GR, |
5a50a989 OZ |
159 | [LSA_T_RI_] = LSA_OT_RI, |
160 | }; | |
161 | ||
162 | #define LOOKUP(a, i) ({ uint _i = (i); (_i < ARRAY_SIZE(a)) ? a[_i] : 0; }) | |
70945cb6 OZ |
163 | |
164 | void | |
5a50a989 | 165 | lsa_get_type_domain_(u32 type, u32 id, struct ospf_iface *ifa, u32 *otype, u32 *domain) |
70945cb6 OZ |
166 | { |
167 | if (ospf_is_v2(ifa->oa->po)) | |
168 | { | |
5a50a989 OZ |
169 | type = type & LSA_T_V2_MASK; |
170 | type = LOOKUP(lsa_v2_types, type); | |
171 | ||
172 | uint code; | |
173 | if (LSA_FUNCTION(type) == LSA_T_OPAQUE_) | |
174 | if (code = LOOKUP(opaque_lsa_types, id >> 24)) | |
1a2ad348 | 175 | { |
5a50a989 | 176 | type = code | LSA_UBIT | LSA_SCOPE(type); |
1a2ad348 OZ |
177 | |
178 | /* Hack for Grace-LSA: It does not use U-bit for link-scoped LSAs */ | |
179 | if (type == (LSA_T_GR | LSA_UBIT)) | |
180 | type = LSA_T_GR; | |
181 | } | |
70945cb6 OZ |
182 | } |
183 | else | |
184 | { | |
185 | /* For unkown LSAs without U-bit change scope to LSA_SCOPE_LINK */ | |
5a50a989 OZ |
186 | if (unknown_lsa_type(type) && !(type & LSA_UBIT)) |
187 | type = type & ~LSA_SCOPE_MASK; | |
70945cb6 OZ |
188 | } |
189 | ||
5a50a989 | 190 | *otype = type; |
70945cb6 | 191 | |
5a50a989 | 192 | switch (LSA_SCOPE(type)) |
70945cb6 OZ |
193 | { |
194 | case LSA_SCOPE_LINK: | |
195 | *domain = ifa->iface_id; | |
196 | return; | |
197 | ||
198 | case LSA_SCOPE_AREA: | |
199 | *domain = ifa->oa->areaid; | |
200 | return; | |
201 | ||
202 | case LSA_SCOPE_AS: | |
203 | default: | |
204 | *domain = 0; | |
205 | return; | |
206 | } | |
207 | } | |
208 | ||
1a2ad348 OZ |
209 | int |
210 | lsa_is_opaque(u32 type) | |
211 | { | |
212 | u32 fn = LSA_FUNCTION(type); | |
213 | return LOOKUP(opaque_lsa_types_inv, fn) || (fn == LSA_T_OPAQUE_); | |
214 | } | |
215 | ||
5a50a989 OZ |
216 | u32 |
217 | lsa_get_opaque_type(u32 type) | |
218 | { | |
219 | return LOOKUP(opaque_lsa_types_inv, LSA_FUNCTION(type)); | |
220 | } | |
221 | ||
70945cb6 | 222 | |
061ab802 | 223 | void |
77edab64 | 224 | lsa_generate_checksum(struct ospf_lsa_header *lsa, const u8 *body) |
061ab802 | 225 | { |
77edab64 OZ |
226 | struct fletcher16_context ctx; |
227 | struct ospf_lsa_header hdr; | |
228 | u16 len = lsa->length; | |
061ab802 | 229 | |
f9c799a0 | 230 | /* |
77edab64 OZ |
231 | * lsa and body are in the host order, we need to compute Fletcher-16 checksum |
232 | * for data in the network order. We also skip the initial age field. | |
233 | */ | |
394acced | 234 | |
77edab64 OZ |
235 | lsa_hton_hdr(lsa, &hdr); |
236 | hdr.checksum = 0; | |
2e10a170 | 237 | |
77edab64 OZ |
238 | fletcher16_init(&ctx); |
239 | fletcher16_update(&ctx, (u8 *) &hdr + 2, sizeof(struct ospf_lsa_header) - 2); | |
240 | fletcher16_update_n32(&ctx, body, len - sizeof(struct ospf_lsa_header)); | |
241 | lsa->checksum = fletcher16_final(&ctx, len, OFFSETOF(struct ospf_lsa_header, checksum)); | |
394acced OF |
242 | } |
243 | ||
394acced | 244 | u16 |
77edab64 | 245 | lsa_verify_checksum(const void *lsa_n, int lsa_len) |
499cb346 | 246 | { |
77edab64 | 247 | struct fletcher16_context ctx; |
499cb346 | 248 | |
77edab64 | 249 | /* The whole LSA is at lsa_n in net order, we just skip initial age field */ |
30d09eb9 | 250 | |
77edab64 OZ |
251 | fletcher16_init(&ctx); |
252 | fletcher16_update(&ctx, (u8 *) lsa_n + 2, lsa_len - 2); | |
499cb346 | 253 | |
77edab64 | 254 | return fletcher16_compute(&ctx) == 0; |
499cb346 OF |
255 | } |
256 | ||
77edab64 | 257 | |
db9fb727 OF |
258 | int |
259 | lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2) | |
394acced | 260 | /* Return codes from point of view of l1 */ |
db9fb727 | 261 | { |
2e10a170 | 262 | u32 sn1, sn2; |
37282678 | 263 | |
2e10a170 OF |
264 | sn1 = l1->sn - LSA_INITSEQNO + 1; |
265 | sn2 = l2->sn - LSA_INITSEQNO + 1; | |
37282678 | 266 | |
2e10a170 OF |
267 | if (sn1 > sn2) |
268 | return CMP_NEWER; | |
269 | if (sn1 < sn2) | |
270 | return CMP_OLDER; | |
ef6f26b4 | 271 | |
2e10a170 OF |
272 | if (l1->checksum != l2->checksum) |
273 | return l1->checksum < l2->checksum ? CMP_OLDER : CMP_NEWER; | |
ef6f26b4 | 274 | |
2e10a170 OF |
275 | if ((l1->age == LSA_MAXAGE) && (l2->age != LSA_MAXAGE)) |
276 | return CMP_NEWER; | |
277 | if ((l2->age == LSA_MAXAGE) && (l1->age != LSA_MAXAGE)) | |
278 | return CMP_OLDER; | |
ef6f26b4 | 279 | |
2e10a170 OF |
280 | if (ABS(l1->age - l2->age) > LSA_MAXAGEDIFF) |
281 | return l1->age < l2->age ? CMP_NEWER : CMP_OLDER; | |
ef6f26b4 OF |
282 | |
283 | return CMP_SAME; | |
db9fb727 OF |
284 | } |
285 | ||
a6bc04d5 | 286 | |
1a2ad348 OZ |
287 | #define LSA_TLV_LENGTH(tlv) \ |
288 | (sizeof(struct ospf_tlv) + BIRD_ALIGN((tlv)->length, 4)) | |
289 | ||
290 | #define LSA_NEXT_TLV(tlv) \ | |
291 | ((struct ospf_tlv *) ((byte *) (tlv) + LSA_TLV_LENGTH(tlv))) | |
292 | ||
293 | #define LSA_WALK_TLVS(tlv,buf,len) \ | |
294 | for(struct ospf_tlv *tlv = (void *) (buf); \ | |
295 | (byte *) tlv < (byte *) (buf) + (len); \ | |
296 | tlv = LSA_NEXT_TLV(tlv)) | |
297 | ||
298 | struct ospf_tlv * | |
299 | lsa_get_tlv(struct top_hash_entry *en, uint type) | |
300 | { | |
301 | LSA_WALK_TLVS(tlv, en->lsa_body, en->lsa.length - HDRLEN) | |
302 | if (tlv->type == type) | |
303 | return tlv; | |
304 | ||
305 | return NULL; | |
306 | } | |
307 | ||
308 | int | |
309 | lsa_validate_tlvs(byte *buf, uint len) | |
310 | { | |
311 | byte *pos = buf; | |
312 | byte *end = buf + len; | |
313 | ||
314 | while (pos < end) | |
315 | { | |
316 | if ((pos + sizeof(struct ospf_tlv)) > end) | |
317 | return 0; | |
318 | ||
319 | struct ospf_tlv *tlv = (void *) pos; | |
320 | uint len = LSA_TLV_LENGTH(tlv); | |
321 | ||
322 | if ((pos + len) > end) | |
323 | return 0; | |
324 | ||
325 | pos += len; | |
326 | } | |
327 | ||
328 | return 1; | |
329 | } | |
330 | ||
331 | ||
70945cb6 OZ |
332 | static inline int |
333 | lsa_walk_rt2(struct ospf_lsa_rt_walk *rt) | |
a6bc04d5 | 334 | { |
70945cb6 | 335 | if (rt->buf >= rt->bufend) |
a6bc04d5 OZ |
336 | return 0; |
337 | ||
70945cb6 OZ |
338 | struct ospf_lsa_rt2_link *l = rt->buf; |
339 | rt->buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos); | |
a6bc04d5 | 340 | |
70945cb6 OZ |
341 | rt->type = l->type; |
342 | rt->metric = l->metric; | |
343 | rt->id = l->id; | |
344 | rt->data = l->data; | |
345 | return 1; | |
346 | } | |
a6bc04d5 | 347 | |
70945cb6 OZ |
348 | static inline int |
349 | lsa_walk_rt3(struct ospf_lsa_rt_walk *rt) | |
350 | { | |
351 | while (rt->buf >= rt->bufend) | |
a6bc04d5 | 352 | { |
70945cb6 OZ |
353 | rt->en = ospf_hash_find_rt3_next(rt->en); |
354 | if (!rt->en) | |
a6bc04d5 | 355 | return 0; |
70945cb6 OZ |
356 | |
357 | rt->buf = rt->en->lsa_body; | |
358 | rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header); | |
359 | rt->buf += sizeof(struct ospf_lsa_rt); | |
a6bc04d5 | 360 | } |
70945cb6 OZ |
361 | |
362 | struct ospf_lsa_rt3_link *l = rt->buf; | |
363 | rt->buf += sizeof(struct ospf_lsa_rt3_link); | |
364 | ||
365 | rt->type = l->type; | |
366 | rt->metric = l->metric; | |
367 | rt->lif = l->lif; | |
368 | rt->nif = l->nif; | |
369 | rt->id = l->id; | |
a6bc04d5 OZ |
370 | return 1; |
371 | } | |
372 | ||
70945cb6 OZ |
373 | void |
374 | lsa_walk_rt_init(struct ospf_proto *p, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt) | |
375 | { | |
376 | rt->ospf2 = ospf_is_v2(p); | |
377 | rt->id = rt->data = rt->lif = rt->nif = 0; | |
378 | ||
379 | if (rt->ospf2) | |
380 | rt->en = act; | |
381 | else | |
382 | rt->en = ospf_hash_find_rt3_first(p->gr, act->domain, act->lsa.rt); | |
383 | ||
384 | rt->buf = rt->en->lsa_body; | |
385 | rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header); | |
386 | rt->buf += sizeof(struct ospf_lsa_rt); | |
387 | } | |
388 | ||
389 | int | |
390 | lsa_walk_rt(struct ospf_lsa_rt_walk *rt) | |
391 | { | |
392 | return rt->ospf2 ? lsa_walk_rt2(rt) : lsa_walk_rt3(rt); | |
393 | } | |
394 | ||
395 | ||
396 | void | |
d3f4f92b | 397 | lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u8 *pxopts, u32 *metric) |
70945cb6 OZ |
398 | { |
399 | if (ospf2) | |
400 | { | |
4a3f5b36 | 401 | uint opts = lsa_get_options(&en->lsa); |
70945cb6 | 402 | struct ospf_lsa_sum2 *ls = en->lsa_body; |
fe9f1a6d | 403 | net_fill_ip4(net, ip4_from_u32(en->lsa.id & ls->netmask), u32_masklen(ls->netmask)); |
4a3f5b36 | 404 | *pxopts = (opts & OPT_DN) ? OPT_PX_DN : 0; |
70945cb6 OZ |
405 | *metric = ls->metric & LSA_METRIC_MASK; |
406 | } | |
407 | else | |
408 | { | |
409 | struct ospf_lsa_sum3_net *ls = en->lsa_body; | |
d3f4f92b | 410 | ospf3_get_prefix(ls->prefix, af, net, pxopts, NULL); |
70945cb6 OZ |
411 | *metric = ls->metric & LSA_METRIC_MASK; |
412 | } | |
413 | } | |
414 | ||
415 | void | |
416 | lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options) | |
417 | { | |
418 | if (ospf2) | |
419 | { | |
420 | struct ospf_lsa_sum2 *ls = en->lsa_body; | |
421 | *drid = en->lsa.id; | |
422 | *metric = ls->metric & LSA_METRIC_MASK; | |
423 | *options = 0; | |
424 | } | |
425 | else | |
426 | { | |
427 | struct ospf_lsa_sum3_rt *ls = en->lsa_body; | |
428 | *drid = ls->drid; | |
429 | *metric = ls->metric & LSA_METRIC_MASK; | |
430 | *options = ls->options & LSA_OPTIONS_MASK; | |
431 | } | |
432 | } | |
433 | ||
434 | void | |
d3f4f92b | 435 | lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_local *rt) |
70945cb6 OZ |
436 | { |
437 | if (ospf2) | |
438 | { | |
439 | struct ospf_lsa_ext2 *ext = en->lsa_body; | |
fe9f1a6d OZ |
440 | net_fill_ip4(&rt->net, |
441 | ip4_from_u32(en->lsa.id & ext->netmask), | |
442 | u32_masklen(ext->netmask)); | |
70945cb6 OZ |
443 | rt->pxopts = 0; |
444 | rt->metric = ext->metric & LSA_METRIC_MASK; | |
445 | rt->ebit = ext->metric & LSA_EXT2_EBIT; | |
446 | ||
447 | rt->fbit = ext->fwaddr; | |
448 | rt->fwaddr = ipa_from_u32(ext->fwaddr); | |
449 | ||
450 | rt->tag = ext->tag; | |
451 | rt->propagate = lsa_get_options(&en->lsa) & OPT_P; | |
4a3f5b36 | 452 | rt->downwards = lsa_get_options(&en->lsa) & OPT_DN; |
70945cb6 OZ |
453 | } |
454 | else | |
455 | { | |
456 | struct ospf_lsa_ext3 *ext = en->lsa_body; | |
d3f4f92b | 457 | u32 *buf = ospf3_get_prefix(ext->rest, af, &rt->net, &rt->pxopts, NULL); |
70945cb6 OZ |
458 | rt->metric = ext->metric & LSA_METRIC_MASK; |
459 | rt->ebit = ext->metric & LSA_EXT3_EBIT; | |
460 | ||
461 | rt->fbit = ext->metric & LSA_EXT3_FBIT; | |
462 | if (rt->fbit) | |
d3f4f92b | 463 | buf = ospf3_get_addr(buf, af, &rt->fwaddr); |
742029eb | 464 | else |
70945cb6 OZ |
465 | rt->fwaddr = IPA_NONE; |
466 | ||
467 | rt->tag = (ext->metric & LSA_EXT3_TBIT) ? *buf++ : 0; | |
468 | rt->propagate = rt->pxopts & OPT_PX_P; | |
4a3f5b36 | 469 | rt->downwards = rt->pxopts & OPT_PX_DN; |
70945cb6 OZ |
470 | } |
471 | } | |
472 | ||
70945cb6 | 473 | |
a6bc04d5 | 474 | static int |
70945cb6 | 475 | lsa_validate_rt2(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body) |
a6bc04d5 | 476 | { |
70945cb6 OZ |
477 | if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt))) |
478 | return 0; | |
479 | ||
480 | uint i = 0; | |
481 | void *buf = body; | |
482 | void *bufend = buf + lsa->length - HDRLEN; | |
483 | buf += sizeof(struct ospf_lsa_rt); | |
484 | ||
485 | while (buf < bufend) | |
486 | { | |
487 | struct ospf_lsa_rt2_link *l = buf; | |
488 | buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos); | |
489 | i++; | |
490 | ||
491 | if (buf > bufend) | |
492 | return 0; | |
493 | ||
494 | if (!((l->type == LSART_PTP) || | |
495 | (l->type == LSART_NET) || | |
496 | (l->type == LSART_STUB) || | |
497 | (l->type == LSART_VLNK))) | |
498 | return 0; | |
499 | } | |
500 | ||
501 | if ((body->options & LSA_RT2_LINKS) != i) | |
a6bc04d5 OZ |
502 | return 0; |
503 | ||
504 | return 1; | |
505 | } | |
506 | ||
a6bc04d5 OZ |
507 | |
508 | static int | |
70945cb6 | 509 | lsa_validate_rt3(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body) |
a6bc04d5 | 510 | { |
70945cb6 | 511 | if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt))) |
a6bc04d5 OZ |
512 | return 0; |
513 | ||
70945cb6 OZ |
514 | void *buf = body; |
515 | void *bufend = buf + lsa->length - HDRLEN; | |
516 | buf += sizeof(struct ospf_lsa_rt); | |
517 | ||
518 | while (buf < bufend) | |
519 | { | |
520 | struct ospf_lsa_rt3_link *l = buf; | |
521 | buf += sizeof(struct ospf_lsa_rt3_link); | |
522 | ||
523 | if (buf > bufend) | |
524 | return 0; | |
525 | ||
526 | if (!((l->type == LSART_PTP) || | |
527 | (l->type == LSART_NET) || | |
528 | (l->type == LSART_VLNK))) | |
529 | return 0; | |
530 | } | |
531 | return 1; | |
532 | } | |
533 | ||
534 | static int | |
535 | lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED) | |
536 | { | |
537 | if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_net))) | |
a6bc04d5 OZ |
538 | return 0; |
539 | ||
540 | return 1; | |
541 | } | |
a6bc04d5 OZ |
542 | |
543 | static int | |
70945cb6 | 544 | lsa_validate_sum2(struct ospf_lsa_header *lsa, struct ospf_lsa_sum2 *body) |
a6bc04d5 | 545 | { |
70945cb6 | 546 | if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum2))) |
a6bc04d5 OZ |
547 | return 0; |
548 | ||
549 | /* First field should have TOS = 0, we ignore other TOS fields */ | |
70945cb6 | 550 | if ((body->metric & LSA_SUM2_TOS) != 0) |
a6bc04d5 OZ |
551 | return 0; |
552 | ||
553 | return 1; | |
554 | } | |
555 | ||
a6bc04d5 OZ |
556 | static inline int |
557 | pxlen(u32 *buf) | |
558 | { | |
559 | return *buf >> 24; | |
560 | } | |
561 | ||
562 | static int | |
70945cb6 | 563 | lsa_validate_sum3_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body) |
a6bc04d5 | 564 | { |
70945cb6 | 565 | if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 4)) |
a6bc04d5 OZ |
566 | return 0; |
567 | ||
568 | u8 pxl = pxlen(body->prefix); | |
fe9f1a6d | 569 | if (pxl > IP6_MAX_PREFIX_LENGTH) |
a6bc04d5 OZ |
570 | return 0; |
571 | ||
742029eb | 572 | if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + |
a6bc04d5 OZ |
573 | IPV6_PREFIX_SPACE(pxl))) |
574 | return 0; | |
575 | ||
576 | return 1; | |
577 | } | |
578 | ||
70945cb6 | 579 | static int |
3e236955 | 580 | lsa_validate_sum3_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body UNUSED) |
70945cb6 OZ |
581 | { |
582 | if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt))) | |
583 | return 0; | |
584 | ||
585 | return 1; | |
586 | } | |
a6bc04d5 OZ |
587 | |
588 | static int | |
70945cb6 | 589 | lsa_validate_ext2(struct ospf_lsa_header *lsa, struct ospf_lsa_ext2 *body) |
a6bc04d5 | 590 | { |
70945cb6 OZ |
591 | if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext2))) |
592 | return 0; | |
593 | ||
594 | /* First field should have TOS = 0, we ignore other TOS fields */ | |
595 | if ((body->metric & LSA_EXT2_TOS) != 0) | |
a6bc04d5 OZ |
596 | return 0; |
597 | ||
598 | return 1; | |
599 | } | |
600 | ||
601 | static int | |
70945cb6 | 602 | lsa_validate_ext3(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body) |
a6bc04d5 | 603 | { |
70945cb6 | 604 | if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext3) + 4)) |
a6bc04d5 OZ |
605 | return 0; |
606 | ||
607 | u8 pxl = pxlen(body->rest); | |
fe9f1a6d | 608 | if (pxl > IP6_MAX_PREFIX_LENGTH) |
a6bc04d5 OZ |
609 | return 0; |
610 | ||
611 | int len = IPV6_PREFIX_SPACE(pxl); | |
d7661fbe | 612 | if (body->metric & LSA_EXT3_FBIT) // forwarding address |
a6bc04d5 | 613 | len += 16; |
70945cb6 | 614 | if (body->metric & LSA_EXT3_TBIT) // route tag |
a6bc04d5 OZ |
615 | len += 4; |
616 | if (*body->rest & 0xFFFF) // referenced LS type field | |
617 | len += 4; | |
618 | ||
70945cb6 | 619 | if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext3) + len)) |
a6bc04d5 OZ |
620 | return 0; |
621 | ||
622 | return 1; | |
623 | } | |
624 | ||
625 | static int | |
70945cb6 | 626 | lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, uint offset, u8 *pbuf) |
a6bc04d5 | 627 | { |
70945cb6 | 628 | uint bound = lsa->length - HDRLEN - 4; |
a6bc04d5 OZ |
629 | u32 i; |
630 | ||
631 | for (i = 0; i < pxcount; i++) | |
632 | { | |
633 | if (offset > bound) | |
634 | return 0; | |
635 | ||
636 | u8 pxl = pxlen((u32 *) (pbuf + offset)); | |
fe9f1a6d | 637 | if (pxl > IP6_MAX_PREFIX_LENGTH) |
a6bc04d5 | 638 | return 0; |
742029eb | 639 | |
a6bc04d5 OZ |
640 | offset += IPV6_PREFIX_SPACE(pxl); |
641 | } | |
642 | ||
643 | if (lsa->length != (HDRLEN + offset)) | |
644 | return 0; | |
645 | ||
646 | return 1; | |
647 | } | |
648 | ||
649 | static int | |
650 | lsa_validate_link(struct ospf_lsa_header *lsa, struct ospf_lsa_link *body) | |
651 | { | |
652 | if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_link))) | |
653 | return 0; | |
654 | ||
655 | return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_link), (u8 *) body); | |
656 | } | |
657 | ||
658 | static int | |
659 | lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body) | |
660 | { | |
661 | if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_prefix))) | |
662 | return 0; | |
663 | ||
664 | return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body); | |
665 | } | |
666 | ||
1a2ad348 OZ |
667 | static int |
668 | lsa_validate_gr(struct ospf_lsa_header *lsa, void *body) | |
669 | { | |
670 | return lsa_validate_tlvs(body, lsa->length - HDRLEN); | |
671 | } | |
672 | ||
5a50a989 OZ |
673 | static int |
674 | lsa_validate_ri(struct ospf_lsa_header *lsa UNUSED, struct ospf_lsa_net *body UNUSED) | |
675 | { | |
676 | /* | |
677 | * There should be proper validation. But we do not really process RI LSAs, so | |
678 | * we can just accept them like another unknown opaque LSAs. | |
679 | */ | |
680 | ||
681 | return 1; | |
682 | } | |
683 | ||
a6bc04d5 OZ |
684 | |
685 | /** | |
686 | * lsa_validate - check whether given LSA is valid | |
687 | * @lsa: LSA header | |
af678af0 OZ |
688 | * @lsa_type: internal LSA type (%LSA_T_xxx) |
689 | * @ospf2: %true for OSPFv2, %false for OSPFv3 | |
a6bc04d5 OZ |
690 | * @body: pointer to LSA body |
691 | * | |
692 | * Checks internal structure of given LSA body (minimal length, | |
693 | * consistency). Returns true if valid. | |
694 | */ | |
a6bc04d5 | 695 | int |
70945cb6 | 696 | lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body) |
a6bc04d5 | 697 | { |
70945cb6 OZ |
698 | if (ospf2) |
699 | { | |
700 | switch (lsa_type) | |
701 | { | |
702 | case LSA_T_RT: | |
703 | return lsa_validate_rt2(lsa, body); | |
704 | case LSA_T_NET: | |
705 | return lsa_validate_net(lsa, body); | |
706 | case LSA_T_SUM_NET: | |
707 | return lsa_validate_sum2(lsa, body); | |
708 | case LSA_T_SUM_RT: | |
709 | return lsa_validate_sum2(lsa, body); | |
710 | case LSA_T_EXT: | |
711 | case LSA_T_NSSA: | |
712 | return lsa_validate_ext2(lsa, body); | |
1a2ad348 OZ |
713 | case LSA_T_GR: |
714 | return lsa_validate_gr(lsa, body); | |
5a50a989 OZ |
715 | case LSA_T_RI_LINK: |
716 | case LSA_T_RI_AREA: | |
717 | case LSA_T_RI_AS: | |
718 | return lsa_validate_ri(lsa, body); | |
719 | case LSA_T_OPAQUE_LINK: | |
720 | case LSA_T_OPAQUE_AREA: | |
721 | case LSA_T_OPAQUE_AS: | |
722 | return 1; /* Unknown Opaque LSAs */ | |
70945cb6 OZ |
723 | default: |
724 | return 0; /* Should not happen, unknown LSAs are already rejected */ | |
725 | } | |
726 | } | |
727 | else | |
728 | { | |
729 | switch (lsa_type) | |
a6bc04d5 OZ |
730 | { |
731 | case LSA_T_RT: | |
70945cb6 | 732 | return lsa_validate_rt3(lsa, body); |
a6bc04d5 OZ |
733 | case LSA_T_NET: |
734 | return lsa_validate_net(lsa, body); | |
735 | case LSA_T_SUM_NET: | |
70945cb6 | 736 | return lsa_validate_sum3_net(lsa, body); |
a6bc04d5 | 737 | case LSA_T_SUM_RT: |
70945cb6 | 738 | return lsa_validate_sum3_rt(lsa, body); |
a6bc04d5 | 739 | case LSA_T_EXT: |
41b612c3 | 740 | case LSA_T_NSSA: |
70945cb6 | 741 | return lsa_validate_ext3(lsa, body); |
a6bc04d5 OZ |
742 | case LSA_T_LINK: |
743 | return lsa_validate_link(lsa, body); | |
744 | case LSA_T_PREFIX: | |
745 | return lsa_validate_prefix(lsa, body); | |
1a2ad348 OZ |
746 | case LSA_T_GR: |
747 | return lsa_validate_gr(lsa, body); | |
5a50a989 OZ |
748 | case LSA_T_RI_LINK: |
749 | case LSA_T_RI_AREA: | |
750 | case LSA_T_RI_AS: | |
751 | return lsa_validate_ri(lsa, body); | |
a6bc04d5 | 752 | default: |
70945cb6 | 753 | return 1; /* Unknown LSAs are OK in OSPFv3 */ |
a6bc04d5 | 754 | } |
85195f1a | 755 | } |
d8852b36 | 756 | } |