summaryrefslogtreecommitdiffstats
path: root/proto/ospf/lsalib.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf/lsalib.c')
-rw-r--r--proto/ospf/lsalib.c497
1 files changed, 289 insertions, 208 deletions
diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c
index e624b6c..7ee3aa4 100644
--- a/proto/ospf/lsalib.c
+++ b/proto/ospf/lsalib.c
@@ -65,8 +65,8 @@ ospf_age(struct proto_ospf *po)
flush_lsa(en, po);
continue;
}
- if ((en->lsa.rt == p->cf->global->router_id) &&(en->lsa.age >=
- LSREFRESHTIME))
+ if ((en->lsa.rt == p->cf->global->router_id) &&
+ (en->lsa.age >= LSREFRESHTIME))
{
OSPF_TRACE(D_EVENTS, "Refreshing my LSA: Type: %u, Id: %R, Rt: %R",
en->lsa.type, en->lsa.id, en->lsa.rt);
@@ -75,7 +75,7 @@ ospf_age(struct proto_ospf *po)
en->inst_t = now;
en->ini_age = 0;
lsasum_calculate(&en->lsa, en->lsa_body);
- ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, en->oa, 1);
+ ospf_lsupd_flood(po, NULL, NULL, &en->lsa, en->domain, 1);
continue;
}
if ((en->lsa.age = (en->ini_age + (now - en->inst_t))) >= LSA_MAXAGE)
@@ -96,216 +96,82 @@ void
htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
{
n->age = htons(h->age);
+#ifdef OSPFv2
n->options = h->options;
- n->type = h->type;
+#endif
+ n->type = htont(h->type);
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);
-};
+}
void
ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
{
h->age = ntohs(n->age);
+#ifdef OSPFv2
h->options = n->options;
- h->type = n->type;
+#endif
+ h->type = ntoht(n->type);
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);
-};
+}
void
-htonlsab(void *h, void *n, u8 type, u16 len)
+htonlsab(void *h, void *n, u16 type, u16 len)
{
- unsigned int i;
- switch (type)
- {
- case LSA_T_RT:
- {
- struct ospf_lsa_rt *hrt, *nrt;
- struct ospf_lsa_rt_link *hrtl, *nrtl;
- u16 links;
-
- nrt = n;
- hrt = h;
- links = hrt->links;
-
- nrt->veb.byte = hrt->veb.byte;
- nrt->padding = 0;
- nrt->links = htons(hrt->links);
- nrtl = (struct ospf_lsa_rt_link *) (nrt + 1);
- hrtl = (struct ospf_lsa_rt_link *) (hrt + 1);
- for (i = 0; i < links; i++)
- {
- (nrtl + i)->id = htonl((hrtl + i)->id);
- (nrtl + i)->data = htonl((hrtl + i)->data);
- (nrtl + i)->type = (hrtl + i)->type;
- (nrtl + i)->notos = (hrtl + i)->notos;
- (nrtl + i)->metric = htons((hrtl + i)->metric);
- }
- break;
- }
- case LSA_T_NET:
- {
- u32 *hid, *nid;
+ u32 *hid = h;
+ u32 *nid = n;
+ int i;
- nid = n;
- hid = h;
-
- for (i = 0; i < (len / sizeof(u32)); i++)
- {
- *(nid + i) = htonl(*(hid + i));
- }
- break;
- }
- case LSA_T_SUM_NET:
- case LSA_T_SUM_RT:
- {
- struct ospf_lsa_sum *hs, *ns;
- union ospf_lsa_sum_tm *hn, *nn;
-
- hs = h;
- ns = n;
-
- ns->netmask = hs->netmask;
- ipa_hton(ns->netmask);
-
- hn = (union ospf_lsa_sum_tm *) (hs + 1);
- nn = (union ospf_lsa_sum_tm *) (ns + 1);
-
- for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) /
- sizeof(union ospf_lsa_sum_tm)); i++)
- {
- (nn + i)->metric = htonl((hn + i)->metric);
- }
- break;
- }
- case LSA_T_EXT:
- {
- struct ospf_lsa_ext *he, *ne;
- struct ospf_lsa_ext_tos *ht, *nt;
-
- he = h;
- ne = n;
-
- ne->netmask = he->netmask;
- ipa_hton(ne->netmask);
+ for (i = 0; i < (len / sizeof(u32)); i++)
+ nid[i] = htonl(hid[i]);
+}
- ht = (struct ospf_lsa_ext_tos *) (he + 1);
- nt = (struct ospf_lsa_ext_tos *) (ne + 1);
+void
+ntohlsab(void *n, void *h, u16 type, u16 len)
+{
+ u32 *nid = n;
+ u32 *hid = h;
+ int i;
- for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) /
- sizeof(struct ospf_lsa_ext_tos)); i++)
- {
- (nt + i)->etm.metric = htonl((ht + i)->etm.metric);
- (nt + i)->fwaddr = (ht + i)->fwaddr;
- ipa_hton((nt + i)->fwaddr);
- (nt + i)->tag = htonl((ht + i)->tag);
- }
- break;
- }
- default:
- bug("(hton): Unknown LSA");
- }
-};
+ for (i = 0; i < (len / sizeof(u32)); i++)
+ hid[i] = ntohl(nid[i]);
+}
void
-ntohlsab(void *n, void *h, u8 type, u16 len)
+buf_dump(const char *hdr, const byte *buf, int blen)
{
- unsigned int i;
- switch (type)
- {
- case LSA_T_RT:
- {
- struct ospf_lsa_rt *hrt, *nrt;
- struct ospf_lsa_rt_link *hrtl, *nrtl;
- u16 links;
-
- nrt = n;
- hrt = h;
-
- hrt->veb.byte = nrt->veb.byte;
- hrt->padding = 0;
- links = hrt->links = ntohs(nrt->links);
- nrtl = (struct ospf_lsa_rt_link *) (nrt + 1);
- hrtl = (struct ospf_lsa_rt_link *) (hrt + 1);
- for (i = 0; i < links; i++)
- {
- (hrtl + i)->id = ntohl((nrtl + i)->id);
- (hrtl + i)->data = ntohl((nrtl + i)->data);
- (hrtl + i)->type = (nrtl + i)->type;
- (hrtl + i)->notos = (nrtl + i)->notos;
- (hrtl + i)->metric = ntohs((nrtl + i)->metric);
- }
- break;
- }
- case LSA_T_NET:
- {
- u32 *hid, *nid;
+ char b2[1024];
+ char *bp;
+ int first = 1;
+ int i;
- hid = h;
- nid = n;
+ const char *lhdr = hdr;
- for (i = 0; i < (len / sizeof(u32)); i++)
- {
- *(hid + i) = ntohl(*(nid + i));
- }
- break;
- }
- case LSA_T_SUM_NET:
- case LSA_T_SUM_RT:
+ bp = b2;
+ for(i = 0; i < blen; i++)
{
- struct ospf_lsa_sum *hs, *ns;
- union ospf_lsa_sum_tm *hn, *nn;
-
- hs = h;
- ns = n;
-
- hs->netmask = ns->netmask;
- ipa_ntoh(hs->netmask);
+ if ((i > 0) && ((i % 16) == 0))
+ {
+ *bp = 0;
+ log(L_WARN "%s\t%s", lhdr, b2);
+ lhdr = "";
+ bp = b2;
+ }
- hn = (union ospf_lsa_sum_tm *) (hs + 1);
- nn = (union ospf_lsa_sum_tm *) (ns + 1);
+ bp += snprintf(bp, 1022, "%02x ", buf[i]);
- for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) /
- sizeof(union ospf_lsa_sum_tm)); i++)
- {
- (hn + i)->metric = ntohl((nn + i)->metric);
- }
- break;
}
- case LSA_T_EXT:
- {
- struct ospf_lsa_ext *he, *ne;
- struct ospf_lsa_ext_tos *ht, *nt;
-
- he = h;
- ne = n;
-
- he->netmask = ne->netmask;
- ipa_ntoh(he->netmask);
- ht = (struct ospf_lsa_ext_tos *) (he + 1);
- nt = (struct ospf_lsa_ext_tos *) (ne + 1);
-
- for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) /
- sizeof(struct ospf_lsa_ext_tos)); i++)
- {
- (ht + i)->etm.metric = ntohl((nt + i)->etm.metric);
- (ht + i)->fwaddr = (nt + i)->fwaddr;
- ipa_ntoh((ht + i)->fwaddr);
- (ht + i)->tag = ntohl((nt + i)->tag);
- }
- break;
- }
- default:
- bug("(ntoh): Unknown LSA");
- }
-};
+ *bp = 0;
+ log(L_WARN "%s\t%s", lhdr, b2);
+}
#define MODX 4102 /* larges signed value without overflow */
@@ -317,17 +183,26 @@ ntohlsab(void *n, void *h, u8 type, u16 len)
void
lsasum_calculate(struct ospf_lsa_header *h, void *body)
{
- u16 length;
-
- length = h->length;
+ u16 length = h->length;
+ u16 type = h->type;
+ // log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length);
htonlsah(h, h);
- htonlsab(body, body, h->type, length - sizeof(struct ospf_lsa_header));
+ htonlsab(body, body, type, length - sizeof(struct ospf_lsa_header));
+
+ /*
+ char buf[1024];
+ memcpy(buf, h, sizeof(struct ospf_lsa_header));
+ memcpy(buf + sizeof(struct ospf_lsa_header), body, length - sizeof(struct ospf_lsa_header));
+ buf_dump("CALC", buf, length);
+ */
(void) lsasum_check(h, body);
+ // log(L_WARN "Checksum result %4x", h->checksum);
+
ntohlsah(h, h);
- ntohlsab(body, body, h->type, length - sizeof(struct ospf_lsa_header));
+ ntohlsab(body, body, type, length - sizeof(struct ospf_lsa_header));
}
/*
@@ -343,7 +218,8 @@ lsasum_check(struct ospf_lsa_header *h, void *body)
u16 length;
b = body;
- sp = (char *) &h->options;
+ sp = (char *) h;
+ sp += 2; /* Skip Age field */
length = ntohs(h->length) - 2;
h->checksum = 0;
@@ -415,47 +291,254 @@ lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
return CMP_SAME;
}
+#define HDRLEN sizeof(struct ospf_lsa_header)
+
+static int
+lsa_validate_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
+{
+ unsigned int i, max;
+
+ if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
+ return 0;
+
+ struct ospf_lsa_rt_link *rtl = (struct ospf_lsa_rt_link *) (body + 1);
+ max = lsa_rt_count(lsa);
+
+#ifdef OSPFv2
+ if (body->links != max)
+ return 0;
+#endif
+
+ for (i = 0; i < max; i++)
+ {
+ u8 type = rtl[i].type;
+ if (!((type == LSART_PTP) ||
+ (type == LSART_NET) ||
+#ifdef OSPFv2
+ (type == LSART_STUB) ||
+#endif
+ (type == LSART_VLNK)))
+ return 0;
+ }
+ return 1;
+}
+
+static int
+lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body)
+{
+ if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_net)))
+ return 0;
+
+ return 1;
+}
+
+#ifdef OSPFv2
+
+static int
+lsa_validate_sum(struct ospf_lsa_header *lsa, struct ospf_lsa_sum *body)
+{
+ if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum)))
+ return 0;
+
+ /* First field should have TOS = 0, we ignore other TOS fields */
+ if ((body->metric & LSA_SUM_TOS) != 0)
+ return 0;
+
+ return 1;
+}
+#define lsa_validate_sum_net(A,B) lsa_validate_sum(A,B)
+#define lsa_validate_sum_rt(A,B) lsa_validate_sum(A,B)
+
+static int
+lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body)
+{
+ if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext)))
+ return 0;
+
+ /* First field should have TOS = 0, we ignore other TOS fields */
+ if ((body->metric & LSA_EXT_TOS) != 0)
+ return 0;
+
+ return 1;
+}
+
+#else /* OSPFv3 */
+
+static inline int
+pxlen(u32 *buf)
+{
+ return *buf >> 24;
+}
+
+static int
+lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_net *body)
+{
+ if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum_net) + 4))
+ return 0;
+
+ u8 pxl = pxlen(body->prefix);
+ if (pxl > MAX_PREFIX_LENGTH)
+ return 0;
+
+ if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum_net) +
+ IPV6_PREFIX_SPACE(pxl)))
+ return 0;
+
+ return 1;
+}
+
+
+static int
+lsa_validate_sum_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_rt *body)
+{
+ if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum_rt)))
+ return 0;
+
+ return 1;
+}
+
+static int
+lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body)
+{
+ if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext) + 4))
+ return 0;
+
+ u8 pxl = pxlen(body->rest);
+ if (pxl > MAX_PREFIX_LENGTH)
+ return 0;
+
+ int len = IPV6_PREFIX_SPACE(pxl);
+ if (body->metric & LSA_EXT_FBIT) // forwardinf address
+ len += 16;
+ if (body->metric & LSA_EXT_TBIT) // route tag
+ len += 4;
+ if (*body->rest & 0xFFFF) // referenced LS type field
+ len += 4;
+
+ if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext) + len))
+ return 0;
+
+ return 1;
+}
+
+static int
+lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, unsigned int offset, u8 *pbuf)
+{
+ unsigned int bound = lsa->length - HDRLEN - 4;
+ u32 i;
+
+ for (i = 0; i < pxcount; i++)
+ {
+ if (offset > bound)
+ return 0;
+
+ u8 pxl = pxlen((u32 *) (pbuf + offset));
+ if (pxl > MAX_PREFIX_LENGTH)
+ return 0;
+
+ 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);
+}
+
+#endif
+
+
+/**
+ * lsa_validate - check whether given LSA is valid
+ * @lsa: LSA header
+ * @body: pointer to LSA body
+ *
+ * Checks internal structure of given LSA body (minimal length,
+ * consistency). Returns true if valid.
+ */
+
+int
+lsa_validate(struct ospf_lsa_header *lsa, void *body)
+{
+ switch (lsa->type)
+ {
+ case LSA_T_RT:
+ return lsa_validate_rt(lsa, body);
+ case LSA_T_NET:
+ return lsa_validate_net(lsa, body);
+ case LSA_T_SUM_NET:
+ return lsa_validate_sum_net(lsa, body);
+ case LSA_T_SUM_RT:
+ return lsa_validate_sum_rt(lsa, body);
+ case LSA_T_EXT:
+ return lsa_validate_ext(lsa, body);
+#ifdef OSPFv3
+ case LSA_T_LINK:
+ return lsa_validate_link(lsa, body);
+ case LSA_T_PREFIX:
+ return lsa_validate_prefix(lsa, body);
+#endif
+ default:
+ /* In OSPFv3, unknown LSAs are OK,
+ In OSPFv2, unknown LSAs are already rejected
+ */
+ return 1;
+ }
+}
+
/**
* lsa_install_new - install new LSA into database
+ * @po: OSPF protocol
* @lsa: LSA header
+ * @domain: domain of LSA
* @body: pointer to LSA body
- * @oa: current ospf_area
+
*
* This function ensures installing new LSA into LSA database. Old instance is
* replaced. Several actions are taken to detect if new routing table
* calculation is necessary. This is described in 13.2 of RFC 2328.
*/
struct top_hash_entry *
-lsa_install_new(struct ospf_lsa_header *lsa, void *body, struct ospf_area *oa)
+lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body)
{
/* LSA can be temporarrily, but body must be mb_allocated. */
int change = 0;
- unsigned i;
struct top_hash_entry *en;
- struct proto_ospf *po = oa->po;
- if ((en = ospf_hash_find_header(po->gr, oa->areaid, lsa)) == NULL)
+ if ((en = ospf_hash_find_header(po->gr, domain, lsa)) == NULL)
{
- en = ospf_hash_get_header(po->gr, oa, lsa);
+ en = ospf_hash_get_header(po->gr, domain, lsa);
change = 1;
}
else
{
- if ((en->lsa.length != lsa->length) || (en->lsa.options != lsa->options)
- || ((en->lsa.age == LSA_MAXAGE) || (lsa->age == LSA_MAXAGE)))
+ if ((en->lsa.length != lsa->length)
+#ifdef OSPFv2
+ || (en->lsa.options != lsa->options)
+#endif
+ || (en->lsa.age == LSA_MAXAGE)
+ || (lsa->age == LSA_MAXAGE)
+ || memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header)))
change = 1;
- else
- {
- u8 *k = en->lsa_body, *l = body;
- for (i = 0; i < (lsa->length - sizeof(struct ospf_lsa_header)); i++)
- {
- if (*(k + i) != *(l + i))
- {
- change = 1;
- break;
- }
- }
- }
+
s_rem_node(SNODE en);
}
@@ -471,9 +554,7 @@ lsa_install_new(struct ospf_lsa_header *lsa, void *body, struct ospf_area *oa)
en->ini_age = en->lsa.age;
if (change)
- {
schedule_rtcalc(po);
- }
return en;
}