| 
									
										
										
										
											2000-03-31 00:21:41 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *	BIRD -- OSPF | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-06-04 21:05:43 +00:00
										 |  |  |  *	(c) 1999--2004 Ondrej Filip <feela@network.cz> | 
					
						
							| 
									
										
										
										
											2015-05-01 14:40:56 +02:00
										 |  |  |  *	(c) 2009--2015 Ondrej Zajicek <santiago@crfreenet.org> | 
					
						
							|  |  |  |  *	(c) 2009--2015 CZ.NIC z.s.p.o. | 
					
						
							| 
									
										
										
										
											2000-03-31 00:21:41 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  *	Can be freely distributed and used under the terms of the GNU GPL. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "ospf.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-01 14:40:56 +02:00
										 |  |  | #include "lib/fletcher16.h"
 | 
					
						
							| 
									
										
										
										
											2000-05-02 22:19:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-30 20:12:59 +02:00
										 |  |  | #define HDRLEN sizeof(struct ospf_lsa_header)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-25 20:12:34 +02:00
										 |  |  | #ifndef CPU_BIG_ENDIAN
 | 
					
						
							| 
									
										
										
										
											2000-03-31 00:21:41 +00:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n) | 
					
						
							| 
									
										
										
										
											2000-03-31 00:21:41 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2004-06-06 09:37:54 +00:00
										 |  |  |   n->age = htons(h->age); | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   n->type_raw = htons(h->type_raw); | 
					
						
							| 
									
										
										
										
											2004-06-06 09:37:54 +00:00
										 |  |  |   n->id = htonl(h->id); | 
					
						
							|  |  |  |   n->rt = htonl(h->rt); | 
					
						
							|  |  |  |   n->sn = htonl(h->sn); | 
					
						
							|  |  |  |   n->checksum = htons(h->checksum); | 
					
						
							|  |  |  |   n->length = htons(h->length); | 
					
						
							| 
									
										
										
										
											2009-09-08 17:06:47 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2000-03-31 00:21:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h) | 
					
						
							| 
									
										
										
										
											2000-03-31 00:21:41 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2004-06-06 09:37:54 +00:00
										 |  |  |   h->age = ntohs(n->age); | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   h->type_raw = ntohs(n->type_raw); | 
					
						
							| 
									
										
										
										
											2004-06-06 09:37:54 +00:00
										 |  |  |   h->id = ntohl(n->id); | 
					
						
							|  |  |  |   h->rt = ntohl(n->rt); | 
					
						
							|  |  |  |   h->sn = ntohl(n->sn); | 
					
						
							|  |  |  |   h->checksum = ntohs(n->checksum); | 
					
						
							|  |  |  |   h->length = ntohs(n->length); | 
					
						
							| 
									
										
										
										
											2009-09-08 17:06:47 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2000-03-31 00:21:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | lsa_hton_body(void *h, void *n, u16 len) | 
					
						
							| 
									
										
										
										
											2000-03-31 00:21:41 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-09-08 17:06:47 +02:00
										 |  |  |   u32 *hid = h; | 
					
						
							|  |  |  |   u32 *nid = n; | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   uint i; | 
					
						
							| 
									
										
										
										
											2000-03-31 00:21:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-08 17:06:47 +02:00
										 |  |  |   for (i = 0; i < (len / sizeof(u32)); i++) | 
					
						
							|  |  |  |     nid[i] = htonl(hid[i]); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2000-03-31 00:21:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | lsa_ntoh_body(void *n, void *h, u16 len) | 
					
						
							| 
									
										
										
										
											2000-03-31 00:21:41 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-09-08 17:06:47 +02:00
										 |  |  |   u32 *nid = n; | 
					
						
							|  |  |  |   u32 *hid = h; | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   uint i; | 
					
						
							| 
									
										
										
										
											2000-03-31 00:21:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-08 17:06:47 +02:00
										 |  |  |   for (i = 0; i < (len / sizeof(u32)); i++) | 
					
						
							|  |  |  |     hid[i] = ntohl(nid[i]); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-04-25 20:12:34 +02:00
										 |  |  | #endif /* little endian */
 | 
					
						
							| 
									
										
										
										
											2000-03-31 00:21:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa) | 
					
						
							| 
									
										
										
										
											2014-07-19 17:28:38 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   /* Handle inactive vlinks */ | 
					
						
							|  |  |  |   if (ifa->state == OSPF_IS_DOWN) | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2014-07-19 17:28:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   /* 4.5.2 (Case 2) */ | 
					
						
							|  |  |  |   switch (LSA_SCOPE(type)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case LSA_SCOPE_LINK: | 
					
						
							|  |  |  |     return ifa->iface_id == domain; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case LSA_SCOPE_AREA: | 
					
						
							|  |  |  |     return ifa->oa->areaid == domain; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case LSA_SCOPE_AS: | 
					
						
							|  |  |  |     if (ifa->type == OSPF_IT_VLINK) | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     if (!oa_is_ext(ifa->oa)) | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     log(L_ERR "OSPF: LSA with invalid scope"); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  | int | 
					
						
							|  |  |  | lsa_is_acceptable(u32 type, struct ospf_neighbor *n, struct ospf_proto *p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (ospf_is_v2(p)) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2019-07-10 18:25:36 +02:00
										 |  |  |     /* Do not check NSSA-LSA here, as OPT_N is only in HELLO packets */ | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (lsa_is_opaque(type)) | 
					
						
							|  |  |  |       return !!(n->options & OPT_O); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * There should be check whether receiving router understands that type | 
					
						
							|  |  |  |      * of LSA (for LSA types with U-bit == 0). But as we do not support any | 
					
						
							|  |  |  |      * optional LSA types, this is not needed yet. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | unknown_lsa_type(u32 type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   switch (type) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case LSA_T_RT: | 
					
						
							|  |  |  |   case LSA_T_NET: | 
					
						
							|  |  |  |   case LSA_T_SUM_NET: | 
					
						
							|  |  |  |   case LSA_T_SUM_RT: | 
					
						
							|  |  |  |   case LSA_T_EXT: | 
					
						
							|  |  |  |   case LSA_T_NSSA: | 
					
						
							|  |  |  |   case LSA_T_LINK: | 
					
						
							|  |  |  |   case LSA_T_PREFIX: | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  |   case LSA_T_RI_LINK: | 
					
						
							|  |  |  |   case LSA_T_RI_AREA: | 
					
						
							|  |  |  |   case LSA_T_RI_AS: | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  | /* Maps OSPFv2 types to OSPFv3 types */ | 
					
						
							|  |  |  | static const u16 lsa_v2_types[] = { | 
					
						
							|  |  |  |   0, LSA_T_RT, LSA_T_NET, LSA_T_SUM_NET, LSA_T_SUM_RT, LSA_T_EXT, 0, LSA_T_NSSA, | 
					
						
							|  |  |  |   0, LSA_T_OPAQUE_LINK, LSA_T_OPAQUE_AREA, LSA_T_OPAQUE_AS | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Maps OSPFv2 opaque types to OSPFv3 function codes */ | 
					
						
							|  |  |  | static const u16 opaque_lsa_types[] = { | 
					
						
							| 
									
										
										
										
											2019-06-30 20:12:59 +02:00
										 |  |  |   [LSA_OT_GR] = LSA_T_GR, | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  |   [LSA_OT_RI] = LSA_T_RI_, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Maps (subset of) OSPFv3 function codes to OSPFv2 opaque types */ | 
					
						
							|  |  |  | static const u8 opaque_lsa_types_inv[] = { | 
					
						
							| 
									
										
										
										
											2019-06-30 20:12:59 +02:00
										 |  |  |   [LSA_T_GR] = LSA_OT_GR, | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  |   [LSA_T_RI_] = LSA_OT_RI, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define LOOKUP(a, i) ({ uint _i = (i); (_i < ARRAY_SIZE(a)) ? a[_i] : 0; })
 | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  | lsa_get_type_domain_(u32 type, u32 id, struct ospf_iface *ifa, u32 *otype, u32 *domain) | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   if (ospf_is_v2(ifa->oa->po)) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  |     type = type & LSA_T_V2_MASK; | 
					
						
							|  |  |  |     type = LOOKUP(lsa_v2_types, type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     uint code; | 
					
						
							|  |  |  |     if (LSA_FUNCTION(type) == LSA_T_OPAQUE_) | 
					
						
							|  |  |  |       if (code = LOOKUP(opaque_lsa_types, id >> 24)) | 
					
						
							| 
									
										
										
										
											2019-06-30 20:12:59 +02:00
										 |  |  |       { | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  | 	type = code | LSA_UBIT | LSA_SCOPE(type); | 
					
						
							| 
									
										
										
										
											2019-06-30 20:12:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Hack for Grace-LSA: It does not use U-bit for link-scoped LSAs */ | 
					
						
							|  |  |  | 	if (type == (LSA_T_GR | LSA_UBIT)) | 
					
						
							|  |  |  | 	  type = LSA_T_GR; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     /* For unkown LSAs without U-bit change scope to LSA_SCOPE_LINK */ | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  |     if (unknown_lsa_type(type) && !(type & LSA_UBIT)) | 
					
						
							|  |  |  |       type = type & ~LSA_SCOPE_MASK; | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  |   *otype = type; | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  |   switch (LSA_SCOPE(type)) | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   { | 
					
						
							|  |  |  |   case LSA_SCOPE_LINK: | 
					
						
							|  |  |  |     *domain = ifa->iface_id; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case LSA_SCOPE_AREA: | 
					
						
							|  |  |  |     *domain = ifa->oa->areaid; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case LSA_SCOPE_AS: | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     *domain = 0; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-30 20:12:59 +02:00
										 |  |  | int | 
					
						
							|  |  |  | lsa_is_opaque(u32 type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   u32 fn = LSA_FUNCTION(type); | 
					
						
							|  |  |  |   return LOOKUP(opaque_lsa_types_inv, fn) || (fn == LSA_T_OPAQUE_); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  | u32 | 
					
						
							|  |  |  | lsa_get_opaque_type(u32 type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return LOOKUP(opaque_lsa_types_inv, LSA_FUNCTION(type)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-27 18:25:46 +02:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											2015-05-01 14:40:56 +02:00
										 |  |  | lsa_generate_checksum(struct ospf_lsa_header *lsa, const u8 *body) | 
					
						
							| 
									
										
										
										
											2009-08-27 18:25:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-05-01 14:40:56 +02:00
										 |  |  |   struct fletcher16_context ctx; | 
					
						
							|  |  |  |   struct ospf_lsa_header hdr; | 
					
						
							|  |  |  |   u16 len = lsa->length; | 
					
						
							| 
									
										
										
										
											2009-08-27 18:25:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-04 11:06:51 +02:00
										 |  |  |   /*
 | 
					
						
							| 
									
										
										
										
											2015-05-01 14:40:56 +02:00
										 |  |  |    * lsa and body are in the host order, we need to compute Fletcher-16 checksum | 
					
						
							|  |  |  |    * for data in the network order. We also skip the initial age field. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2000-04-02 20:41:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-01 14:40:56 +02:00
										 |  |  |   lsa_hton_hdr(lsa, &hdr); | 
					
						
							|  |  |  |   hdr.checksum = 0; | 
					
						
							| 
									
										
										
										
											2004-06-06 09:37:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-01 14:40:56 +02:00
										 |  |  |   fletcher16_init(&ctx); | 
					
						
							|  |  |  |   fletcher16_update(&ctx, (u8 *) &hdr + 2, sizeof(struct ospf_lsa_header) - 2); | 
					
						
							|  |  |  |   fletcher16_update_n32(&ctx, body, len - sizeof(struct ospf_lsa_header)); | 
					
						
							|  |  |  |   lsa->checksum = fletcher16_final(&ctx, len, OFFSETOF(struct ospf_lsa_header, checksum)); | 
					
						
							| 
									
										
										
										
											2000-04-02 20:41:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | u16 | 
					
						
							| 
									
										
										
										
											2015-05-01 14:40:56 +02:00
										 |  |  | lsa_verify_checksum(const void *lsa_n, int lsa_len) | 
					
						
							| 
									
										
										
										
											2000-04-01 02:45:49 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-05-01 14:40:56 +02:00
										 |  |  |   struct fletcher16_context ctx; | 
					
						
							| 
									
										
										
										
											2000-04-01 02:45:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-01 14:40:56 +02:00
										 |  |  |   /* The whole LSA is at lsa_n in net order, we just skip initial age field */ | 
					
						
							| 
									
										
										
										
											2015-04-28 13:45:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-01 14:40:56 +02:00
										 |  |  |   fletcher16_init(&ctx); | 
					
						
							|  |  |  |   fletcher16_update(&ctx, (u8 *) lsa_n + 2, lsa_len - 2); | 
					
						
							| 
									
										
										
										
											2000-04-01 02:45:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-01 14:40:56 +02:00
										 |  |  |   return fletcher16_compute(&ctx) == 0; | 
					
						
							| 
									
										
										
										
											2000-04-01 02:45:49 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-01 14:40:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-04-02 19:04:23 +00:00
										 |  |  | int | 
					
						
							|  |  |  | lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2) | 
					
						
							| 
									
										
										
										
											2000-04-02 20:41:33 +00:00
										 |  |  | 			/* Return codes from point of view of l1 */ | 
					
						
							| 
									
										
										
										
											2000-04-02 19:04:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2004-06-06 09:37:54 +00:00
										 |  |  |   u32 sn1, sn2; | 
					
						
							| 
									
										
										
										
											2000-05-31 18:21:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-06 09:37:54 +00:00
										 |  |  |   sn1 = l1->sn - LSA_INITSEQNO + 1; | 
					
						
							|  |  |  |   sn2 = l2->sn - LSA_INITSEQNO + 1; | 
					
						
							| 
									
										
										
										
											2000-05-31 18:21:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-06 09:37:54 +00:00
										 |  |  |   if (sn1 > sn2) | 
					
						
							|  |  |  |     return CMP_NEWER; | 
					
						
							|  |  |  |   if (sn1 < sn2) | 
					
						
							|  |  |  |     return CMP_OLDER; | 
					
						
							| 
									
										
										
										
											2000-05-30 15:01:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-06 09:37:54 +00:00
										 |  |  |   if (l1->checksum != l2->checksum) | 
					
						
							|  |  |  |     return l1->checksum < l2->checksum ? CMP_OLDER : CMP_NEWER; | 
					
						
							| 
									
										
										
										
											2000-05-30 15:01:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-06 09:37:54 +00:00
										 |  |  |   if ((l1->age == LSA_MAXAGE) && (l2->age != LSA_MAXAGE)) | 
					
						
							|  |  |  |     return CMP_NEWER; | 
					
						
							|  |  |  |   if ((l2->age == LSA_MAXAGE) && (l1->age != LSA_MAXAGE)) | 
					
						
							|  |  |  |     return CMP_OLDER; | 
					
						
							| 
									
										
										
										
											2000-05-30 15:01:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-06 09:37:54 +00:00
										 |  |  |   if (ABS(l1->age - l2->age) > LSA_MAXAGEDIFF) | 
					
						
							|  |  |  |     return l1->age < l2->age ? CMP_NEWER : CMP_OLDER; | 
					
						
							| 
									
										
										
										
											2000-05-30 15:01:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return CMP_SAME; | 
					
						
							| 
									
										
										
										
											2000-04-02 19:04:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-30 20:12:59 +02:00
										 |  |  | #define LSA_TLV_LENGTH(tlv) \
 | 
					
						
							|  |  |  |   (sizeof(struct ospf_tlv) + BIRD_ALIGN((tlv)->length, 4)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define LSA_NEXT_TLV(tlv) \
 | 
					
						
							|  |  |  |   ((struct ospf_tlv *) ((byte *) (tlv) + LSA_TLV_LENGTH(tlv))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define LSA_WALK_TLVS(tlv,buf,len)					\
 | 
					
						
							|  |  |  |   for(struct ospf_tlv *tlv = (void *) (buf);				\ | 
					
						
							|  |  |  |       (byte *) tlv < (byte *) (buf) + (len);				\ | 
					
						
							|  |  |  |       tlv = LSA_NEXT_TLV(tlv)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct ospf_tlv * | 
					
						
							|  |  |  | lsa_get_tlv(struct top_hash_entry *en, uint type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   LSA_WALK_TLVS(tlv, en->lsa_body, en->lsa.length - HDRLEN) | 
					
						
							|  |  |  |     if (tlv->type == type) | 
					
						
							|  |  |  |       return tlv; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | lsa_validate_tlvs(byte *buf, uint len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   byte *pos = buf; | 
					
						
							|  |  |  |   byte *end = buf + len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (pos < end) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if ((pos + sizeof(struct ospf_tlv)) > end) | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     struct ospf_tlv *tlv = (void *) pos; | 
					
						
							|  |  |  |     uint len = LSA_TLV_LENGTH(tlv); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((pos + len) > end) | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pos += len; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | static inline int | 
					
						
							|  |  |  | lsa_walk_rt2(struct ospf_lsa_rt_walk *rt) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   if (rt->buf >= rt->bufend) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   struct ospf_lsa_rt2_link *l = rt->buf; | 
					
						
							|  |  |  |   rt->buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos); | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   rt->type = l->type; | 
					
						
							|  |  |  |   rt->metric = l->metric; | 
					
						
							|  |  |  |   rt->id = l->id; | 
					
						
							|  |  |  |   rt->data = l->data; | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | static inline int | 
					
						
							|  |  |  | lsa_walk_rt3(struct ospf_lsa_rt_walk *rt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   while (rt->buf >= rt->bufend) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |     rt->en = ospf_hash_find_rt3_next(rt->en); | 
					
						
							|  |  |  |     if (!rt->en) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |       return 0; | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     rt->buf = rt->en->lsa_body; | 
					
						
							|  |  |  |     rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header); | 
					
						
							|  |  |  |     rt->buf += sizeof(struct ospf_lsa_rt); | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   struct ospf_lsa_rt3_link *l = rt->buf; | 
					
						
							|  |  |  |   rt->buf += sizeof(struct ospf_lsa_rt3_link); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   rt->type = l->type; | 
					
						
							|  |  |  |   rt->metric = l->metric; | 
					
						
							|  |  |  |   rt->lif = l->lif; | 
					
						
							|  |  |  |   rt->nif = l->nif; | 
					
						
							|  |  |  |   rt->id = l->id; | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | void | 
					
						
							|  |  |  | lsa_walk_rt_init(struct ospf_proto *p, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   rt->ospf2 = ospf_is_v2(p); | 
					
						
							|  |  |  |   rt->id = rt->data = rt->lif = rt->nif = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (rt->ospf2) | 
					
						
							|  |  |  |     rt->en = act; | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     rt->en = ospf_hash_find_rt3_first(p->gr, act->domain, act->lsa.rt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   rt->buf = rt->en->lsa_body; | 
					
						
							|  |  |  |   rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header); | 
					
						
							|  |  |  |   rt->buf += sizeof(struct ospf_lsa_rt); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | lsa_walk_rt(struct ospf_lsa_rt_walk *rt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return rt->ospf2 ? lsa_walk_rt2(rt) : lsa_walk_rt3(rt); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2017-10-09 01:16:29 +02:00
										 |  |  | lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u8 *pxopts, u32 *metric) | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   if (ospf2) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2019-02-13 15:40:22 +01:00
										 |  |  |     uint opts = lsa_get_options(&en->lsa); | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |     struct ospf_lsa_sum2 *ls = en->lsa_body; | 
					
						
							| 
									
										
										
										
											2015-11-05 12:48:52 +01:00
										 |  |  |     net_fill_ip4(net, ip4_from_u32(en->lsa.id & ls->netmask), u32_masklen(ls->netmask)); | 
					
						
							| 
									
										
										
										
											2019-02-13 15:40:22 +01:00
										 |  |  |     *pxopts = (opts & OPT_DN) ? OPT_PX_DN : 0; | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |     *metric = ls->metric & LSA_METRIC_MASK; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     struct ospf_lsa_sum3_net *ls = en->lsa_body; | 
					
						
							| 
									
										
										
										
											2017-10-09 01:16:29 +02:00
										 |  |  |     ospf3_get_prefix(ls->prefix, af, net, pxopts, NULL); | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |     *metric = ls->metric & LSA_METRIC_MASK; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (ospf2) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     struct ospf_lsa_sum2 *ls = en->lsa_body; | 
					
						
							|  |  |  |     *drid = en->lsa.id; | 
					
						
							|  |  |  |     *metric = ls->metric & LSA_METRIC_MASK; | 
					
						
							|  |  |  |     *options = 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     struct ospf_lsa_sum3_rt *ls = en->lsa_body; | 
					
						
							|  |  |  |     *drid = ls->drid; | 
					
						
							|  |  |  |     *metric = ls->metric & LSA_METRIC_MASK; | 
					
						
							|  |  |  |     *options = ls->options & LSA_OPTIONS_MASK; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2017-10-09 01:16:29 +02:00
										 |  |  | lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_local *rt) | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   if (ospf2) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     struct ospf_lsa_ext2 *ext = en->lsa_body; | 
					
						
							| 
									
										
										
										
											2015-11-05 12:48:52 +01:00
										 |  |  |     net_fill_ip4(&rt->net, | 
					
						
							|  |  |  | 		 ip4_from_u32(en->lsa.id & ext->netmask), | 
					
						
							|  |  |  | 		 u32_masklen(ext->netmask)); | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |     rt->pxopts = 0; | 
					
						
							|  |  |  |     rt->metric = ext->metric & LSA_METRIC_MASK; | 
					
						
							|  |  |  |     rt->ebit = ext->metric & LSA_EXT2_EBIT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rt->fbit = ext->fwaddr; | 
					
						
							|  |  |  |     rt->fwaddr = ipa_from_u32(ext->fwaddr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rt->tag = ext->tag; | 
					
						
							|  |  |  |     rt->propagate = lsa_get_options(&en->lsa) & OPT_P; | 
					
						
							| 
									
										
										
										
											2019-02-13 15:40:22 +01:00
										 |  |  |     rt->downwards = lsa_get_options(&en->lsa) & OPT_DN; | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     struct ospf_lsa_ext3 *ext = en->lsa_body; | 
					
						
							| 
									
										
										
										
											2017-10-09 01:16:29 +02:00
										 |  |  |     u32 *buf = ospf3_get_prefix(ext->rest, af, &rt->net, &rt->pxopts, NULL); | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |     rt->metric = ext->metric & LSA_METRIC_MASK; | 
					
						
							|  |  |  |     rt->ebit = ext->metric & LSA_EXT3_EBIT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rt->fbit = ext->metric & LSA_EXT3_FBIT; | 
					
						
							|  |  |  |     if (rt->fbit) | 
					
						
							| 
									
										
										
										
											2017-10-09 01:16:29 +02:00
										 |  |  |       buf = ospf3_get_addr(buf, af, &rt->fwaddr); | 
					
						
							| 
									
										
										
										
											2014-07-19 17:28:38 +02:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |       rt->fwaddr = IPA_NONE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rt->tag = (ext->metric & LSA_EXT3_TBIT) ? *buf++ : 0; | 
					
						
							|  |  |  |     rt->propagate = rt->pxopts & OPT_PX_P; | 
					
						
							| 
									
										
										
										
											2019-02-13 15:40:22 +01:00
										 |  |  |     rt->downwards = rt->pxopts & OPT_PX_DN; | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | lsa_validate_rt2(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt))) | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint i = 0; | 
					
						
							|  |  |  |   void *buf = body; | 
					
						
							|  |  |  |   void *bufend = buf + lsa->length - HDRLEN; | 
					
						
							|  |  |  |   buf += sizeof(struct ospf_lsa_rt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (buf < bufend) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     struct ospf_lsa_rt2_link *l = buf; | 
					
						
							|  |  |  |     buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos); | 
					
						
							|  |  |  |     i++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (buf > bufend) | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!((l->type == LSART_PTP) || | 
					
						
							|  |  |  | 	  (l->type == LSART_NET) || | 
					
						
							|  |  |  | 	  (l->type == LSART_STUB) || | 
					
						
							|  |  |  | 	  (l->type == LSART_VLNK))) | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if ((body->options & LSA_RT2_LINKS) != i) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | lsa_validate_rt3(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt))) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   void *buf = body; | 
					
						
							|  |  |  |   void *bufend = buf + lsa->length - HDRLEN; | 
					
						
							|  |  |  |   buf += sizeof(struct ospf_lsa_rt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (buf < bufend) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     struct ospf_lsa_rt3_link *l = buf; | 
					
						
							|  |  |  |     buf += sizeof(struct ospf_lsa_rt3_link); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (buf > bufend) | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!((l->type == LSART_PTP) || | 
					
						
							|  |  |  | 	  (l->type == LSART_NET) || | 
					
						
							|  |  |  | 	  (l->type == LSART_VLNK))) | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_net))) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | lsa_validate_sum2(struct ospf_lsa_header *lsa, struct ospf_lsa_sum2 *body) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum2))) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* First field should have TOS = 0, we ignore other TOS fields */ | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   if ((body->metric & LSA_SUM2_TOS) != 0) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int | 
					
						
							|  |  |  | pxlen(u32 *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return *buf >> 24; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | lsa_validate_sum3_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 4)) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   u8 pxl = pxlen(body->prefix); | 
					
						
							| 
									
										
										
										
											2015-11-05 12:48:52 +01:00
										 |  |  |   if (pxl > IP6_MAX_PREFIX_LENGTH) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-19 17:28:38 +02:00
										 |  |  |   if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | 		      IPV6_PREFIX_SPACE(pxl))) | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2016-10-14 15:37:04 +02:00
										 |  |  | lsa_validate_sum3_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body UNUSED) | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt))) | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | lsa_validate_ext2(struct ospf_lsa_header *lsa, struct ospf_lsa_ext2 *body) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext2))) | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* First field should have TOS = 0, we ignore other TOS fields */ | 
					
						
							|  |  |  |   if ((body->metric & LSA_EXT2_TOS) != 0) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | lsa_validate_ext3(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext3) + 4)) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   u8 pxl = pxlen(body->rest); | 
					
						
							| 
									
										
										
										
											2015-11-05 12:48:52 +01:00
										 |  |  |   if (pxl > IP6_MAX_PREFIX_LENGTH) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int len = IPV6_PREFIX_SPACE(pxl); | 
					
						
							| 
									
										
										
										
											2015-12-11 15:35:37 +01:00
										 |  |  |   if (body->metric & LSA_EXT3_FBIT) // forwarding address
 | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     len += 16; | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   if (body->metric & LSA_EXT3_TBIT) // route tag
 | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     len += 4; | 
					
						
							|  |  |  |   if (*body->rest & 0xFFFF) // referenced LS type field
 | 
					
						
							|  |  |  |     len += 4; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext3) + len)) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, uint offset, u8 *pbuf) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   uint bound = lsa->length - HDRLEN - 4; | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |   u32 i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (i = 0; i < pxcount; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if (offset > bound) | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       u8 pxl = pxlen((u32 *) (pbuf + offset)); | 
					
						
							| 
									
										
										
										
											2015-11-05 12:48:52 +01:00
										 |  |  |       if (pxl > IP6_MAX_PREFIX_LENGTH) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2014-07-19 17:28:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |       offset += IPV6_PREFIX_SPACE(pxl); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (lsa->length != (HDRLEN + offset)) | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | lsa_validate_link(struct ospf_lsa_header *lsa, struct ospf_lsa_link *body) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_link))) | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_link), (u8 *) body); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_prefix))) | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-30 20:12:59 +02:00
										 |  |  | static int | 
					
						
							|  |  |  | lsa_validate_gr(struct ospf_lsa_header *lsa, void *body) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return lsa_validate_tlvs(body, lsa->length - HDRLEN); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  | static int | 
					
						
							|  |  |  | lsa_validate_ri(struct ospf_lsa_header *lsa UNUSED, struct ospf_lsa_net *body UNUSED) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   /*
 | 
					
						
							|  |  |  |    * There should be proper validation. But we do not really process RI LSAs, so | 
					
						
							|  |  |  |    * we can just accept them like another unknown opaque LSAs. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * lsa_validate - check whether given LSA is valid | 
					
						
							|  |  |  |  * @lsa: LSA header | 
					
						
							| 
									
										
										
										
											2016-05-12 17:49:12 +02:00
										 |  |  |  * @lsa_type: internal LSA type (%LSA_T_xxx) | 
					
						
							|  |  |  |  * @ospf2: %true for OSPFv2, %false for OSPFv3 | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |  * @body: pointer to LSA body | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Checks internal structure of given LSA body (minimal length, | 
					
						
							|  |  |  |  * consistency). Returns true if valid. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  | lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |   if (ospf2) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     switch (lsa_type) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case LSA_T_RT: | 
					
						
							|  |  |  |       return lsa_validate_rt2(lsa, body); | 
					
						
							|  |  |  |     case LSA_T_NET: | 
					
						
							|  |  |  |       return lsa_validate_net(lsa, body); | 
					
						
							|  |  |  |     case LSA_T_SUM_NET: | 
					
						
							|  |  |  |       return lsa_validate_sum2(lsa, body); | 
					
						
							|  |  |  |     case LSA_T_SUM_RT: | 
					
						
							|  |  |  |       return lsa_validate_sum2(lsa, body); | 
					
						
							|  |  |  |     case LSA_T_EXT: | 
					
						
							|  |  |  |     case LSA_T_NSSA: | 
					
						
							|  |  |  |       return lsa_validate_ext2(lsa, body); | 
					
						
							| 
									
										
										
										
											2019-06-30 20:12:59 +02:00
										 |  |  |     case LSA_T_GR: | 
					
						
							|  |  |  |       return lsa_validate_gr(lsa, body); | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  |     case LSA_T_RI_LINK: | 
					
						
							|  |  |  |     case LSA_T_RI_AREA: | 
					
						
							|  |  |  |     case LSA_T_RI_AS: | 
					
						
							|  |  |  |       return lsa_validate_ri(lsa, body); | 
					
						
							|  |  |  |     case LSA_T_OPAQUE_LINK: | 
					
						
							|  |  |  |     case LSA_T_OPAQUE_AREA: | 
					
						
							|  |  |  |     case LSA_T_OPAQUE_AS: | 
					
						
							|  |  |  |       return 1;	/* Unknown Opaque LSAs */ | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |     default: | 
					
						
							|  |  |  |       return 0;	/* Should not happen, unknown LSAs are already rejected */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     switch (lsa_type) | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |     case LSA_T_RT: | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |       return lsa_validate_rt3(lsa, body); | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     case LSA_T_NET: | 
					
						
							|  |  |  |       return lsa_validate_net(lsa, body); | 
					
						
							|  |  |  |     case LSA_T_SUM_NET: | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |       return lsa_validate_sum3_net(lsa, body); | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     case LSA_T_SUM_RT: | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |       return lsa_validate_sum3_rt(lsa, body); | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     case LSA_T_EXT: | 
					
						
							| 
									
										
										
										
											2011-07-20 23:40:20 +02:00
										 |  |  |     case LSA_T_NSSA: | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |       return lsa_validate_ext3(lsa, body); | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     case LSA_T_LINK: | 
					
						
							|  |  |  |       return lsa_validate_link(lsa, body); | 
					
						
							|  |  |  |     case LSA_T_PREFIX: | 
					
						
							|  |  |  |       return lsa_validate_prefix(lsa, body); | 
					
						
							| 
									
										
										
										
											2019-06-30 20:12:59 +02:00
										 |  |  |     case LSA_T_GR: | 
					
						
							|  |  |  |       return lsa_validate_gr(lsa, body); | 
					
						
							| 
									
										
										
										
											2019-01-24 22:34:33 +01:00
										 |  |  |     case LSA_T_RI_LINK: | 
					
						
							|  |  |  |     case LSA_T_RI_AREA: | 
					
						
							|  |  |  |     case LSA_T_RI_AS: | 
					
						
							|  |  |  |       return lsa_validate_ri(lsa, body); | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     default: | 
					
						
							| 
									
										
										
										
											2014-06-26 11:58:57 +02:00
										 |  |  |       return 1;	/* Unknown LSAs are OK in OSPFv3 */ | 
					
						
							| 
									
										
										
										
											2009-10-29 23:57:42 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2000-04-30 22:14:31 +00:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2000-04-04 15:55:55 +00:00
										 |  |  | } |