summaryrefslogtreecommitdiff
path: root/proto/ospf/lsalib.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf/lsalib.c')
-rw-r--r--proto/ospf/lsalib.c75
1 files changed, 73 insertions, 2 deletions
diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c
index 7ddf64e3..7767700f 100644
--- a/proto/ospf/lsalib.c
+++ b/proto/ospf/lsalib.c
@@ -12,6 +12,9 @@
#include "lib/fletcher16.h"
+#define HDRLEN sizeof(struct ospf_lsa_header)
+
+
#ifndef CPU_BIG_ENDIAN
void
lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
@@ -61,7 +64,6 @@ lsa_ntoh_body(void *n, void *h, u16 len)
#endif /* little endian */
-
int
lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa)
{
@@ -147,11 +149,13 @@ static const u16 lsa_v2_types[] = {
/* Maps OSPFv2 opaque types to OSPFv3 function codes */
static const u16 opaque_lsa_types[] = {
+ [LSA_OT_GR] = LSA_T_GR,
[LSA_OT_RI] = LSA_T_RI_,
};
/* Maps (subset of) OSPFv3 function codes to OSPFv2 opaque types */
static const u8 opaque_lsa_types_inv[] = {
+ [LSA_T_GR] = LSA_OT_GR,
[LSA_T_RI_] = LSA_OT_RI,
};
@@ -168,7 +172,13 @@ lsa_get_type_domain_(u32 type, u32 id, struct ospf_iface *ifa, u32 *otype, u32 *
uint code;
if (LSA_FUNCTION(type) == LSA_T_OPAQUE_)
if (code = LOOKUP(opaque_lsa_types, id >> 24))
+ {
type = code | LSA_UBIT | LSA_SCOPE(type);
+
+ /* 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;
+ }
}
else
{
@@ -196,6 +206,13 @@ lsa_get_type_domain_(u32 type, u32 id, struct ospf_iface *ifa, u32 *otype, u32 *
}
}
+int
+lsa_is_opaque(u32 type)
+{
+ u32 fn = LSA_FUNCTION(type);
+ return LOOKUP(opaque_lsa_types_inv, fn) || (fn == LSA_T_OPAQUE_);
+}
+
u32
lsa_get_opaque_type(u32 type)
{
@@ -267,6 +284,51 @@ lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
}
+#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;
+}
+
+
static inline int
lsa_walk_rt2(struct ospf_lsa_rt_walk *rt)
{
@@ -408,7 +470,6 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_
}
}
-#define HDRLEN sizeof(struct ospf_lsa_header)
static int
lsa_validate_rt2(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
@@ -604,6 +665,12 @@ lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body)
}
static int
+lsa_validate_gr(struct ospf_lsa_header *lsa, void *body)
+{
+ return lsa_validate_tlvs(body, lsa->length - HDRLEN);
+}
+
+static int
lsa_validate_ri(struct ospf_lsa_header *lsa UNUSED, struct ospf_lsa_net *body UNUSED)
{
/*
@@ -643,6 +710,8 @@ lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body)
case LSA_T_EXT:
case LSA_T_NSSA:
return lsa_validate_ext2(lsa, body);
+ case LSA_T_GR:
+ return lsa_validate_gr(lsa, body);
case LSA_T_RI_LINK:
case LSA_T_RI_AREA:
case LSA_T_RI_AS:
@@ -674,6 +743,8 @@ lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body)
return lsa_validate_link(lsa, body);
case LSA_T_PREFIX:
return lsa_validate_prefix(lsa, body);
+ case LSA_T_GR:
+ return lsa_validate_gr(lsa, body);
case LSA_T_RI_LINK:
case LSA_T_RI_AREA:
case LSA_T_RI_AS: