mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-17 08:38:42 +00:00
Merge remote-tracking branch 'origin/soft-int'
This commit is contained in:
commit
7730553b7e
4
NEWS
4
NEWS
@ -1,3 +1,7 @@
|
||||
Version 1.5.0pre (2014-11-05) - Not for production
|
||||
o Major OSPF protocol redesign
|
||||
o RFC 6549 - OSPFv2 multi-instance extension
|
||||
|
||||
Version 1.4.5 (2014-10-06)
|
||||
o New 'show route noexport' command option.
|
||||
o Port option for BGP sessions.
|
||||
|
@ -124,22 +124,24 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
|
||||
}
|
||||
|
||||
{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
|
||||
ip4_addr a;
|
||||
if (!ip4_pton(yytext, &a))
|
||||
cf_error("Invalid IPv4 address %s", yytext);
|
||||
|
||||
#ifdef IPV6
|
||||
if (ipv4_pton_u32(yytext, &cf_lval.i32))
|
||||
return RTRID;
|
||||
cf_error("Invalid IPv4 address %s", yytext);
|
||||
cf_lval.i32 = ip4_to_u32(a);
|
||||
return RTRID;
|
||||
#else
|
||||
if (ip_pton(yytext, &cf_lval.a))
|
||||
return IPA;
|
||||
cf_error("Invalid IP address %s", yytext);
|
||||
cf_lval.a = ipa_from_ip4(a);
|
||||
return IPA;
|
||||
#endif
|
||||
}
|
||||
|
||||
({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
|
||||
#ifdef IPV6
|
||||
if (ip_pton(yytext, &cf_lval.a))
|
||||
if (ipa_pton(yytext, &cf_lval.a))
|
||||
return IPA;
|
||||
cf_error("Invalid IP address %s", yytext);
|
||||
cf_error("Invalid IPv6 address %s", yytext);
|
||||
#else
|
||||
cf_error("This is an IPv4 router, therefore IPv6 addresses are not supported");
|
||||
#endif
|
||||
|
@ -187,7 +187,7 @@ pxlen:
|
||||
$$ = $2;
|
||||
}
|
||||
| ':' ipa {
|
||||
$$ = ipa_mklen($2);
|
||||
$$ = ipa_masklen($2);
|
||||
if ($$ < 0) cf_error("Invalid netmask %I", $2);
|
||||
}
|
||||
;
|
||||
|
@ -2292,6 +2292,7 @@ networks.
|
||||
<code>
|
||||
protocol ospf <name> {
|
||||
rfc1583compat <switch>;
|
||||
instance id <num>;
|
||||
stub router <switch>;
|
||||
tick <num>;
|
||||
ecmp <switch> [limit <num>];
|
||||
@ -2336,6 +2337,7 @@ protocol ospf <name> {
|
||||
tx length <num>;
|
||||
type [broadcast|bcast|pointopoint|ptp|
|
||||
nonbroadcast|nbma|pointomultipoint|ptmp];
|
||||
link lsa suppression <switch>;
|
||||
strict nonbroadcast <switch>;
|
||||
real broadcast <switch>;
|
||||
ptp netmask <switch>;
|
||||
@ -2378,14 +2380,24 @@ protocol ospf <name> {
|
||||
RFC 1583 <htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc1583.txt">.
|
||||
Default value is no.
|
||||
|
||||
<tag>instance id <m/num/</tag>
|
||||
When multiple OSPF protocol instances are active on the same links, they
|
||||
should use different instance IDs to distinguish their packets. Although
|
||||
it could be done on per-interface basis, it is often preferred to set
|
||||
one instance ID to whole OSPF domain/topology (e.g., when multiple
|
||||
instances are used to represent separate logical topologies on the same
|
||||
physical network). This option specifies the default instance ID for all
|
||||
interfaces of the OSPF instance. Note that this option, if used, must
|
||||
precede interface definitions. Default value is 0.
|
||||
|
||||
<tag>stub router <M>switch</M></tag>
|
||||
This option configures the router to be a stub router, i.e., a router
|
||||
that participates in the OSPF topology but does not allow transit
|
||||
traffic. In OSPFv2, this is implemented by advertising maximum metric
|
||||
for outgoing links, as suggested by
|
||||
RFC 3137 <htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc3137.txt">.
|
||||
In OSPFv3, the stub router behavior is announced by clearing the R-bit
|
||||
in the router LSA. Default value is no.
|
||||
for outgoing links. In OSPFv3, the stub router behavior is announced by
|
||||
clearing the R-bit in the router LSA. See RFC 6987
|
||||
<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc6987.txt"> for
|
||||
details. Default value is no.
|
||||
|
||||
<tag>tick <M>num</M></tag>
|
||||
The routing table calculation and clean-up of areas' databases is not
|
||||
@ -2487,22 +2499,26 @@ protocol ospf <name> {
|
||||
prefix. When option <cf/summary/ is used, also default stub networks
|
||||
that are subnetworks of given stub network are suppressed. This might be
|
||||
used, for example, to aggregate generated stub networks.
|
||||
|
||||
|
||||
<tag>interface <M>pattern</M> [instance <m/num/]</tag>
|
||||
Defines that the specified interfaces belong to the area being defined.
|
||||
See <ref id="dsc-iface" name="interface"> common option for detailed
|
||||
description. In OSPFv2, extended interface clauses are used, because
|
||||
OSPFv2 handles each network prefix as a separate virtual interface. In
|
||||
OSPFv3, you can specify instance ID for that interface description, so
|
||||
it is possible to have several instances of that interface with
|
||||
different options or even in different areas.
|
||||
each network prefix is handled as a separate virtual interface.
|
||||
|
||||
You can specify alternative instance ID for the interface definition,
|
||||
therefore it is possible to have several instances of that interface
|
||||
with different options or even in different areas. For OSPFv2,
|
||||
instance ID support is an extension (RFC 6549
|
||||
<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc6549.txt">) and is
|
||||
supposed to be set per-protocol. For OSPFv3, it is an integral feature.
|
||||
|
||||
<tag>virtual link <M>id</M> [instance <m/num/]</tag>
|
||||
Virtual link to router with the router id. Virtual link acts as a
|
||||
point-to-point interface belonging to backbone. The actual area is used
|
||||
as transport area. This item cannot be in the backbone. In OSPFv3, you
|
||||
could also use several virtual links to one destination with different
|
||||
instance IDs.
|
||||
as a transport area. This item cannot be in the backbone. Like with
|
||||
<cf/interface/ option, you could also use several virtual links to one
|
||||
destination with different instance IDs.
|
||||
|
||||
<tag>cost <M>num</M></tag>
|
||||
Specifies output cost (metric) of an interface. Default value is 10.
|
||||
@ -2533,8 +2549,8 @@ protocol ospf <name> {
|
||||
|
||||
<tag>wait <M>num</M></tag>
|
||||
After start, router waits for the specified number of seconds between
|
||||
starting election and building adjacency. Default value is 40.
|
||||
|
||||
starting election and building adjacency. Default value is 4*<m/hello/.
|
||||
|
||||
<tag>dead count <M>num</M></tag>
|
||||
When the router does not receive any messages from a neighbor in
|
||||
<m/dead count/*<m/hello/ seconds, it will consider the neighbor down.
|
||||
@ -2600,9 +2616,16 @@ protocol ospf <name> {
|
||||
communication, or if the NBMA network is used as an (possibly
|
||||
unnumbered) PtP link.
|
||||
|
||||
<tag>strict nonbroadcast <M>switch</M></tag>
|
||||
<tag>link lsa suppression <m/switch/</tag>
|
||||
In OSPFv3, link LSAs are generated for each link, announcing link-local
|
||||
IPv6 address of the router to its local neighbors. These are useless on
|
||||
PtP or PtMP networks and this option allows to suppress the link LSA
|
||||
origination for such interfaces. The option is ignored on other than PtP
|
||||
or PtMP interfaces. Default value is no.
|
||||
|
||||
<tag>strict nonbroadcast <m/switch/</tag>
|
||||
If set, don't send hello to any undefined neighbor. This switch is
|
||||
ignored on other than NBMA or PtMP networks. Default value is no.
|
||||
ignored on other than NBMA or PtMP interfaces. Default value is no.
|
||||
|
||||
<tag>real broadcast <m/switch/</tag>
|
||||
In <cf/type broadcast/ or <cf/type ptp/ network configuration, OSPF
|
||||
|
@ -3,13 +3,6 @@ bitops.c
|
||||
bitops.h
|
||||
ip.h
|
||||
ip.c
|
||||
#ifdef IPV6
|
||||
ipv6.c
|
||||
ipv6.h
|
||||
#else
|
||||
ipv4.c
|
||||
ipv4.h
|
||||
#endif
|
||||
lists.c
|
||||
lists.h
|
||||
md5.c
|
||||
|
@ -33,6 +33,12 @@
|
||||
#define ABS(a) ((a)>=0 ? (a) : -(a))
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
|
||||
|
||||
#define BIT32_VAL(p) (((u32) 1) << ((p) % 32))
|
||||
#define BIT32_TEST(b,p) ((b)[(p)/32] & BIT32_VAL(p))
|
||||
#define BIT32_SET(b,p) ((b)[(p)/32] |= BIT32_VAL(p))
|
||||
#define BIT32_CLR(b,p) ((b)[(p)/32] &= ~BIT32_VAL(p))
|
||||
#define BIT32_ZERO(b,l) memset((b), 0, (l)/8)
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *) 0)
|
||||
#endif
|
||||
|
@ -27,7 +27,7 @@ event_list global_event_list;
|
||||
inline void
|
||||
ev_postpone(event *e)
|
||||
{
|
||||
if (e->n.next)
|
||||
if (ev_active(e))
|
||||
{
|
||||
rem_node(&e->n);
|
||||
e->n.next = NULL;
|
||||
|
@ -30,4 +30,11 @@ void ev_schedule(event *);
|
||||
void ev_postpone(event *);
|
||||
int ev_run_list(event_list *);
|
||||
|
||||
static inline int
|
||||
ev_active(event *e)
|
||||
{
|
||||
return e->n.next != NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
376
lib/ip.c
376
lib/ip.c
@ -1,14 +1,11 @@
|
||||
/*
|
||||
* BIRD Library -- IP address routines common for IPv4 and IPv6
|
||||
* BIRD Library -- IP address functions
|
||||
*
|
||||
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "lib/ip.h"
|
||||
|
||||
/**
|
||||
* DOC: IP addresses
|
||||
*
|
||||
@ -18,6 +15,333 @@
|
||||
* they must be manipulated using the following functions and macros.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "lib/ip.h"
|
||||
|
||||
|
||||
int
|
||||
ip6_compare(ip6_addr a, ip6_addr b)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<4; i++)
|
||||
if (a.addr[i] > b.addr[i])
|
||||
return 1;
|
||||
else if (a.addr[i] < b.addr[i])
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ip6_addr
|
||||
ip6_mkmask(uint n)
|
||||
{
|
||||
ip6_addr a;
|
||||
int i;
|
||||
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if (!n)
|
||||
a.addr[i] = 0;
|
||||
else if (n >= 32)
|
||||
{
|
||||
a.addr[i] = ~0;
|
||||
n -= 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
a.addr[i] = u32_mkmask(n);
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
int
|
||||
ip6_masklen(ip6_addr *a)
|
||||
{
|
||||
int i, j, n;
|
||||
|
||||
for (i=0, n=0; i<4; i++, n+=32)
|
||||
if (a->addr[i] != ~0U)
|
||||
{
|
||||
j = u32_masklen(a->addr[i]);
|
||||
if (j < 0)
|
||||
return j;
|
||||
n += j;
|
||||
while (++i < 4)
|
||||
if (a->addr[i])
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
ip4_classify(ip4_addr ad)
|
||||
{
|
||||
u32 a = _I(ad);
|
||||
u32 b = a >> 24U;
|
||||
|
||||
if (b && b <= 0xdf)
|
||||
{
|
||||
if (b == 0x7f)
|
||||
return IADDR_HOST | SCOPE_HOST;
|
||||
else if ((b == 0x0a) ||
|
||||
((a & 0xffff0000) == 0xc0a80000) ||
|
||||
((a & 0xfff00000) == 0xac100000))
|
||||
return IADDR_HOST | SCOPE_SITE;
|
||||
else
|
||||
return IADDR_HOST | SCOPE_UNIVERSE;
|
||||
}
|
||||
|
||||
if (b >= 0xe0 && b <= 0xef)
|
||||
return IADDR_MULTICAST | SCOPE_UNIVERSE;
|
||||
|
||||
if (a == 0xffffffff)
|
||||
return IADDR_BROADCAST | SCOPE_LINK;
|
||||
|
||||
return IADDR_INVALID;
|
||||
}
|
||||
|
||||
int
|
||||
ip6_classify(ip6_addr *a)
|
||||
{
|
||||
u32 x = a->addr[0];
|
||||
|
||||
if ((x & 0xe0000000) == 0x20000000) /* 2000::/3 Aggregatable Global Unicast Address */
|
||||
return IADDR_HOST | SCOPE_UNIVERSE;
|
||||
if ((x & 0xffc00000) == 0xfe800000) /* fe80::/10 Link-Local Address */
|
||||
return IADDR_HOST | SCOPE_LINK;
|
||||
if ((x & 0xffc00000) == 0xfec00000) /* fec0::/10 Site-Local Address */
|
||||
return IADDR_HOST | SCOPE_SITE;
|
||||
if ((x & 0xfe000000) == 0xfc000000) /* fc00::/7 Unique Local Unicast Address (RFC 4193) */
|
||||
return IADDR_HOST | SCOPE_SITE;
|
||||
if ((x & 0xff000000) == 0xff000000) /* ff00::/8 Multicast Address */
|
||||
{
|
||||
uint scope = (x >> 16) & 0x0f;
|
||||
switch (scope)
|
||||
{
|
||||
case 1: return IADDR_MULTICAST | SCOPE_HOST;
|
||||
case 2: return IADDR_MULTICAST | SCOPE_LINK;
|
||||
case 5: return IADDR_MULTICAST | SCOPE_SITE;
|
||||
case 8: return IADDR_MULTICAST | SCOPE_ORGANIZATION;
|
||||
case 14: return IADDR_MULTICAST | SCOPE_UNIVERSE;
|
||||
default: return IADDR_MULTICAST | SCOPE_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!x && !a->addr[1])
|
||||
{
|
||||
u32 a2 = a->addr[2];
|
||||
u32 a3 = a->addr[3];
|
||||
|
||||
if (a2 == 0 && a3 == 1)
|
||||
return IADDR_HOST | SCOPE_HOST; /* Loopback address */
|
||||
if (a2 == 0)
|
||||
return ip4_classify(_MI4(a3)); /* IPv4 compatible addresses */
|
||||
if (a2 == 0xffff)
|
||||
return ip4_classify(_MI4(a3)); /* IPv4 mapped addresses */
|
||||
|
||||
return IADDR_INVALID;
|
||||
}
|
||||
|
||||
return IADDR_HOST | SCOPE_UNDEFINED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Conversion of IPv6 address to presentation format and vice versa.
|
||||
* Heavily inspired by routines written by Paul Vixie for the BIND project
|
||||
* and of course by RFC 2373.
|
||||
*/
|
||||
|
||||
|
||||
char *
|
||||
ip4_ntop(ip4_addr a, char *b)
|
||||
{
|
||||
u32 x = _I(a);
|
||||
return b + bsprintf(b, "%d.%d.%d.%d", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
ip6_ntop(ip6_addr a, char *b)
|
||||
{
|
||||
u16 words[8];
|
||||
int bestpos, bestlen, curpos, curlen, i;
|
||||
|
||||
/* First of all, preprocess the address and find the longest run of zeros */
|
||||
bestlen = bestpos = curpos = curlen = 0;
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
u32 x = a.addr[i/2];
|
||||
words[i] = ((i%2) ? x : (x >> 16)) & 0xffff;
|
||||
if (words[i])
|
||||
curlen = 0;
|
||||
else
|
||||
{
|
||||
if (!curlen)
|
||||
curpos = i;
|
||||
curlen++;
|
||||
if (curlen > bestlen)
|
||||
{
|
||||
bestpos = curpos;
|
||||
bestlen = curlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestlen < 2)
|
||||
bestpos = -1;
|
||||
|
||||
/* Is it an encapsulated IPv4 address? */
|
||||
if (!bestpos && ((bestlen == 5 && a.addr[2] == 0xffff) || (bestlen == 6)))
|
||||
{
|
||||
u32 x = a.addr[3];
|
||||
b += bsprintf(b, "::%s%d.%d.%d.%d",
|
||||
a.addr[2] ? "ffff:" : "",
|
||||
(x >> 24) & 0xff,
|
||||
(x >> 16) & 0xff,
|
||||
(x >> 8) & 0xff,
|
||||
x & 0xff);
|
||||
return b;
|
||||
}
|
||||
|
||||
/* Normal IPv6 formatting, compress the largest sequence of zeros */
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
if (i == bestpos)
|
||||
{
|
||||
i += bestlen - 1;
|
||||
*b++ = ':';
|
||||
if (i == 7)
|
||||
*b++ = ':';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i)
|
||||
*b++ = ':';
|
||||
b += bsprintf(b, "%x", words[i]);
|
||||
}
|
||||
}
|
||||
*b = 0;
|
||||
return b;
|
||||
}
|
||||
|
||||
int
|
||||
ip4_pton(char *a, ip4_addr *o)
|
||||
{
|
||||
int i;
|
||||
unsigned long int l;
|
||||
u32 ia = 0;
|
||||
|
||||
i=4;
|
||||
while (i--)
|
||||
{
|
||||
char *d, *c = strchr(a, '.');
|
||||
if (!c != !i)
|
||||
return 0;
|
||||
l = strtoul(a, &d, 10);
|
||||
if (d != c && *d || l > 255)
|
||||
return 0;
|
||||
ia = (ia << 8) | l;
|
||||
if (c)
|
||||
c++;
|
||||
a = c;
|
||||
}
|
||||
*o = ip4_from_u32(ia);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
ip6_pton(char *a, ip6_addr *o)
|
||||
{
|
||||
u16 words[8];
|
||||
int i, j, k, l, hfil;
|
||||
char *start;
|
||||
|
||||
if (a[0] == ':') /* Leading :: */
|
||||
{
|
||||
if (a[1] != ':')
|
||||
return 0;
|
||||
a++;
|
||||
}
|
||||
|
||||
hfil = -1;
|
||||
i = 0;
|
||||
while (*a)
|
||||
{
|
||||
if (*a == ':') /* :: */
|
||||
{
|
||||
if (hfil >= 0)
|
||||
return 0;
|
||||
|
||||
hfil = i;
|
||||
a++;
|
||||
continue;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
l = 0;
|
||||
start = a;
|
||||
for (;;)
|
||||
{
|
||||
if (*a >= '0' && *a <= '9')
|
||||
k = *a++ - '0';
|
||||
else if (*a >= 'A' && *a <= 'F')
|
||||
k = *a++ - 'A' + 10;
|
||||
else if (*a >= 'a' && *a <= 'f')
|
||||
k = *a++ - 'a' + 10;
|
||||
else
|
||||
break;
|
||||
|
||||
j = (j << 4) + k;
|
||||
if (j >= 0x10000 || ++l > 4)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*a == ':' && a[1])
|
||||
a++;
|
||||
else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0))
|
||||
{ /* Embedded IPv4 address */
|
||||
ip4_addr x;
|
||||
if (!ip4_pton(start, &x))
|
||||
return 0;
|
||||
words[i++] = _I(x) >> 16;
|
||||
words[i++] = _I(x);
|
||||
break;
|
||||
}
|
||||
else if (*a)
|
||||
return 0;
|
||||
|
||||
if (i >= 8)
|
||||
return 0;
|
||||
|
||||
words[i++] = j;
|
||||
}
|
||||
|
||||
/* Replace :: with an appropriate number of zeros */
|
||||
if (hfil >= 0)
|
||||
{
|
||||
j = 8 - i;
|
||||
for (i=7; i-j >= hfil; i--)
|
||||
words[i] = words[i-j];
|
||||
for (; i>=hfil; i--)
|
||||
words[i] = 0;
|
||||
}
|
||||
|
||||
/* Convert the address to ip6_addr format */
|
||||
for (i=0; i<4; i++)
|
||||
o->addr[i] = (words[2*i] << 16) | words[2*i+1];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ip_scope_text - get textual representation of address scope
|
||||
* @scope: scope (%SCOPE_xxx)
|
||||
@ -25,7 +349,7 @@
|
||||
* Returns a pointer to a textual name of the scope given.
|
||||
*/
|
||||
char *
|
||||
ip_scope_text(unsigned scope)
|
||||
ip_scope_text(uint scope)
|
||||
{
|
||||
static char *scope_table[] = { "host", "link", "site", "org", "univ", "undef" };
|
||||
|
||||
@ -35,6 +359,23 @@ ip_scope_text(unsigned scope)
|
||||
return scope_table[scope];
|
||||
}
|
||||
|
||||
ip4_addr
|
||||
ip4_class_mask(ip4_addr ad)
|
||||
{
|
||||
u32 m, a = _I(ad);
|
||||
|
||||
if (a < 0x80000000)
|
||||
m = 0xff000000;
|
||||
else if (a < 0xc0000000)
|
||||
m = 0xffff0000;
|
||||
else
|
||||
m = 0xffffff00;
|
||||
if (a & ~m)
|
||||
m = 0xffffffff;
|
||||
|
||||
return _MI4(m);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* ipa_equal - compare two IP addresses for equality
|
||||
@ -102,14 +443,14 @@ ip_addr ipa_not(ip_addr x) { DUMMY }
|
||||
ip_addr ipa_mkmask(int x) { DUMMY }
|
||||
|
||||
/**
|
||||
* ipa_mkmask - calculate netmask length
|
||||
* ipa_masklen - calculate netmask length
|
||||
* @x: IP address
|
||||
*
|
||||
* This function checks whether @x represents a valid netmask and
|
||||
* returns the size of the associate network prefix or -1 for invalid
|
||||
* mask.
|
||||
*/
|
||||
int ipa_mklen(ip_addr x) { DUMMY }
|
||||
int ipa_masklen(ip_addr x) { DUMMY }
|
||||
|
||||
/**
|
||||
* ipa_hash - hash IP addresses
|
||||
@ -151,8 +492,8 @@ void ipa_ntoh(ip_addr x) { DUMMY }
|
||||
int ipa_classify(ip_addr x) { DUMMY }
|
||||
|
||||
/**
|
||||
* ipa_class_mask - guess netmask according to address class
|
||||
* @x: IP address
|
||||
* ip4_class_mask - guess netmask according to address class
|
||||
* @x: IPv4 address
|
||||
*
|
||||
* This function (available in IPv4 version only) returns a
|
||||
* network mask according to the address class of @x. Although
|
||||
@ -160,7 +501,7 @@ int ipa_classify(ip_addr x) { DUMMY }
|
||||
* routing protocols transferring no prefix lengths nor netmasks
|
||||
* and this function could be useful to them.
|
||||
*/
|
||||
ip_addr ipa_class_mask(ip_addr x) { DUMMY }
|
||||
ip4_addr ip4_class_mask(ip4_addr x) { DUMMY }
|
||||
|
||||
/**
|
||||
* ipa_from_u32 - convert IPv4 address to an integer
|
||||
@ -193,7 +534,7 @@ ip_addr ipa_to_u32(u32 x) { DUMMY }
|
||||
int ipa_compare(ip_addr x, ip_addr y) { DUMMY }
|
||||
|
||||
/**
|
||||
* ipa_build - build an IPv6 address from parts
|
||||
* ipa_build6 - build an IPv6 address from parts
|
||||
* @a1: part #1
|
||||
* @a2: part #2
|
||||
* @a3: part #3
|
||||
@ -203,18 +544,7 @@ int ipa_compare(ip_addr x, ip_addr y) { DUMMY }
|
||||
* address. It's used for example when a protocol wants to bind its
|
||||
* socket to a hard-wired multicast address.
|
||||
*/
|
||||
ip_addr ipa_build(u32 a1, u32 a2, u32 a3, u32 a4) { DUMMY }
|
||||
|
||||
/**
|
||||
* ipa_absolutize - convert link scope IPv6 address to universe scope
|
||||
* @x: link scope IPv6 address
|
||||
* @y: universe scope IPv6 prefix of the interface
|
||||
*
|
||||
* This function combines a link-scope IPv6 address @x with the universe
|
||||
* scope prefix @x of the network assigned to an interface to get a
|
||||
* universe scope form of @x.
|
||||
*/
|
||||
ip_addr ipa_absolutize(ip_addr x, ip_addr y) { DUMMY }
|
||||
ip_addr ipa_build6(u32 a1, u32 a2, u32 a3, u32 a4) { DUMMY }
|
||||
|
||||
/**
|
||||
* ip_ntop - convert IP address to textual representation
|
||||
|
475
lib/ip.h
475
lib/ip.h
@ -9,59 +9,474 @@
|
||||
#ifndef _BIRD_IP_H_
|
||||
#define _BIRD_IP_H_
|
||||
|
||||
#ifndef IPV6
|
||||
#include "ipv4.h"
|
||||
#include "lib/endian.h"
|
||||
#include "lib/string.h"
|
||||
#include "lib/bitops.h"
|
||||
#include "lib/unaligned.h"
|
||||
|
||||
|
||||
#define IP4_OSPF_ALL_ROUTERS ipa_build4(224, 0, 0, 5)
|
||||
#define IP4_OSPF_DES_ROUTERS ipa_build4(224, 0, 0, 6)
|
||||
|
||||
#define IP6_ALL_NODES ipa_build6(0xFF020000, 0, 0, 1)
|
||||
#define IP6_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 2)
|
||||
#define IP6_OSPF_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 5)
|
||||
#define IP6_OSPF_DES_ROUTERS ipa_build6(0xFF020000, 0, 0, 6)
|
||||
#define IP6_RIP_ROUTERS ipa_build6(0xFF020000, 0, 0, 9)
|
||||
|
||||
#define IP4_NONE _MI4(0)
|
||||
#define IP6_NONE _MI6(0,0,0,0)
|
||||
|
||||
#define IP4_MIN_MTU 576
|
||||
#define IP6_MIN_MTU 1280
|
||||
|
||||
#define IP_PREC_INTERNET_CONTROL 0xc0
|
||||
|
||||
|
||||
#ifdef IPV6
|
||||
#define MAX_PREFIX_LENGTH 128
|
||||
#define BITS_PER_IP_ADDRESS 128
|
||||
#define STD_ADDRESS_P_LENGTH 39
|
||||
#define SIZE_OF_IP_HEADER 40
|
||||
#else
|
||||
#include "ipv6.h"
|
||||
#define MAX_PREFIX_LENGTH 32
|
||||
#define BITS_PER_IP_ADDRESS 32
|
||||
#define STD_ADDRESS_P_LENGTH 15
|
||||
#define SIZE_OF_IP_HEADER 24
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DEBUGGING
|
||||
|
||||
typedef struct ip4_addr {
|
||||
u32 addr;
|
||||
} ip4_addr;
|
||||
|
||||
#define _MI4(x) ((struct ip4_addr) { x })
|
||||
#define _I(x) (x).addr
|
||||
|
||||
#else
|
||||
|
||||
typedef u32 ip4_addr;
|
||||
|
||||
#define _MI4(x) (x)
|
||||
#define _I(x) (x)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct ip6_addr {
|
||||
u32 addr[4];
|
||||
} ip6_addr;
|
||||
|
||||
#define _MI6(a,b,c,d) ((struct ip6_addr) {{ a, b, c, d }})
|
||||
#define _I0(a) ((a).addr[0])
|
||||
#define _I1(a) ((a).addr[1])
|
||||
#define _I2(a) ((a).addr[2])
|
||||
#define _I3(a) ((a).addr[3])
|
||||
|
||||
|
||||
#ifdef IPV6
|
||||
|
||||
/* Structure ip_addr may contain both IPv4 and IPv6 addresses */
|
||||
typedef ip6_addr ip_addr;
|
||||
#define IPA_NONE IP6_NONE
|
||||
|
||||
#define ipa_from_ip4(x) _MI6(0,0,0xffff,_I(x))
|
||||
#define ipa_from_ip6(x) x
|
||||
#define ipa_from_u32(x) ipa_from_ip4(ip4_from_u32(x))
|
||||
|
||||
#define ipa_to_ip4(x) _MI4(_I3(x))
|
||||
#define ipa_to_ip6(x) x
|
||||
#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x))
|
||||
|
||||
#define ipa_is_ip4(a) ip6_is_v4mapped(a)
|
||||
|
||||
#else
|
||||
|
||||
/* Provisionary ip_addr definition same as ip4_addr */
|
||||
typedef ip4_addr ip_addr;
|
||||
#define IPA_NONE IP4_NONE
|
||||
|
||||
#define ipa_from_ip4(x) x
|
||||
#define ipa_from_ip6(x) IPA_NONE
|
||||
#define ipa_from_u32(x) ipa_from_ip4(ip4_from_u32(x))
|
||||
|
||||
#define ipa_to_ip4(x) x
|
||||
#define ipa_to_ip6(x) IP6_NONE
|
||||
#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x))
|
||||
|
||||
#define ipa_is_ip4(a) 1
|
||||
|
||||
#endif
|
||||
|
||||
#define ipa_zero(x) (!ipa_nonzero(x))
|
||||
#define ip_is_prefix(a,l) (!ipa_nonzero(ipa_and(a, ipa_not(ipa_mkmask(l)))))
|
||||
#define ipa_in_net(x,n,p) (ipa_zero(ipa_and(ipa_xor((n),(x)),ipa_mkmask(p))))
|
||||
#define net_in_net(n1,l1,n2,l2) (((l1) >= (l2)) && (ipa_zero(ipa_and(ipa_xor((n1),(n2)),ipa_mkmask(l2)))))
|
||||
|
||||
/*
|
||||
* ip_classify() returns either a negative number for invalid addresses
|
||||
* or scope OR'ed together with address type.
|
||||
* Public constructors
|
||||
*/
|
||||
|
||||
#define ip4_from_u32(x) _MI4(x)
|
||||
#define ip4_to_u32(x) _I(x)
|
||||
|
||||
#define ip4_build(a,b,c,d) _MI4(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
|
||||
#define ip6_build(a,b,c,d) _MI6(a,b,c,d)
|
||||
|
||||
#define ipa_build4(a,b,c,d) ipa_from_ip4(ip4_build(a,b,c,d))
|
||||
#define ipa_build6(a,b,c,d) ipa_from_ip6(ip6_build(a,b,c,d))
|
||||
|
||||
|
||||
/*
|
||||
* Basic algebraic functions
|
||||
*/
|
||||
|
||||
static inline int ip4_equal(ip4_addr a, ip4_addr b)
|
||||
{ return _I(a) == _I(b); }
|
||||
|
||||
static inline int ip4_zero(ip4_addr a)
|
||||
{ return _I(a) == 0; }
|
||||
|
||||
static inline int ip4_nonzero(ip4_addr a)
|
||||
{ return _I(a) != 0; }
|
||||
|
||||
static inline ip4_addr ip4_and(ip4_addr a, ip4_addr b)
|
||||
{ return _MI4(_I(a) & _I(b)); }
|
||||
|
||||
static inline ip4_addr ip4_or(ip4_addr a, ip4_addr b)
|
||||
{ return _MI4(_I(a) | _I(b)); }
|
||||
|
||||
static inline ip4_addr ip4_xor(ip4_addr a, ip4_addr b)
|
||||
{ return _MI4(_I(a) ^ _I(b)); }
|
||||
|
||||
static inline ip4_addr ip4_not(ip4_addr a)
|
||||
{ return _MI4(~_I(a)); }
|
||||
|
||||
|
||||
static inline int ip6_equal(ip6_addr a, ip6_addr b)
|
||||
{ return _I0(a) == _I0(b) && _I1(a) == _I1(b) && _I2(a) == _I2(b) && _I3(a) == _I3(b); }
|
||||
|
||||
static inline int ip6_zero(ip6_addr a)
|
||||
{ return !_I0(a) && !_I1(a) && !_I2(a) && !_I3(a); }
|
||||
|
||||
static inline int ip6_nonzero(ip6_addr a)
|
||||
{ return _I0(a) || _I1(a) || _I2(a) || _I3(a); }
|
||||
|
||||
static inline ip6_addr ip6_and(ip6_addr a, ip6_addr b)
|
||||
{ return _MI6(_I0(a) & _I0(b), _I1(a) & _I1(b), _I2(a) & _I2(b), _I3(a) & _I3(b)); }
|
||||
|
||||
static inline ip6_addr ip6_or(ip6_addr a, ip6_addr b)
|
||||
{ return _MI6(_I0(a) | _I0(b), _I1(a) | _I1(b), _I2(a) | _I2(b), _I3(a) | _I3(b)); }
|
||||
|
||||
static inline ip6_addr ip6_xor(ip6_addr a, ip6_addr b)
|
||||
{ return _MI6(_I0(a) ^ _I0(b), _I1(a) ^ _I1(b), _I2(a) ^ _I2(b), _I3(a) ^ _I3(b)); }
|
||||
|
||||
static inline ip6_addr ip6_not(ip6_addr a)
|
||||
{ return _MI6(~_I0(a), ~_I1(a), ~_I2(a), ~_I3(a)); }
|
||||
|
||||
|
||||
#ifdef IPV6
|
||||
#define ipa_equal(x,y) ip6_equal(x,y)
|
||||
#define ipa_zero(x) ip6_zero(x)
|
||||
#define ipa_nonzero(x) ip6_nonzero(x)
|
||||
#define ipa_and(x,y) ip6_and(x,y)
|
||||
#define ipa_or(x,y) ip6_or(x,y)
|
||||
#define ipa_xor(x,y) ip6_xor(x,y)
|
||||
#define ipa_not(x) ip6_not(x)
|
||||
#else
|
||||
#define ipa_equal(x,y) ip4_equal(x,y)
|
||||
#define ipa_zero(x) ip4_zero(x)
|
||||
#define ipa_nonzero(x) ip4_nonzero(x)
|
||||
#define ipa_and(x,y) ip4_and(x,y)
|
||||
#define ipa_or(x,y) ip4_or(x,y)
|
||||
#define ipa_xor(x,y) ip4_xor(x,y)
|
||||
#define ipa_not(x) ip4_not(x)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef IPV6
|
||||
/*
|
||||
* A zero address is either a token for invalid/unused, or the prefix of default
|
||||
* routes. These functions should be used in the second case, where both IPv4
|
||||
* and IPv6 zero addresses should be checked.
|
||||
*/
|
||||
|
||||
static inline int ipa_zero2(ip_addr a)
|
||||
{ return !_I0(a) && !_I1(a) && ((_I2(a) == 0) || (_I2(a) == 0xffff)) && !_I3(a); }
|
||||
|
||||
static inline int ipa_nonzero2(ip_addr a)
|
||||
{ return _I0(a) || _I1(a) || ((_I2(a) != 0) && (_I2(a) != 0xffff)) || _I3(a); }
|
||||
|
||||
#else
|
||||
#define ipa_zero2(x) ip4_zero(x)
|
||||
#define ipa_nonzero2(x) ip4_nonzero(x)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Hash and compare functions
|
||||
*/
|
||||
|
||||
static inline uint ip4_hash(ip4_addr a)
|
||||
{
|
||||
/* Returns a 16-bit value */
|
||||
u32 x = _I(a);
|
||||
x ^= x >> 16;
|
||||
x ^= x << 10;
|
||||
return x & 0xffff;
|
||||
}
|
||||
|
||||
static inline u32 ip4_hash32(ip4_addr a)
|
||||
{
|
||||
/* Returns a 32-bit value, although low-order bits are not mixed */
|
||||
u32 x = _I(a);
|
||||
x ^= x << 16;
|
||||
x ^= x << 12;
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline uint ip6_hash(ip6_addr a)
|
||||
{
|
||||
/* Returns a 16-bit hash key */
|
||||
u32 x = _I0(a) ^ _I1(a) ^ _I2(a) ^ _I3(a);
|
||||
return (x ^ (x >> 16) ^ (x >> 8)) & 0xffff;
|
||||
}
|
||||
|
||||
static inline u32 ip6_hash32(ip6_addr a)
|
||||
{
|
||||
/* Returns a 32-bit hash key, although low-order bits are not mixed */
|
||||
u32 x = _I0(a) ^ _I1(a) ^ _I2(a) ^ _I3(a);
|
||||
return x ^ (x << 16) ^ (x << 24);
|
||||
}
|
||||
|
||||
static inline int ip4_compare(ip4_addr a, ip4_addr b)
|
||||
{ return (_I(a) > _I(b)) - (_I(a) < _I(b)); }
|
||||
|
||||
int ip6_compare(ip6_addr a, ip6_addr b);
|
||||
|
||||
|
||||
#ifdef IPV6
|
||||
#define ipa_hash(x) ip6_hash(x)
|
||||
#define ipa_hash32(x) ip6_hash32(x)
|
||||
#define ipa_compare(x,y) ip6_compare(x,y)
|
||||
#else
|
||||
#define ipa_hash(x) ip4_hash(x)
|
||||
#define ipa_hash32(x) ip4_hash32(x)
|
||||
#define ipa_compare(x,y) ip4_compare(x,y)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* IP address classification
|
||||
*/
|
||||
|
||||
/* Address class */
|
||||
#define IADDR_INVALID -1
|
||||
#define IADDR_SCOPE_MASK 0xfff
|
||||
#define IADDR_HOST 0x1000
|
||||
#define IADDR_BROADCAST 0x2000
|
||||
#define IADDR_MULTICAST 0x4000
|
||||
|
||||
/* Address scope */
|
||||
#define SCOPE_HOST 0
|
||||
#define SCOPE_LINK 1
|
||||
#define SCOPE_SITE 2
|
||||
#define SCOPE_ORGANIZATION 3
|
||||
#define SCOPE_UNIVERSE 4
|
||||
#define SCOPE_UNDEFINED 5
|
||||
|
||||
int ip4_classify(ip4_addr ad);
|
||||
int ip6_classify(ip6_addr *a);
|
||||
|
||||
static inline int ip6_is_link_local(ip6_addr a)
|
||||
{ return (_I0(a) & 0xffc00000) == 0xfe800000; }
|
||||
|
||||
static inline int ip6_is_v4mapped(ip6_addr a)
|
||||
{ return _I0(a) == 0 && _I1(a) == 0 && _I2(a) == 0xffff; }
|
||||
|
||||
#ifdef IPV6
|
||||
#define ipa_classify(x) ip6_classify(&(x))
|
||||
#define ipa_is_link_local(x) ip6_is_link_local(x)
|
||||
#else
|
||||
#define ipa_classify(x) ip4_classify(x)
|
||||
#define ipa_is_link_local(x) 0
|
||||
#endif
|
||||
|
||||
static inline int ipa_classify_net(ip_addr a)
|
||||
{ return ipa_zero2(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); }
|
||||
|
||||
|
||||
/*
|
||||
* Address scope
|
||||
* Miscellaneous IP prefix manipulation
|
||||
*/
|
||||
|
||||
#define SCOPE_HOST 0
|
||||
#define SCOPE_LINK 1
|
||||
#define SCOPE_SITE 2
|
||||
#define SCOPE_ORGANIZATION 3
|
||||
#define SCOPE_UNIVERSE 4
|
||||
#define SCOPE_UNDEFINED 5
|
||||
static inline ip4_addr ip4_mkmask(uint n)
|
||||
{ return _MI4(u32_mkmask(n)); }
|
||||
|
||||
static inline int ip4_masklen(ip4_addr a)
|
||||
{ return u32_masklen(_I(a)); }
|
||||
|
||||
ip6_addr ip6_mkmask(uint n);
|
||||
int ip6_masklen(ip6_addr *a);
|
||||
|
||||
/* ipX_pxlen() requires that x != y */
|
||||
static inline uint ip4_pxlen(ip4_addr a, ip4_addr b)
|
||||
{ return 31 - u32_log2(_I(a) ^ _I(b)); }
|
||||
|
||||
static inline uint ip6_pxlen(ip6_addr a, ip6_addr b)
|
||||
{
|
||||
int i = 0;
|
||||
i += (a.addr[i] == b.addr[i]);
|
||||
i += (a.addr[i] == b.addr[i]);
|
||||
i += (a.addr[i] == b.addr[i]);
|
||||
i += (a.addr[i] == b.addr[i]);
|
||||
return 32 * i + 31 - u32_log2(a.addr[i] ^ b.addr[i]);
|
||||
}
|
||||
|
||||
static inline u32 ip4_getbit(ip4_addr a, uint pos)
|
||||
{ return _I(a) & (0x80000000 >> pos); }
|
||||
|
||||
static inline u32 ip6_getbit(ip6_addr a, uint pos)
|
||||
{ return a.addr[pos / 32] & (0x80000000 >> (pos % 32)); }
|
||||
|
||||
static inline ip4_addr ip4_opposite_m1(ip4_addr a)
|
||||
{ return _MI4(_I(a) ^ 1); }
|
||||
|
||||
static inline ip4_addr ip4_opposite_m2(ip4_addr a)
|
||||
{ return _MI4(_I(a) ^ 3); }
|
||||
|
||||
static inline ip6_addr ip6_opposite_m1(ip6_addr a)
|
||||
{ return _MI6(_I0(a), _I1(a), _I2(a), _I3(a) ^ 1); }
|
||||
|
||||
static inline ip6_addr ip6_opposite_m2(ip6_addr a)
|
||||
{ return _MI6(_I0(a), _I1(a), _I2(a), _I3(a) ^ 3); }
|
||||
|
||||
ip4_addr ip4_class_mask(ip4_addr ad);
|
||||
|
||||
#ifdef IPV6
|
||||
#define ipa_mkmask(x) ip6_mkmask(x)
|
||||
#define ipa_masklen(x) ip6_masklen(&x)
|
||||
#define ipa_pxlen(x,y) ip6_pxlen(x,y)
|
||||
#define ipa_getbit(x,n) ip6_getbit(x,n)
|
||||
#define ipa_opposite_m1(x) ip6_opposite_m1(x)
|
||||
#define ipa_opposite_m2(x) ip6_opposite_m2(x)
|
||||
#else
|
||||
#define ipa_mkmask(x) ip4_mkmask(x)
|
||||
#define ipa_masklen(x) ip4_masklen(x)
|
||||
#define ipa_pxlen(x,y) ip4_pxlen(x,y)
|
||||
#define ipa_getbit(x,n) ip4_getbit(x,n)
|
||||
#define ipa_opposite_m1(x) ip4_opposite_m1(x)
|
||||
#define ipa_opposite_m2(x) ip4_opposite_m2(x)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Host/network order conversions
|
||||
*/
|
||||
|
||||
static inline ip4_addr ip4_hton(ip4_addr a)
|
||||
{ return _MI4(htonl(_I(a))); }
|
||||
|
||||
static inline ip4_addr ip4_ntoh(ip4_addr a)
|
||||
{ return _MI4(ntohl(_I(a))); }
|
||||
|
||||
static inline ip6_addr ip6_hton(ip6_addr a)
|
||||
{ return _MI6(htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a))); }
|
||||
|
||||
static inline ip6_addr ip6_ntoh(ip6_addr a)
|
||||
{ return _MI6(ntohl(_I0(a)), ntohl(_I1(a)), ntohl(_I2(a)), ntohl(_I3(a))); }
|
||||
|
||||
#ifdef IPV6
|
||||
#define ipa_hton(x) x = ip6_hton(x)
|
||||
#define ipa_ntoh(x) x = ip6_ntoh(x)
|
||||
#else
|
||||
#define ipa_hton(x) x = ip4_hton(x)
|
||||
#define ipa_ntoh(x) x = ip4_ntoh(x)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Unaligned data access (in network order)
|
||||
*/
|
||||
|
||||
static inline ip4_addr get_ip4(void *buf)
|
||||
{
|
||||
return _MI4(get_u32(buf));
|
||||
}
|
||||
|
||||
static inline ip6_addr get_ip6(void *buf)
|
||||
{
|
||||
ip6_addr a;
|
||||
memcpy(&a, buf, 16);
|
||||
return ip6_ntoh(a);
|
||||
}
|
||||
|
||||
static inline void * put_ip4(void *buf, ip4_addr a)
|
||||
{
|
||||
put_u32(buf, _I(a));
|
||||
return buf+4;
|
||||
}
|
||||
|
||||
static inline void * put_ip6(void *buf, ip6_addr a)
|
||||
{
|
||||
a = ip6_hton(a);
|
||||
memcpy(buf, &a, 16);
|
||||
return buf+16;
|
||||
}
|
||||
|
||||
// XXXX these functions must be redesigned or removed
|
||||
#ifdef IPV6
|
||||
#define get_ipa(x) get_ip6(x)
|
||||
#define put_ipa(x,y) put_ip6(x,y)
|
||||
#else
|
||||
#define get_ipa(x) get_ip4(x)
|
||||
#define put_ipa(x,y) put_ip4(x,y)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Binary/text form conversions
|
||||
*/
|
||||
|
||||
char *ip4_ntop(ip4_addr a, char *b);
|
||||
char *ip6_ntop(ip6_addr a, char *b);
|
||||
|
||||
static inline char * ip4_ntox(ip4_addr a, char *b)
|
||||
{ return b + bsprintf(b, "%08x", _I(a)); }
|
||||
|
||||
static inline char * ip6_ntox(ip6_addr a, char *b)
|
||||
{ return b + bsprintf(b, "%08x.%08x.%08x.%08x", _I0(a), _I1(a), _I2(a), _I3(a)); }
|
||||
|
||||
int ip4_pton(char *a, ip4_addr *o);
|
||||
int ip6_pton(char *a, ip6_addr *o);
|
||||
|
||||
// XXXX these functions must be redesigned or removed
|
||||
#ifdef IPV6
|
||||
#define ipa_ntop(x,y) ip6_ntop(x,y)
|
||||
#define ipa_ntox(x,y) ip6_ntox(x,y)
|
||||
#define ipa_pton(x,y) ip6_pton(x,y)
|
||||
#else
|
||||
#define ipa_ntop(x,y) ip4_ntop(x,y)
|
||||
#define ipa_ntox(x,y) ip4_ntox(x,y)
|
||||
#define ipa_pton(x,y) ip4_pton(x,y)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Miscellaneous
|
||||
*/
|
||||
|
||||
// XXXX review this
|
||||
|
||||
#define ip_is_prefix(a,l) (!ipa_nonzero(ipa_and(a, ipa_not(ipa_mkmask(l)))))
|
||||
#define ipa_in_net(x,n,p) (ipa_zero(ipa_and(ipa_xor((n),(x)),ipa_mkmask(p))))
|
||||
#define net_in_net(n1,l1,n2,l2) (((l1) >= (l2)) && (ipa_zero(ipa_and(ipa_xor((n1),(n2)),ipa_mkmask(l2)))))
|
||||
|
||||
char *ip_scope_text(unsigned);
|
||||
|
||||
/*
|
||||
* Network prefixes
|
||||
*/
|
||||
|
||||
struct prefix {
|
||||
ip_addr addr;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
static inline int ipa_classify_net(ip_addr a)
|
||||
{ return ipa_zero(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); }
|
||||
|
||||
/*
|
||||
* Conversions between internal and string representation
|
||||
*/
|
||||
|
||||
char *ip_ntop(ip_addr a, char *);
|
||||
char *ip_ntox(ip_addr a, char *);
|
||||
int ip_pton(char *a, ip_addr *o);
|
||||
|
||||
#endif
|
||||
|
110
lib/ipv4.c
110
lib/ipv4.c
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* BIRD Library -- IPv4 Address Manipulation Functions
|
||||
*
|
||||
* (c) 1998 Martin Mares <mj@ucw.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "lib/ip.h"
|
||||
#include "lib/string.h"
|
||||
|
||||
int
|
||||
ipv4_classify(u32 a)
|
||||
{
|
||||
u32 b = a >> 24U;
|
||||
|
||||
if (b && b <= 0xdf)
|
||||
{
|
||||
if (b == 0x7f)
|
||||
return IADDR_HOST | SCOPE_HOST;
|
||||
else if (b == 0x0a ||
|
||||
(a & 0xffff0000) == 0xc0a80000 ||
|
||||
(a & 0xfff00000) == 0xac100000)
|
||||
return IADDR_HOST | SCOPE_SITE;
|
||||
else
|
||||
return IADDR_HOST | SCOPE_UNIVERSE;
|
||||
}
|
||||
if (b >= 0xe0 && b <= 0xef)
|
||||
return IADDR_MULTICAST | SCOPE_UNIVERSE;
|
||||
if (a == 0xffffffff)
|
||||
return IADDR_BROADCAST | SCOPE_LINK;
|
||||
return IADDR_INVALID;
|
||||
}
|
||||
|
||||
char *
|
||||
ip_ntop(ip_addr a, char *b)
|
||||
{
|
||||
u32 x = _I(a);
|
||||
|
||||
return b + bsprintf(b, "%d.%d.%d.%d",
|
||||
((x >> 24) & 0xff),
|
||||
((x >> 16) & 0xff),
|
||||
((x >> 8) & 0xff),
|
||||
(x & 0xff));
|
||||
}
|
||||
|
||||
char *
|
||||
ip_ntox(ip_addr a, char *b)
|
||||
{
|
||||
return b + bsprintf(b, "%08x", _I(a));
|
||||
}
|
||||
|
||||
u32
|
||||
ipv4_class_mask(u32 a)
|
||||
{
|
||||
u32 m;
|
||||
|
||||
if (a < 0x80000000)
|
||||
m = 0xff000000;
|
||||
else if (a < 0xc0000000)
|
||||
m = 0xffff0000;
|
||||
else
|
||||
m = 0xffffff00;
|
||||
while (a & ~m)
|
||||
m |= m >> 1;
|
||||
return m;
|
||||
}
|
||||
|
||||
int
|
||||
ip_pton(char *a, ip_addr *o)
|
||||
{
|
||||
int i;
|
||||
unsigned long int l;
|
||||
u32 ia = 0;
|
||||
|
||||
i=4;
|
||||
while (i--)
|
||||
{
|
||||
char *d, *c = strchr(a, '.');
|
||||
if (!c != !i)
|
||||
return 0;
|
||||
l = strtoul(a, &d, 10);
|
||||
if (d != c && *d || l > 255)
|
||||
return 0;
|
||||
ia = (ia << 8) | l;
|
||||
if (c)
|
||||
c++;
|
||||
a = c;
|
||||
}
|
||||
*o = ipa_from_u32(ia);
|
||||
return 1;
|
||||
}
|
||||
|
||||
byte *
|
||||
ipv4_skip_header(byte *pkt, int *len)
|
||||
{
|
||||
int l = *len;
|
||||
int q;
|
||||
|
||||
if (l < 20 || (*pkt & 0xf0) != 0x40)
|
||||
return NULL;
|
||||
q = (*pkt & 0x0f) * 4;
|
||||
if (q > l)
|
||||
return NULL;
|
||||
*len -= q;
|
||||
return pkt + q;
|
||||
}
|
116
lib/ipv4.h
116
lib/ipv4.h
@ -1,116 +0,0 @@
|
||||
/*
|
||||
* BIRD -- IP Addresses et Cetera for IPv4
|
||||
*
|
||||
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_IPV4_H_
|
||||
#define _BIRD_IPV4_H_
|
||||
|
||||
#include "lib/endian.h"
|
||||
#include "lib/bitops.h"
|
||||
#include "lib/unaligned.h"
|
||||
|
||||
#ifdef DEBUGGING
|
||||
|
||||
/*
|
||||
* Use the structural representation when you want to make sure
|
||||
* nobody unauthorized attempts to handle ip_addr as number.
|
||||
*/
|
||||
|
||||
typedef struct ipv4_addr {
|
||||
u32 addr;
|
||||
} ip_addr;
|
||||
|
||||
#define _I(x) (x).addr
|
||||
#define _MI(x) ((struct ipv4_addr) { x })
|
||||
|
||||
#else
|
||||
|
||||
typedef u32 ip_addr;
|
||||
|
||||
#define _I(x) (x)
|
||||
#define _MI(x) (x)
|
||||
|
||||
#endif
|
||||
|
||||
#define MAX_PREFIX_LENGTH 32
|
||||
#define BITS_PER_IP_ADDRESS 32
|
||||
#define STD_ADDRESS_P_LENGTH 15
|
||||
#define SIZE_OF_IP_HEADER 24
|
||||
|
||||
#define IPA_NONE (_MI(0))
|
||||
|
||||
#define ipa_equal(x,y) (_I(x) == _I(y))
|
||||
#define ipa_nonzero(x) _I(x)
|
||||
#define ipa_and(x,y) _MI(_I(x) & _I(y))
|
||||
#define ipa_or(x,y) _MI(_I(x) | _I(y))
|
||||
#define ipa_xor(x,y) _MI(_I(x) ^ _I(y))
|
||||
#define ipa_not(x) _MI(~_I(x))
|
||||
#define ipa_mkmask(x) _MI(u32_mkmask(x))
|
||||
#define ipa_mklen(x) u32_masklen(_I(x))
|
||||
#define ipa_hash(x) ipv4_hash(_I(x))
|
||||
#define ipa_hash32(x) ipv4_hash32(_I(x))
|
||||
#define ipa_hton(x) x = _MI(htonl(_I(x)))
|
||||
#define ipa_ntoh(x) x = _MI(ntohl(_I(x)))
|
||||
#define ipa_classify(x) ipv4_classify(_I(x))
|
||||
#define ipa_has_link_scope(x) ipv4_has_link_scope(_I(x))
|
||||
#define ipa_opposite_m1(x) _MI(_I(x) ^ 1)
|
||||
#define ipa_opposite_m2(x) _MI(_I(x) ^ 3)
|
||||
#define ipa_class_mask(x) _MI(ipv4_class_mask(_I(x)))
|
||||
#define ipa_from_u32(x) _MI(x)
|
||||
#define ipa_to_u32(x) _I(x)
|
||||
#define ipa_compare(x,y) ipv4_compare(_I(x),_I(y))
|
||||
/* ipa_pxlen() requires that x != y */
|
||||
#define ipa_pxlen(x, y) ipv4_pxlen(_I(x), _I(y))
|
||||
#define ipa_getbit(x, y) (_I(x) & (0x80000000 >> (y)))
|
||||
#define ipa_put_addr(x, y) ipv4_put_addr(x, y)
|
||||
|
||||
#define ip_skip_header(x, y) ipv4_skip_header(x, y)
|
||||
|
||||
int ipv4_classify(u32);
|
||||
u32 ipv4_class_mask(u32);
|
||||
byte *ipv4_skip_header(byte *, int *);
|
||||
|
||||
static inline int ipv4_has_link_scope(u32 a UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned ipv4_hash(u32 a)
|
||||
{
|
||||
/* Returns a 16-bit value */
|
||||
a ^= a >> 16;
|
||||
a ^= a << 10;
|
||||
return a & 0xffff;
|
||||
}
|
||||
|
||||
static inline u32 ipv4_hash32(u32 a)
|
||||
{
|
||||
/* Returns a 32-bit value, although low-order bits are not mixed */
|
||||
a ^= a << 16;
|
||||
a ^= a << 12;
|
||||
return a;
|
||||
}
|
||||
|
||||
static inline int ipv4_compare(u32 x, u32 y)
|
||||
{
|
||||
return (x > y) - (x < y);
|
||||
}
|
||||
|
||||
static inline u32 ipv4_pxlen(u32 a, u32 b)
|
||||
{
|
||||
return 31 - u32_log2(a ^ b);
|
||||
}
|
||||
|
||||
static inline byte * ipv4_put_addr(byte *buf, ip_addr a)
|
||||
{
|
||||
put_u32(buf, _I(a));
|
||||
return buf+4;
|
||||
}
|
||||
|
||||
#define IP_PREC_INTERNET_CONTROL 0xc0
|
||||
|
||||
#endif
|
384
lib/ipv6.c
384
lib/ipv6.c
@ -1,384 +0,0 @@
|
||||
/*
|
||||
* BIRD Library -- IPv6 Address Manipulation Functions
|
||||
*
|
||||
* (c) 1999 Martin Mares <mj@ucw.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "lib/ip.h"
|
||||
#include "lib/bitops.h"
|
||||
#include "lib/endian.h"
|
||||
#include "lib/string.h"
|
||||
|
||||
/*
|
||||
* See RFC 2373 for explanation of IPv6 addressing issues.
|
||||
*/
|
||||
|
||||
ip_addr
|
||||
ipv6_mkmask(unsigned n)
|
||||
{
|
||||
ip_addr a;
|
||||
int i;
|
||||
|
||||
for(i=0; i<4; i++)
|
||||
{
|
||||
if (!n)
|
||||
a.addr[i] = 0;
|
||||
else if (n >= 32)
|
||||
{
|
||||
a.addr[i] = ~0;
|
||||
n -= 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
a.addr[i] = u32_mkmask(n);
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
unsigned
|
||||
ipv6_mklen(ip_addr *a)
|
||||
{
|
||||
int i, j, n;
|
||||
|
||||
for(i=0, n=0; i<4; i++, n+=32)
|
||||
if (a->addr[i] != ~0U)
|
||||
{
|
||||
j = u32_masklen(a->addr[i]);
|
||||
if (j < 0)
|
||||
return j;
|
||||
n += j;
|
||||
while (++i < 4)
|
||||
if (a->addr[i])
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
ipv6_classify(ip_addr *a)
|
||||
{
|
||||
u32 x = a->addr[0];
|
||||
|
||||
if ((x & 0xe0000000) == 0x20000000) /* 2000::/3 Aggregatable Global Unicast Address */
|
||||
return IADDR_HOST | SCOPE_UNIVERSE;
|
||||
if ((x & 0xffc00000) == 0xfe800000) /* fe80::/10 Link-Local Address */
|
||||
return IADDR_HOST | SCOPE_LINK;
|
||||
if ((x & 0xffc00000) == 0xfec00000) /* fec0::/10 Site-Local Address */
|
||||
return IADDR_HOST | SCOPE_SITE;
|
||||
if ((x & 0xfe000000) == 0xfc000000) /* fc00::/7 Unique Local Unicast Address (RFC 4193) */
|
||||
return IADDR_HOST | SCOPE_SITE;
|
||||
if ((x & 0xff000000) == 0xff000000) /* ff00::/8 Multicast Address */
|
||||
{
|
||||
unsigned int scope = (x >> 16) & 0x0f;
|
||||
switch (scope)
|
||||
{
|
||||
case 1: return IADDR_MULTICAST | SCOPE_HOST;
|
||||
case 2: return IADDR_MULTICAST | SCOPE_LINK;
|
||||
case 5: return IADDR_MULTICAST | SCOPE_SITE;
|
||||
case 8: return IADDR_MULTICAST | SCOPE_ORGANIZATION;
|
||||
case 14: return IADDR_MULTICAST | SCOPE_UNIVERSE;
|
||||
default: return IADDR_MULTICAST | SCOPE_UNDEFINED;
|
||||
}
|
||||
}
|
||||
if (!x && !a->addr[1] && !a->addr[2])
|
||||
{
|
||||
u32 y = a->addr[3];
|
||||
if (y == 1)
|
||||
return IADDR_HOST | SCOPE_HOST; /* Loopback address */
|
||||
/* IPv4 compatible addresses */
|
||||
if (y >= 0x7f000000 && y < 0x80000000)
|
||||
return IADDR_HOST | SCOPE_HOST;
|
||||
if ((y & 0xff000000) == 0x0a000000 ||
|
||||
(y & 0xffff0000) == 0xc0a80000 ||
|
||||
(y & 0xfff00000) == 0xac100000)
|
||||
return IADDR_HOST | SCOPE_SITE;
|
||||
if (y >= 0x01000000 && y < 0xe0000000)
|
||||
return IADDR_HOST | SCOPE_UNIVERSE;
|
||||
}
|
||||
return IADDR_HOST | SCOPE_UNDEFINED;
|
||||
}
|
||||
|
||||
void
|
||||
ipv6_hton(ip_addr *a)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<4; i++)
|
||||
a->addr[i] = htonl(a->addr[i]);
|
||||
}
|
||||
|
||||
void
|
||||
ipv6_ntoh(ip_addr *a)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<4; i++)
|
||||
a->addr[i] = ntohl(a->addr[i]);
|
||||
}
|
||||
|
||||
int
|
||||
ipv6_compare(ip_addr X, ip_addr Y)
|
||||
{
|
||||
int i;
|
||||
ip_addr *x = &X;
|
||||
ip_addr *y = &Y;
|
||||
|
||||
for(i=0; i<4; i++)
|
||||
if (x->addr[i] > y->addr[i])
|
||||
return 1;
|
||||
else if (x->addr[i] < y->addr[i])
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Conversion of IPv6 address to presentation format and vice versa.
|
||||
* Heavily inspired by routines written by Paul Vixie for the BIND project
|
||||
* and of course by RFC 2373.
|
||||
*/
|
||||
|
||||
char *
|
||||
ip_ntop(ip_addr a, char *b)
|
||||
{
|
||||
u16 words[8];
|
||||
int bestpos, bestlen, curpos, curlen, i;
|
||||
|
||||
/* First of all, preprocess the address and find the longest run of zeros */
|
||||
bestlen = bestpos = curpos = curlen = 0;
|
||||
for(i=0; i<8; i++)
|
||||
{
|
||||
u32 x = a.addr[i/2];
|
||||
words[i] = ((i%2) ? x : (x >> 16)) & 0xffff;
|
||||
if (words[i])
|
||||
curlen = 0;
|
||||
else
|
||||
{
|
||||
if (!curlen)
|
||||
curpos = i;
|
||||
curlen++;
|
||||
if (curlen > bestlen)
|
||||
{
|
||||
bestpos = curpos;
|
||||
bestlen = curlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bestlen < 2)
|
||||
bestpos = -1;
|
||||
|
||||
/* Is it an encapsulated IPv4 address? */
|
||||
if (!bestpos &&
|
||||
(bestlen == 5 && a.addr[2] == 0xffff ||
|
||||
bestlen == 6))
|
||||
{
|
||||
u32 x = a.addr[3];
|
||||
b += bsprintf(b, "::%s%d.%d.%d.%d",
|
||||
a.addr[2] ? "ffff:" : "",
|
||||
((x >> 24) & 0xff),
|
||||
((x >> 16) & 0xff),
|
||||
((x >> 8) & 0xff),
|
||||
(x & 0xff));
|
||||
return b;
|
||||
}
|
||||
|
||||
/* Normal IPv6 formatting, compress the largest sequence of zeros */
|
||||
for(i=0; i<8; i++)
|
||||
{
|
||||
if (i == bestpos)
|
||||
{
|
||||
i += bestlen - 1;
|
||||
*b++ = ':';
|
||||
if (i == 7)
|
||||
*b++ = ':';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i)
|
||||
*b++ = ':';
|
||||
b += bsprintf(b, "%x", words[i]);
|
||||
}
|
||||
}
|
||||
*b = 0;
|
||||
return b;
|
||||
}
|
||||
|
||||
char *
|
||||
ip_ntox(ip_addr a, char *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<4; i++)
|
||||
{
|
||||
if (i)
|
||||
*b++ = '.';
|
||||
b += bsprintf(b, "%08x", a.addr[i]);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
int
|
||||
ipv4_pton_u32(char *a, u32 *o)
|
||||
{
|
||||
int i;
|
||||
unsigned long int l;
|
||||
u32 ia = 0;
|
||||
|
||||
i=4;
|
||||
while (i--)
|
||||
{
|
||||
char *d, *c = strchr(a, '.');
|
||||
if (!c != !i)
|
||||
return 0;
|
||||
l = strtoul(a, &d, 10);
|
||||
if (d != c && *d || l > 255)
|
||||
return 0;
|
||||
ia = (ia << 8) | l;
|
||||
if (c)
|
||||
c++;
|
||||
a = c;
|
||||
}
|
||||
*o = ia;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
ip_pton(char *a, ip_addr *o)
|
||||
{
|
||||
u16 words[8];
|
||||
int i, j, k, l, hfil;
|
||||
char *start;
|
||||
|
||||
if (a[0] == ':') /* Leading :: */
|
||||
{
|
||||
if (a[1] != ':')
|
||||
return 0;
|
||||
a++;
|
||||
}
|
||||
hfil = -1;
|
||||
i = 0;
|
||||
while (*a)
|
||||
{
|
||||
if (*a == ':') /* :: */
|
||||
{
|
||||
if (hfil >= 0)
|
||||
return 0;
|
||||
hfil = i;
|
||||
a++;
|
||||
continue;
|
||||
}
|
||||
j = 0;
|
||||
l = 0;
|
||||
start = a;
|
||||
for(;;)
|
||||
{
|
||||
if (*a >= '0' && *a <= '9')
|
||||
k = *a++ - '0';
|
||||
else if (*a >= 'A' && *a <= 'F')
|
||||
k = *a++ - 'A' + 10;
|
||||
else if (*a >= 'a' && *a <= 'f')
|
||||
k = *a++ - 'a' + 10;
|
||||
else
|
||||
break;
|
||||
j = (j << 4) + k;
|
||||
if (j >= 0x10000 || ++l > 4)
|
||||
return 0;
|
||||
}
|
||||
if (*a == ':' && a[1])
|
||||
a++;
|
||||
else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0))
|
||||
{ /* Embedded IPv4 address */
|
||||
u32 x;
|
||||
if (!ipv4_pton_u32(start, &x))
|
||||
return 0;
|
||||
words[i++] = x >> 16;
|
||||
words[i++] = x;
|
||||
break;
|
||||
}
|
||||
else if (*a)
|
||||
return 0;
|
||||
if (i >= 8)
|
||||
return 0;
|
||||
words[i++] = j;
|
||||
}
|
||||
|
||||
/* Replace :: with an appropriate number of zeros */
|
||||
if (hfil >= 0)
|
||||
{
|
||||
j = 8 - i;
|
||||
for(i=7; i-j >= hfil; i--)
|
||||
words[i] = words[i-j];
|
||||
for(; i>=hfil; i--)
|
||||
words[i] = 0;
|
||||
}
|
||||
|
||||
/* Convert the address to ip_addr format */
|
||||
for(i=0; i<4; i++)
|
||||
o->addr[i] = (words[2*i] << 16) | words[2*i+1];
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ipv6_absolutize(ip_addr *a, ip_addr *ifa)
|
||||
{
|
||||
if ((a->addr[0] & 0xffc00000) == 0xfe800000 && /* a is link-scope */
|
||||
((ifa->addr[0] & 0xe0000000) == 0x20000000 | /* ifa is AGU ... */
|
||||
(ifa->addr[0] & 0xffc00000) == 0xfec00000)) /* ... or site-scope */
|
||||
{
|
||||
a->addr[0] = ifa->addr[0]; /* Copy the prefix, leave interface ID */
|
||||
a->addr[1] = ifa->addr[1];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include "bitops.c"
|
||||
|
||||
static void test(char *x)
|
||||
{
|
||||
ip_addr a;
|
||||
char c[STD_ADDRESS_P_LENGTH+1];
|
||||
|
||||
printf("%-40s ", x);
|
||||
if (!ip_pton(x, &a))
|
||||
{
|
||||
puts("BAD");
|
||||
return;
|
||||
}
|
||||
ip_ntop(a, c);
|
||||
printf("%-40s %04x\n", c, ipv6_classify(&a));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
puts("Positive tests:");
|
||||
test("1:2:3:4:5:6:7:8");
|
||||
test("dead:beef:DEAD:BEEF::f00d");
|
||||
test("::");
|
||||
test("::1");
|
||||
test("1::");
|
||||
test("::1.234.5.6");
|
||||
test("::ffff:1.234.5.6");
|
||||
test("::fffe:1.234.5.6");
|
||||
test("1:2:3:4:5:6:7::8");
|
||||
test("2080::8:800:200c:417a");
|
||||
test("ff01::101");
|
||||
|
||||
puts("Negative tests:");
|
||||
test(":::");
|
||||
test("1:2:3:4:5:6:7:8:");
|
||||
test("1::2::3");
|
||||
test("::12345");
|
||||
test("::1.2.3.4:5");
|
||||
test(":1:2:3:4:5:6:7:8");
|
||||
test("g:1:2:3:4:5:6:7");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
141
lib/ipv6.h
141
lib/ipv6.h
@ -1,141 +0,0 @@
|
||||
|
||||
/*
|
||||
* BIRD -- IP Addresses et Cetera for IPv6
|
||||
*
|
||||
* (c) 1999--2000 Martin Mares <mj@ucw.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_IPV6_H_
|
||||
#define _BIRD_IPV6_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include "lib/string.h"
|
||||
#include "lib/bitops.h"
|
||||
#include "lib/unaligned.h"
|
||||
|
||||
typedef struct ipv6_addr {
|
||||
u32 addr[4];
|
||||
} ip_addr;
|
||||
|
||||
#define _MI(a,b,c,d) ((struct ipv6_addr) {{ a, b, c, d }})
|
||||
#define _I0(a) ((a).addr[0])
|
||||
#define _I1(a) ((a).addr[1])
|
||||
#define _I2(a) ((a).addr[2])
|
||||
#define _I3(a) ((a).addr[3])
|
||||
|
||||
#define MAX_PREFIX_LENGTH 128
|
||||
#define BITS_PER_IP_ADDRESS 128
|
||||
#define STD_ADDRESS_P_LENGTH 39
|
||||
#define SIZE_OF_IP_HEADER 40
|
||||
|
||||
#define IPA_NONE _MI(0,0,0,0)
|
||||
|
||||
#define ipa_equal(x,y) ({ ip_addr _a=(x), _b=(y); \
|
||||
_I0(_a) == _I0(_b) && \
|
||||
_I1(_a) == _I1(_b) && \
|
||||
_I2(_a) == _I2(_b) && \
|
||||
_I3(_a) == _I3(_b); })
|
||||
#define ipa_nonzero(x) ({ ip_addr _a=(x); (_I0(_a) || _I1(_a) || _I2(_a) || _I3(_a)); })
|
||||
#define ipa_and(x,y) ({ ip_addr _a=(x), _b=(y); \
|
||||
_MI(_I0(_a) & _I0(_b), \
|
||||
_I1(_a) & _I1(_b), \
|
||||
_I2(_a) & _I2(_b), \
|
||||
_I3(_a) & _I3(_b)); })
|
||||
#define ipa_or(x,y) ({ ip_addr _a=(x), _b=(y); \
|
||||
_MI(_I0(_a) | _I0(_b), \
|
||||
_I1(_a) | _I1(_b), \
|
||||
_I2(_a) | _I2(_b), \
|
||||
_I3(_a) | _I3(_b)); })
|
||||
#define ipa_xor(x,y) ({ ip_addr _a=(x), _b=(y); \
|
||||
_MI(_I0(_a) ^ _I0(_b), \
|
||||
_I1(_a) ^ _I1(_b), \
|
||||
_I2(_a) ^ _I2(_b), \
|
||||
_I3(_a) ^ _I3(_b)); })
|
||||
#define ipa_not(x) ({ ip_addr _a=(x); _MI(~_I0(_a),~_I1(_a),~_I2(_a),~_I3(_a)); })
|
||||
#define ipa_mkmask(x) ipv6_mkmask(x)
|
||||
#define ipa_mklen(x) ipv6_mklen(&(x))
|
||||
#define ipa_hash(x) ipv6_hash(&(x))
|
||||
#define ipa_hash32(x) ipv6_hash32(&(x))
|
||||
#define ipa_hton(x) ipv6_hton(&(x))
|
||||
#define ipa_ntoh(x) ipv6_ntoh(&(x))
|
||||
#define ipa_classify(x) ipv6_classify(&(x))
|
||||
#define ipa_has_link_scope(x) ipv6_has_link_scope(&(x))
|
||||
#define ipa_opposite_m1(x) ({ ip_addr _a=(x); _MI(_I0(_a),_I1(_a),_I2(_a),_I3(_a) ^ 1); })
|
||||
#define ipa_opposite_m2(x) ({ ip_addr _a=(x); _MI(_I0(_a),_I1(_a),_I2(_a),_I3(_a) ^ 3); })
|
||||
/* ipa_class_mask don't make sense with IPv6 */
|
||||
/* ipa_from_u32 and ipa_to_u32 replaced by ipa_build */
|
||||
#define ipa_build(a,b,c,d) _MI(a,b,c,d)
|
||||
#define ipa_compare(x,y) ipv6_compare(x,y)
|
||||
/* ipa_pxlen() requires that x != y */
|
||||
#define ipa_pxlen(x, y) ipv6_pxlen(x, y)
|
||||
#define ipa_getbit(x, y) ipv6_getbit(x, y)
|
||||
#define ipa_put_addr(x, y) ipv6_put_addr(x, y)
|
||||
#define ipa_absolutize(x,y) ipv6_absolutize(x,y)
|
||||
|
||||
/* In IPv6, SOCK_RAW does not return packet header */
|
||||
#define ip_skip_header(x, y) x
|
||||
|
||||
ip_addr ipv6_mkmask(unsigned);
|
||||
unsigned ipv6_mklen(ip_addr *);
|
||||
int ipv6_classify(ip_addr *);
|
||||
void ipv6_hton(ip_addr *);
|
||||
void ipv6_ntoh(ip_addr *);
|
||||
int ipv6_compare(ip_addr, ip_addr);
|
||||
int ipv4_pton_u32(char *, u32 *);
|
||||
void ipv6_absolutize(ip_addr *, ip_addr *);
|
||||
|
||||
static inline int ipv6_has_link_scope(ip_addr *a)
|
||||
{
|
||||
return ((a->addr[0] & 0xffc00000) == 0xfe800000);
|
||||
}
|
||||
|
||||
/*
|
||||
* This hash function looks well, but once IPv6 enters
|
||||
* mainstream use, we need to check that it has good
|
||||
* distribution properties on real routing tables.
|
||||
*/
|
||||
|
||||
static inline unsigned ipv6_hash(ip_addr *a)
|
||||
{
|
||||
/* Returns a 16-bit hash key */
|
||||
u32 x = _I0(*a) ^ _I1(*a) ^ _I2(*a) ^ _I3(*a);
|
||||
return (x ^ (x >> 16) ^ (x >> 8)) & 0xffff;
|
||||
}
|
||||
|
||||
static inline u32 ipv6_hash32(ip_addr *a)
|
||||
{
|
||||
/* Returns a 32-bit hash key, although low-order bits are not ixed */
|
||||
u32 x = _I0(*a) ^ _I1(*a) ^ _I2(*a) ^ _I3(*a);
|
||||
return x ^ (x << 16) ^ (x << 24);
|
||||
}
|
||||
|
||||
static inline u32 ipv6_getbit(ip_addr a, u32 y)
|
||||
{
|
||||
return a.addr[y / 32] & (0x80000000 >> (y % 32));
|
||||
}
|
||||
|
||||
static inline u32 ipv6_pxlen(ip_addr a, ip_addr b)
|
||||
{
|
||||
int i = 0;
|
||||
i+= (a.addr[i] == b.addr[i]);
|
||||
i+= (a.addr[i] == b.addr[i]);
|
||||
i+= (a.addr[i] == b.addr[i]);
|
||||
i+= (a.addr[i] == b.addr[i]);
|
||||
return 32 * i + 31 - u32_log2(a.addr[i] ^ b.addr[i]);
|
||||
}
|
||||
|
||||
static inline byte * ipv6_put_addr(byte *buf, ip_addr a)
|
||||
{
|
||||
put_u32(buf+0, _I0(a));
|
||||
put_u32(buf+4, _I1(a));
|
||||
put_u32(buf+8, _I2(a));
|
||||
put_u32(buf+12, _I3(a));
|
||||
return buf+16;
|
||||
}
|
||||
|
||||
#define IP_PREC_INTERNET_CONTROL 0xc0
|
||||
|
||||
#endif
|
@ -283,9 +283,9 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
|
||||
/* IP address */
|
||||
case 'I':
|
||||
if (flags & SPECIAL)
|
||||
ip_ntox(va_arg(args, ip_addr), ipbuf);
|
||||
ipa_ntox(va_arg(args, ip_addr), ipbuf);
|
||||
else {
|
||||
ip_ntop(va_arg(args, ip_addr), ipbuf);
|
||||
ipa_ntop(va_arg(args, ip_addr), ipbuf);
|
||||
if (field_width == 1)
|
||||
field_width = STD_ADDRESS_P_LENGTH;
|
||||
}
|
||||
|
@ -68,10 +68,12 @@ typedef struct siterator {
|
||||
#define SNODE (snode *)
|
||||
#define SHEAD(list) ((void *)((list).head))
|
||||
#define STAIL(list) ((void *)((list).tail))
|
||||
#define WALK_SLIST(n,list) for(n=SHEAD(list);(SNODE (n))->next; \
|
||||
n=(void *)((SNODE (n))->next))
|
||||
#define SNODE_NEXT(n) ((void *)((SNODE (n))->next))
|
||||
#define SNODE_VALID(n) ((SNODE (n))->next)
|
||||
|
||||
#define WALK_SLIST(n,list) for(n=SHEAD(list); SNODE_VALID(n); n=SNODE_NEXT(n))
|
||||
#define WALK_SLIST_DELSAFE(n,nxt,list) \
|
||||
for(n=SHEAD(list); nxt=(void *)((SNODE (n))->next); n=(void *) nxt)
|
||||
for(n=SHEAD(list); nxt=SNODE_NEXT(n); n=(void *) nxt)
|
||||
#define EMPTY_SLIST(list) (!(list).head->next)
|
||||
|
||||
void s_add_tail(slist *, snode *);
|
||||
|
@ -91,6 +91,8 @@ int sk_set_ipv6_checksum(sock *s, int offset);
|
||||
int sk_set_icmp6_filter(sock *s, int p1, int p2);
|
||||
void sk_log_error(sock *s, const char *p);
|
||||
|
||||
byte * sk_rx_buffer(sock *s, int *len); /* Temporary */
|
||||
|
||||
extern int sk_priority_control; /* Suggested priority for control traffic, should be sysdep define */
|
||||
|
||||
|
||||
|
31
nest/iface.c
31
nest/iface.c
@ -150,7 +150,7 @@ ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
|
||||
}
|
||||
|
||||
static void
|
||||
ifa_notify_change_dep(unsigned c, struct ifa *a)
|
||||
ifa_notify_change_(unsigned c, struct ifa *a)
|
||||
{
|
||||
struct proto *p;
|
||||
|
||||
@ -163,8 +163,13 @@ ifa_notify_change_dep(unsigned c, struct ifa *a)
|
||||
static inline void
|
||||
ifa_notify_change(unsigned c, struct ifa *a)
|
||||
{
|
||||
neigh_ifa_update(a);
|
||||
ifa_notify_change_dep(c, a);
|
||||
if (c & IF_CHANGE_DOWN)
|
||||
neigh_ifa_update(a);
|
||||
|
||||
ifa_notify_change_(c, a);
|
||||
|
||||
if (c & IF_CHANGE_UP)
|
||||
neigh_ifa_update(a);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -201,14 +206,14 @@ if_notify_change(unsigned c, struct iface *i)
|
||||
if_dump(i);
|
||||
#endif
|
||||
|
||||
if (c & IF_CHANGE_UP)
|
||||
neigh_if_up(i);
|
||||
if (c & IF_CHANGE_DOWN)
|
||||
neigh_if_down(i);
|
||||
|
||||
if (c & IF_CHANGE_DOWN)
|
||||
WALK_LIST(a, i->addrs)
|
||||
{
|
||||
a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
|
||||
ifa_notify_change_dep(IF_CHANGE_DOWN, a);
|
||||
ifa_notify_change_(IF_CHANGE_DOWN, a);
|
||||
}
|
||||
|
||||
WALK_LIST(p, active_proto_list)
|
||||
@ -218,14 +223,14 @@ if_notify_change(unsigned c, struct iface *i)
|
||||
WALK_LIST(a, i->addrs)
|
||||
{
|
||||
a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
|
||||
ifa_notify_change_dep(IF_CHANGE_UP, a);
|
||||
ifa_notify_change_(IF_CHANGE_UP, a);
|
||||
}
|
||||
|
||||
if (c & IF_CHANGE_UP)
|
||||
neigh_if_up(i);
|
||||
|
||||
if ((c & (IF_CHANGE_UP | IF_CHANGE_DOWN | IF_CHANGE_LINK)) == IF_CHANGE_LINK)
|
||||
neigh_if_link(i);
|
||||
|
||||
if (c & IF_CHANGE_DOWN)
|
||||
neigh_if_down(i);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
@ -251,8 +256,8 @@ if_change_flags(struct iface *i, unsigned flags)
|
||||
}
|
||||
|
||||
/**
|
||||
* if_delete - remove interface
|
||||
* @old: interface
|
||||
* if_delete - remove interface
|
||||
* @old: interface
|
||||
*
|
||||
* This function is called by the low-level platform dependent code
|
||||
* whenever it notices an interface disappears. It is just a shorthand
|
||||
@ -676,7 +681,7 @@ iface_patt_match(struct iface_patt *ifp, struct iface *i, struct ifa *a)
|
||||
if ((a->flags & IA_PEER) &&
|
||||
ipa_in_net(a->opposite, p->prefix, p->pxlen))
|
||||
return pos;
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
10
nest/locks.c
10
nest/locks.c
@ -22,10 +22,11 @@
|
||||
* or some other non-shareable resource, it asks the core to lock it and it doesn't
|
||||
* use the resource until it's notified that it has acquired the lock.
|
||||
*
|
||||
* Object locks are represented by &object_lock structures which are in turn a kind of
|
||||
* resource. Lockable resources are uniquely determined by resource type
|
||||
* Object locks are represented by &object_lock structures which are in turn a
|
||||
* kind of resource. Lockable resources are uniquely determined by resource type
|
||||
* (%OBJLOCK_UDP for a UDP port etc.), IP address (usually a broadcast or
|
||||
* multicast address the port is bound to), port number and interface.
|
||||
* multicast address the port is bound to), port number, interface and optional
|
||||
* instance ID.
|
||||
*/
|
||||
|
||||
#undef LOCAL_DEBUG
|
||||
@ -45,6 +46,7 @@ olock_same(struct object_lock *x, struct object_lock *y)
|
||||
x->type == y->type &&
|
||||
x->iface == y->iface &&
|
||||
x->port == y->port &&
|
||||
x->inst == y->inst &&
|
||||
ipa_equal(x->addr, y->addr);
|
||||
}
|
||||
|
||||
@ -88,7 +90,7 @@ olock_dump(resource *r)
|
||||
struct object_lock *l = (struct object_lock *) r;
|
||||
static char *olock_states[] = { "free", "locked", "waiting", "event" };
|
||||
|
||||
debug("(%d:%s:%I:%d) [%s]\n", l->type, (l->iface ? l->iface->name : "?"), l->addr, l->port, olock_states[l->state]);
|
||||
debug("(%d:%s:%I:%d:%d) [%s]\n", l->type, (l->iface ? l->iface->name : "?"), l->addr, l->port, l->inst, olock_states[l->state]);
|
||||
if (!EMPTY_LIST(l->waiters))
|
||||
debug(" [wanted]\n");
|
||||
}
|
||||
|
@ -26,9 +26,10 @@
|
||||
struct object_lock {
|
||||
resource r;
|
||||
ip_addr addr; /* Identification of a object: IP address */
|
||||
unsigned int type; /* ... object type (OBJLOCK_xxx) */
|
||||
uint type; /* ... object type (OBJLOCK_xxx) */
|
||||
uint port; /* ... port number */
|
||||
uint inst; /* ... instance ID */
|
||||
struct iface *iface; /* ... interface */
|
||||
unsigned int port; /* ... port number */
|
||||
void (*hook)(struct object_lock *); /* Called when the lock succeeds */
|
||||
void *data; /* User data */
|
||||
/* ... internal to lock manager, don't touch ... */
|
||||
|
@ -36,9 +36,18 @@ password_find(list *l, int first_fit)
|
||||
return pf;
|
||||
}
|
||||
|
||||
void password_cpy(char *dst, char *src, int size)
|
||||
struct password_item *
|
||||
password_find_by_id(list *l, int id)
|
||||
{
|
||||
bzero(dst, size);
|
||||
memcpy(dst, src, (strlen(src) < (unsigned) size ? strlen(src) : (unsigned) size));
|
||||
struct password_item *pi;
|
||||
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
WALK_LIST(pi, *l)
|
||||
if ((pi->id == id) && (pi->accfrom <= now_real) && (now_real < pi->accto))
|
||||
return pi;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,13 @@ struct password_item {
|
||||
extern struct password_item *last_password_item;
|
||||
|
||||
struct password_item *password_find(list *l, int first_fit);
|
||||
void password_cpy(char *dst, char *src, int size);
|
||||
struct password_item *password_find_by_id(list *l, int id);
|
||||
|
||||
static inline int password_verify(struct password_item *p1, char *p2, uint size)
|
||||
{
|
||||
char buf[size];
|
||||
strncpy(buf, p1->password, size);
|
||||
return !memcmp(buf, p2, size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -991,7 +991,7 @@ bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p
|
||||
if (p->cf->next_hop_self ||
|
||||
rta->dest != RTD_ROUTER ||
|
||||
ipa_equal(rta->gw, IPA_NONE) ||
|
||||
ipa_has_link_scope(rta->gw) ||
|
||||
ipa_is_link_local(rta->gw) ||
|
||||
(!p->is_internal && !p->cf->next_hop_keep &&
|
||||
(!p->neigh || (rta->iface != p->neigh->iface))))
|
||||
set_next_hop(z, p->source_addr);
|
||||
|
@ -689,7 +689,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
|
||||
s->password = p->cf->password;
|
||||
s->tx_hook = bgp_connected;
|
||||
BGP_TRACE(D_EVENTS, "Connecting to %I%J from local address %I%J", s->daddr, p->cf->iface,
|
||||
s->saddr, ipa_has_link_scope(s->saddr) ? s->iface : NULL);
|
||||
s->saddr, ipa_is_link_local(s->saddr) ? s->iface : NULL);
|
||||
bgp_setup_conn(p, conn);
|
||||
bgp_setup_sk(conn, s);
|
||||
bgp_conn_set_state(conn, BS_CONNECT);
|
||||
@ -735,7 +735,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
|
||||
{
|
||||
struct bgp_proto *p = (struct bgp_proto *) pc->proto;
|
||||
if (ipa_equal(p->cf->remote_ip, sk->daddr) &&
|
||||
(!ipa_has_link_scope(sk->daddr) || (p->cf->iface == sk->iface)))
|
||||
(!ipa_is_link_local(sk->daddr) || (p->cf->iface == sk->iface)))
|
||||
{
|
||||
/* We are in proper state and there is no other incoming connection */
|
||||
int acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) &&
|
||||
@ -750,7 +750,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
|
||||
}
|
||||
|
||||
BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s",
|
||||
sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL,
|
||||
sk->daddr, ipa_is_link_local(sk->daddr) ? sk->iface : NULL,
|
||||
sk->dport, acc ? "accepted" : "rejected");
|
||||
|
||||
if (!acc)
|
||||
@ -779,7 +779,7 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
|
||||
}
|
||||
|
||||
log(L_WARN "BGP: Unexpected connect from unknown address %I%J (port %d)",
|
||||
sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL, sk->dport);
|
||||
sk->daddr, ipa_is_link_local(sk->daddr) ? sk->iface : NULL, sk->dport);
|
||||
reject:
|
||||
rfree(sk);
|
||||
return 0;
|
||||
@ -1169,8 +1169,8 @@ bgp_check_config(struct bgp_config *c)
|
||||
if (c->multihop && (c->gw_mode == GW_DIRECT))
|
||||
cf_error("Multihop BGP cannot use direct gateway mode");
|
||||
|
||||
if (c->multihop && (ipa_has_link_scope(c->remote_ip) ||
|
||||
ipa_has_link_scope(c->source_addr)))
|
||||
if (c->multihop && (ipa_is_link_local(c->remote_ip) ||
|
||||
ipa_is_link_local(c->source_addr)))
|
||||
cf_error("Multihop BGP cannot be used with link-local addresses");
|
||||
|
||||
if (c->multihop && c->bfd && ipa_zero(c->source_addr))
|
||||
|
@ -63,7 +63,7 @@ bgp_proto:
|
||||
| bgp_proto NEIGHBOR ipa ipa_scope ipa_port AS expr ';' {
|
||||
if (ipa_nonzero(BGP_CFG->remote_ip))
|
||||
cf_error("Only one neighbor per BGP instance is allowed");
|
||||
if (!ipa_has_link_scope($3) != !$4)
|
||||
if (!ipa_is_link_local($3) != !$4)
|
||||
cf_error("Link-local address and interface scope must be used together");
|
||||
|
||||
BGP_CFG->remote_ip = $3;
|
||||
|
@ -69,8 +69,8 @@ mrt_put_bgp4_hdr(byte *buf, struct bgp_conn *conn, int as4)
|
||||
put_u16(buf+0, (p->neigh && p->neigh->iface) ? p->neigh->iface->index : 0);
|
||||
put_u16(buf+2, BGP_AF);
|
||||
buf+=4;
|
||||
buf = ipa_put_addr(buf, conn->sk ? conn->sk->daddr : IPA_NONE);
|
||||
buf = ipa_put_addr(buf, conn->sk ? conn->sk->saddr : IPA_NONE);
|
||||
buf = put_ipa(buf, conn->sk ? conn->sk->daddr : IPA_NONE);
|
||||
buf = put_ipa(buf, conn->sk ? conn->sk->saddr : IPA_NONE);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@ -522,7 +522,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
|
||||
*tmp++ = BGP_AF_IPV6;
|
||||
*tmp++ = 1;
|
||||
|
||||
if (ipa_has_link_scope(ip))
|
||||
if (ipa_is_link_local(ip))
|
||||
ip = IPA_NONE;
|
||||
|
||||
if (ipa_nonzero(ip_ll))
|
||||
@ -1034,7 +1034,7 @@ bgp_set_next_hop(struct bgp_proto *p, rta *a)
|
||||
int second = (nh->u.ptr->length == NEXT_HOP_LENGTH) && ipa_nonzero(nexthop[1]);
|
||||
|
||||
/* First address should not be link-local, but may be zero in direct mode */
|
||||
if (ipa_has_link_scope(*nexthop))
|
||||
if (ipa_is_link_local(*nexthop))
|
||||
*nexthop = IPA_NONE;
|
||||
#else
|
||||
int second = 0;
|
||||
|
@ -19,9 +19,11 @@ static struct ospf_area_config *this_area;
|
||||
static struct nbma_node *this_nbma;
|
||||
static list *this_nets;
|
||||
static struct area_net_config *this_pref;
|
||||
static struct ospf_stubnet_config *this_stubnet;
|
||||
static struct ospf_stubnet_config *this_stubnet;
|
||||
|
||||
static inline int ospf_cfg_is_v2(void) { return OSPF_CFG->ospf2; }
|
||||
static inline int ospf_cfg_is_v3(void) { return ! OSPF_CFG->ospf2; }
|
||||
|
||||
#ifdef OSPFv2
|
||||
static void
|
||||
ospf_iface_finish(void)
|
||||
{
|
||||
@ -30,6 +32,9 @@ ospf_iface_finish(void)
|
||||
if (ip->deadint == 0)
|
||||
ip->deadint = ip->deadc * ip->helloint;
|
||||
|
||||
if (ip->waitint == 0)
|
||||
ip->waitint = ip->deadc * ip->helloint;
|
||||
|
||||
ip->passwords = get_passwords();
|
||||
|
||||
if ((ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5))
|
||||
@ -38,21 +43,6 @@ ospf_iface_finish(void)
|
||||
if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL))
|
||||
log(L_WARN "Password option without authentication option does not make sense");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OSPFv3
|
||||
static void
|
||||
ospf_iface_finish(void)
|
||||
{
|
||||
struct ospf_iface_patt *ip = OSPF_PATT;
|
||||
|
||||
if (ip->deadint == 0)
|
||||
ip->deadint = ip->deadc * ip->helloint;
|
||||
|
||||
if ((ip->autype != OSPF_AUTH_NONE) || (get_passwords() != NULL))
|
||||
cf_error("Authentication not supported in OSPFv3");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ospf_area_finish(void)
|
||||
@ -61,12 +51,12 @@ ospf_area_finish(void)
|
||||
cf_error("Backbone area cannot be stub/NSSA");
|
||||
|
||||
if (this_area->summary && (this_area->type == OPT_E))
|
||||
cf_error("Only Stub/NSSA areas can use summary propagation");
|
||||
cf_error("Only stub/NSSA areas can use summary propagation");
|
||||
|
||||
if (this_area->default_nssa && ((this_area->type != OPT_N) || ! this_area->summary))
|
||||
cf_error("Only NSSA areas with summary propagation can use NSSA default route");
|
||||
|
||||
if ((this_area->default_cost & LSA_EXT_EBIT) && ! this_area->default_nssa)
|
||||
if ((this_area->default_cost & LSA_EXT3_EBIT) && ! this_area->default_nssa)
|
||||
cf_error("Only NSSA default route can use type 2 metric");
|
||||
}
|
||||
|
||||
@ -80,15 +70,22 @@ ospf_proto_finish(void)
|
||||
|
||||
int areano = 0;
|
||||
int backbone = 0;
|
||||
int nssa = 0;
|
||||
struct ospf_area_config *ac;
|
||||
WALK_LIST(ac, cf->area_list)
|
||||
{
|
||||
areano++;
|
||||
if (ac->areaid == 0)
|
||||
backbone = 1;
|
||||
backbone = 1;
|
||||
if (ac->type == OPT_N)
|
||||
nssa = 1;
|
||||
}
|
||||
|
||||
cf->abr = areano > 1;
|
||||
|
||||
/* Route export or NSSA translation (RFC 3101 3.1) */
|
||||
cf->asbr = (this_proto->out_filter != FILTER_REJECT) || (nssa && cf->abr);
|
||||
|
||||
if (cf->abr && !backbone)
|
||||
{
|
||||
struct ospf_area_config *ac = cfg_allocz(sizeof(struct ospf_area_config));
|
||||
@ -101,26 +98,27 @@ ospf_proto_finish(void)
|
||||
}
|
||||
|
||||
if (!cf->abr && !EMPTY_LIST(cf->vlink_list))
|
||||
cf_error( "Vlinks cannot be used on single area router");
|
||||
cf_error("Vlinks cannot be used on single area router");
|
||||
|
||||
if (cf->asbr && (areano == 1) && (this_area->type == 0))
|
||||
cf_error("ASBR must be in non-stub area");
|
||||
}
|
||||
|
||||
static inline void
|
||||
check_defcost(int cost)
|
||||
ospf_check_defcost(int cost)
|
||||
{
|
||||
if ((cost <= 0) || (cost >= LSINFINITY))
|
||||
cf_error("Default cost must be in range 1-%d", LSINFINITY-1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_instance_id(unsigned id)
|
||||
ospf_check_auth(void)
|
||||
{
|
||||
#ifdef OSPFv3
|
||||
OSPF_PATT->instance_id = id;
|
||||
#else
|
||||
cf_error("Instance ID requires OSPFv3");
|
||||
#endif
|
||||
if (ospf_cfg_is_v3())
|
||||
cf_error("Authentication not supported in OSPFv3");
|
||||
}
|
||||
|
||||
|
||||
CF_DECLS
|
||||
|
||||
CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
|
||||
@ -132,7 +130,7 @@ CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD)
|
||||
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
|
||||
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
|
||||
CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH)
|
||||
CF_KEYWORDS(SECONDARY, MERGE)
|
||||
CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION)
|
||||
|
||||
%type <t> opttext
|
||||
%type <ld> lsadb_args
|
||||
@ -146,8 +144,8 @@ ospf_proto_start: proto_start OSPF {
|
||||
this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config), $1);
|
||||
init_list(&OSPF_CFG->area_list);
|
||||
init_list(&OSPF_CFG->vlink_list);
|
||||
OSPF_CFG->rfc1583 = DEFAULT_RFC1583;
|
||||
OSPF_CFG->tick = DEFAULT_OSPFTICK;
|
||||
OSPF_CFG->tick = OSPF_DEFAULT_TICK;
|
||||
OSPF_CFG->ospf2 = OSPF_IS_V2;
|
||||
}
|
||||
;
|
||||
|
||||
@ -160,10 +158,11 @@ ospf_proto_item:
|
||||
proto_item
|
||||
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
|
||||
| STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
|
||||
| ECMP bool { OSPF_CFG->ecmp = $2 ? DEFAULT_ECMP_LIMIT : 0; }
|
||||
| ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
|
||||
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); }
|
||||
| MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; }
|
||||
| TICK expr { OSPF_CFG->tick = $2; if($2<=0) cf_error("Tick must be greater than zero"); }
|
||||
| INSTANCE ID expr { OSPF_CFG->instance_id = $3; if (($3<0) || ($3>255)) cf_error("Instance ID must be in range 0-255"); }
|
||||
| ospf_area
|
||||
;
|
||||
|
||||
@ -171,9 +170,9 @@ ospf_area_start: AREA idval {
|
||||
this_area = cfg_allocz(sizeof(struct ospf_area_config));
|
||||
add_tail(&OSPF_CFG->area_list, NODE this_area);
|
||||
this_area->areaid = $2;
|
||||
this_area->default_cost = DEFAULT_STUB_COST;
|
||||
this_area->default_cost = OSPF_DEFAULT_STUB_COST;
|
||||
this_area->type = OPT_E;
|
||||
this_area->transint = DEFAULT_TRANSINT;
|
||||
this_area->transint = OSPF_DEFAULT_TRANSINT;
|
||||
|
||||
init_list(&this_area->patt_list);
|
||||
init_list(&this_area->net_list);
|
||||
@ -195,9 +194,9 @@ ospf_area_item:
|
||||
| NSSA { this_area->type = OPT_N; }
|
||||
| SUMMARY bool { this_area->summary = $2; }
|
||||
| DEFAULT NSSA bool { this_area->default_nssa = $3; }
|
||||
| DEFAULT COST expr { this_area->default_cost = $3; check_defcost($3); }
|
||||
| DEFAULT COST2 expr { this_area->default_cost = $3 | LSA_EXT_EBIT; check_defcost($3); }
|
||||
| STUB COST expr { this_area->default_cost = $3; check_defcost($3); }
|
||||
| DEFAULT COST expr { this_area->default_cost = $3; ospf_check_defcost($3); }
|
||||
| DEFAULT COST2 expr { this_area->default_cost = $3 | LSA_EXT3_EBIT; ospf_check_defcost($3); }
|
||||
| STUB COST expr { this_area->default_cost = $3; ospf_check_defcost($3); }
|
||||
| TRANSLATOR bool { this_area->translator = $2; }
|
||||
| TRANSLATOR STABILITY expr { this_area->transint = $3; }
|
||||
| NETWORKS { this_nets = &this_area->net_list; } '{' pref_list '}'
|
||||
@ -218,7 +217,7 @@ ospf_stubnet_start:
|
||||
add_tail(&this_area->stubnet_list, NODE this_stubnet);
|
||||
this_stubnet->px = $1;
|
||||
this_stubnet->cost = COST_D;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
ospf_stubnet_opts:
|
||||
@ -244,15 +243,15 @@ ospf_vlink_opts:
|
||||
|
||||
ospf_vlink_item:
|
||||
| HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); }
|
||||
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=0) cf_error("Retransmit int must be greater than zero"); }
|
||||
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error("Retransmit int must be greater than one"); }
|
||||
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
|
||||
| WAIT expr { OSPF_PATT->waitint = $2 ; }
|
||||
| WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error("Wait interval must be greater than one"); }
|
||||
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
|
||||
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
|
||||
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
|
||||
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
|
||||
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; }
|
||||
| password_list
|
||||
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
|
||||
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
|
||||
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
|
||||
| password_list { ospf_check_auth(); }
|
||||
;
|
||||
|
||||
ospf_vlink_start: VIRTUAL LINK idval
|
||||
@ -266,12 +265,10 @@ ospf_vlink_start: VIRTUAL LINK idval
|
||||
OSPF_PATT->helloint = HELLOINT_D;
|
||||
OSPF_PATT->rxmtint = RXMTINT_D;
|
||||
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
|
||||
OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D;
|
||||
OSPF_PATT->deadc = DEADC_D;
|
||||
OSPF_PATT->deadint = 0;
|
||||
OSPF_PATT->type = OSPF_IT_VLINK;
|
||||
OSPF_PATT->instance_id = OSPF_CFG->instance_id;
|
||||
init_list(&OSPF_PATT->nbma_list);
|
||||
OSPF_PATT->autype = OSPF_AUTH_NONE;
|
||||
reset_passwords();
|
||||
}
|
||||
;
|
||||
@ -280,8 +277,8 @@ ospf_iface_item:
|
||||
COST expr { OSPF_PATT->cost = $2 ; if (($2<=0) || ($2>65535)) cf_error("Cost must be in range 1-65535"); }
|
||||
| HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); }
|
||||
| POLL expr { OSPF_PATT->pollint = $2 ; if ($2<=0) cf_error("Poll int must be greater than zero"); }
|
||||
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=0) cf_error("Retransmit int must be greater than zero"); }
|
||||
| WAIT expr { OSPF_PATT->waitint = $2 ; }
|
||||
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error("Retransmit int must be greater than one"); }
|
||||
| WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error("Wait interval must be greater than one"); }
|
||||
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
|
||||
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
|
||||
| TYPE BROADCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
|
||||
@ -292,20 +289,21 @@ ospf_iface_item:
|
||||
| TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; }
|
||||
| TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; }
|
||||
| TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; }
|
||||
| REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (OSPF_VERSION != 2) cf_error("Real broadcast option requires OSPFv2"); }
|
||||
| PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (OSPF_VERSION != 2) cf_error("Real netmask option requires OSPFv2"); }
|
||||
| REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (!ospf_cfg_is_v2()) cf_error("Real broadcast option requires OSPFv2"); }
|
||||
| PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (!ospf_cfg_is_v2()) cf_error("PtP netmask option requires OSPFv2"); }
|
||||
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
|
||||
| PRIORITY expr { OSPF_PATT->priority = $2 ; if (($2<0) || ($2>255)) cf_error("Priority must be in range 0-255"); }
|
||||
| STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
|
||||
| STUB bool { OSPF_PATT->stub = $2 ; }
|
||||
| CHECK LINK bool { OSPF_PATT->check_link = $3; }
|
||||
| ECMP WEIGHT expr { OSPF_PATT->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
|
||||
| LINK LSA SUPPRESSION bool { OSPF_PATT->link_lsa_suppression = $4; if (!ospf_cfg_is_v3()) cf_error("Link LSA suppression option requires OSPFv3"); }
|
||||
| NEIGHBORS '{' nbma_list '}'
|
||||
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
|
||||
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
|
||||
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; }
|
||||
| RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; }
|
||||
| RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; }
|
||||
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
|
||||
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
|
||||
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
|
||||
| RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; }
|
||||
| RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; }
|
||||
| RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); }
|
||||
| TX tos { OSPF_PATT->tx_tos = $2; }
|
||||
| TX PRIORITY expr { OSPF_PATT->tx_priority = $3; }
|
||||
@ -314,7 +312,7 @@ ospf_iface_item:
|
||||
| TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
|
||||
| BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); }
|
||||
| SECONDARY bool { OSPF_PATT->bsd_secondary = $2; }
|
||||
| password_list
|
||||
| password_list { ospf_check_auth(); }
|
||||
;
|
||||
|
||||
pref_list:
|
||||
@ -348,8 +346,8 @@ nbma_eligible:
|
||||
/* empty */ { $$ = 0; }
|
||||
| ELIGIBLE { $$ = 1; }
|
||||
;
|
||||
|
||||
nbma_item: IPA nbma_eligible ';'
|
||||
|
||||
nbma_item: ipa nbma_eligible ';'
|
||||
{
|
||||
this_nbma = cfg_allocz(sizeof(struct nbma_node));
|
||||
add_tail(&OSPF_PATT->nbma_list, NODE this_nbma);
|
||||
@ -357,7 +355,7 @@ nbma_item: IPA nbma_eligible ';'
|
||||
this_nbma->eligible=$2;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
ospf_iface_start:
|
||||
{
|
||||
this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt));
|
||||
@ -369,12 +367,10 @@ ospf_iface_start:
|
||||
OSPF_PATT->rxmtint = RXMTINT_D;
|
||||
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
|
||||
OSPF_PATT->priority = PRIORITY_D;
|
||||
OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D;
|
||||
OSPF_PATT->deadc = DEADC_D;
|
||||
OSPF_PATT->deadint = 0;
|
||||
OSPF_PATT->type = OSPF_IT_UNDEF;
|
||||
OSPF_PATT->instance_id = OSPF_CFG->instance_id;
|
||||
init_list(&OSPF_PATT->nbma_list);
|
||||
OSPF_PATT->autype = OSPF_AUTH_NONE;
|
||||
OSPF_PATT->ptp_netmask = 2; /* not specified */
|
||||
OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL;
|
||||
OSPF_PATT->tx_priority = sk_priority_control;
|
||||
@ -384,12 +380,12 @@ ospf_iface_start:
|
||||
|
||||
ospf_instance_id:
|
||||
/* empty */
|
||||
| INSTANCE expr { set_instance_id($2); }
|
||||
| INSTANCE expr { OSPF_PATT->instance_id = $2; if (($2<0) || ($2>255)) cf_error("Instance ID must be in range 0-255"); }
|
||||
;
|
||||
|
||||
ospf_iface_patt_list:
|
||||
iface_patt_list { if (OSPF_VERSION == 3) iface_patt_check(); } ospf_instance_id
|
||||
;
|
||||
iface_patt_list { if (ospf_cfg_is_v3()) iface_patt_check(); } ospf_instance_id
|
||||
;
|
||||
|
||||
ospf_iface_opts:
|
||||
/* empty */
|
||||
|
@ -2,6 +2,8 @@
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 1999--2004 Ondrej Filip <feela@network.cz>
|
||||
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2009--2014 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
@ -9,64 +11,188 @@
|
||||
#include "ospf.h"
|
||||
|
||||
|
||||
#ifdef OSPFv2
|
||||
struct ospf_dbdes_packet
|
||||
struct ospf_dbdes2_packet
|
||||
{
|
||||
struct ospf_packet ospf_packet;
|
||||
struct ospf_packet hdr;
|
||||
union ospf_auth auth;
|
||||
|
||||
u16 iface_mtu;
|
||||
u8 options;
|
||||
union imms imms; /* I, M, MS bits */
|
||||
u8 imms; /* I, M, MS bits */
|
||||
u32 ddseq;
|
||||
|
||||
struct ospf_lsa_header lsas[];
|
||||
};
|
||||
|
||||
#define hton_opt(X) X
|
||||
#define ntoh_opt(X) X
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef OSPFv3
|
||||
struct ospf_dbdes_packet
|
||||
struct ospf_dbdes3_packet
|
||||
{
|
||||
struct ospf_packet ospf_packet;
|
||||
struct ospf_packet hdr;
|
||||
|
||||
u32 options;
|
||||
u16 iface_mtu;
|
||||
u8 padding;
|
||||
union imms imms; /* I, M, MS bits */
|
||||
u8 imms; /* I, M, MS bits */
|
||||
u32 ddseq;
|
||||
|
||||
struct ospf_lsa_header lsas[];
|
||||
};
|
||||
|
||||
#define hton_opt(X) htonl(X)
|
||||
#define ntoh_opt(X) ntohl(X)
|
||||
#endif
|
||||
|
||||
|
||||
static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
|
||||
static inline uint
|
||||
ospf_dbdes_hdrlen(struct ospf_proto *p)
|
||||
{
|
||||
struct ospf_packet *op = &pkt->ospf_packet;
|
||||
|
||||
ASSERT(op->type == DBDES_P);
|
||||
ospf_dump_common(p, op);
|
||||
log(L_TRACE "%s: imms %s%s%s",
|
||||
p->name, pkt->imms.bit.ms ? "MS " : "",
|
||||
pkt->imms.bit.m ? "M " : "",
|
||||
pkt->imms.bit.i ? "I " : "" );
|
||||
log(L_TRACE "%s: ddseq %u", p->name, ntohl(pkt->ddseq));
|
||||
|
||||
struct ospf_lsa_header *plsa = (void *) (pkt + 1);
|
||||
unsigned int i, j;
|
||||
|
||||
j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
|
||||
sizeof(struct ospf_lsa_header);
|
||||
|
||||
for (i = 0; i < j; i++)
|
||||
ospf_dump_lsahdr(p, plsa + i);
|
||||
return ospf_is_v2(p) ?
|
||||
sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ospf_dbdes_body(struct ospf_proto *p, struct ospf_packet *pkt,
|
||||
struct ospf_lsa_header **body, uint *count)
|
||||
{
|
||||
uint plen = ntohs(pkt->length);
|
||||
uint hlen = ospf_dbdes_hdrlen(p);
|
||||
|
||||
*body = ((void *) pkt) + hlen;
|
||||
*count = (plen - hlen) / sizeof(struct ospf_lsa_header);
|
||||
}
|
||||
|
||||
static void
|
||||
ospf_dump_dbdes(struct ospf_proto *p, struct ospf_packet *pkt)
|
||||
{
|
||||
struct ospf_lsa_header *lsas;
|
||||
uint i, lsa_count;
|
||||
u32 pkt_ddseq;
|
||||
u16 pkt_iface_mtu;
|
||||
u8 pkt_imms;
|
||||
|
||||
ASSERT(pkt->type == DBDES_P);
|
||||
ospf_dump_common(p, pkt);
|
||||
|
||||
if (ospf_is_v2(p))
|
||||
{
|
||||
struct ospf_dbdes2_packet *ps = (void *) pkt;
|
||||
pkt_iface_mtu = ntohs(ps->iface_mtu);
|
||||
pkt_imms = ps->imms;
|
||||
pkt_ddseq = ntohl(ps->ddseq);
|
||||
}
|
||||
else /* OSPFv3 */
|
||||
{
|
||||
struct ospf_dbdes3_packet *ps = (void *) pkt;
|
||||
pkt_iface_mtu = ntohs(ps->iface_mtu);
|
||||
pkt_imms = ps->imms;
|
||||
pkt_ddseq = ntohl(ps->ddseq);
|
||||
}
|
||||
|
||||
log(L_TRACE "%s: mtu %u", p->p.name, pkt_iface_mtu);
|
||||
log(L_TRACE "%s: imms %s%s%s", p->p.name,
|
||||
(pkt_imms & DBDES_I) ? "I " : "",
|
||||
(pkt_imms & DBDES_M) ? "M " : "",
|
||||
(pkt_imms & DBDES_MS) ? "MS" : "");
|
||||
log(L_TRACE "%s: ddseq %u", p->p.name, pkt_ddseq);
|
||||
|
||||
ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
|
||||
for (i = 0; i < lsa_count; i++)
|
||||
ospf_dump_lsahdr(p, lsas + i);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
|
||||
{
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
struct ospf_packet *pkt;
|
||||
uint length;
|
||||
|
||||
u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu;
|
||||
|
||||
/* Update DBDES buffer */
|
||||
if (n->ldd_bsize != ifa->tx_length)
|
||||
{
|
||||
mb_free(n->ldd_buffer);
|
||||
n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
|
||||
n->ldd_bsize = ifa->tx_length;
|
||||
}
|
||||
|
||||
pkt = n->ldd_buffer;
|
||||
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
|
||||
|
||||
if (ospf_is_v2(p))
|
||||
{
|
||||
struct ospf_dbdes2_packet *ps = (void *) pkt;
|
||||
ps->iface_mtu = htons(iface_mtu);
|
||||
ps->options = ifa->oa->options;
|
||||
ps->imms = 0; /* Will be set later */
|
||||
ps->ddseq = htonl(n->dds);
|
||||
length = sizeof(struct ospf_dbdes2_packet);
|
||||
}
|
||||
else /* OSPFv3 */
|
||||
{
|
||||
struct ospf_dbdes3_packet *ps = (void *) pkt;
|
||||
ps->options = htonl(ifa->oa->options);
|
||||
ps->iface_mtu = htons(iface_mtu);
|
||||
ps->padding = 0;
|
||||
ps->imms = 0; /* Will be set later */
|
||||
ps->ddseq = htonl(n->dds);
|
||||
length = sizeof(struct ospf_dbdes3_packet);
|
||||
}
|
||||
|
||||
/* Prepare DBDES body */
|
||||
if (!(n->myimms & DBDES_I) && (n->myimms & DBDES_M))
|
||||
{
|
||||
struct ospf_lsa_header *lsas;
|
||||
struct top_hash_entry *en;
|
||||
uint i = 0, lsa_max;
|
||||
|
||||
ospf_dbdes_body(p, pkt, &lsas, &lsa_max);
|
||||
en = (void *) s_get(&(n->dbsi));
|
||||
|
||||
while (i < lsa_max)
|
||||
{
|
||||
if (!SNODE_VALID(en))
|
||||
{
|
||||
n->myimms &= ~DBDES_M; /* Unset More bit */
|
||||
break;
|
||||
}
|
||||
|
||||
if ((en->lsa.age < LSA_MAXAGE) &&
|
||||
lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
|
||||
{
|
||||
lsa_hton_hdr(&(en->lsa), lsas + i);
|
||||
i++;
|
||||
}
|
||||
|
||||
en = SNODE_NEXT(en);
|
||||
}
|
||||
|
||||
s_put(&(n->dbsi), SNODE en);
|
||||
|
||||
length += i * sizeof(struct ospf_lsa_header);
|
||||
}
|
||||
|
||||
if (ospf_is_v2(p))
|
||||
((struct ospf_dbdes2_packet *) pkt)->imms = n->myimms;
|
||||
else
|
||||
((struct ospf_dbdes3_packet *) pkt)->imms = n->myimms;
|
||||
|
||||
pkt->length = htons(length);
|
||||
}
|
||||
|
||||
static void
|
||||
ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
|
||||
{
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
|
||||
OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer,
|
||||
"DBDES packet sent to nbr %R on %s", n->rid, ifa->ifname);
|
||||
sk_set_tbuf(ifa->sk, n->ldd_buffer);
|
||||
ospf_send_to(ifa, n->ip);
|
||||
sk_set_tbuf(ifa->sk, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* ospf_dbdes_send - transmit database description packet
|
||||
* ospf_send_dbdes - transmit database description packet
|
||||
* @n: neighbor
|
||||
* @next: whether to send a next packet in a sequence (1) or to retransmit the old one (0)
|
||||
*
|
||||
* Sending of a database description packet is described in 10.8 of RFC 2328.
|
||||
* Reception of each packet is acknowledged in the sequence number of another.
|
||||
@ -75,356 +201,280 @@ static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
|
||||
* of the buffer.
|
||||
*/
|
||||
void
|
||||
ospf_dbdes_send(struct ospf_neighbor *n, int next)
|
||||
ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
|
||||
{
|
||||
struct ospf_dbdes_packet *pkt;
|
||||
struct ospf_packet *op;
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
struct ospf_area *oa = ifa->oa;
|
||||
struct proto_ospf *po = oa->po;
|
||||
struct proto *p = &po->proto;
|
||||
u16 length, i, j;
|
||||
/* RFC 2328 10.8 */
|
||||
|
||||
/* FIXME ??? */
|
||||
if ((oa->rt == NULL) || (EMPTY_LIST(po->lsal)))
|
||||
update_rt_lsa(oa);
|
||||
ASSERT((n->state == NEIGHBOR_EXSTART) || (n->state == NEIGHBOR_EXCHANGE));
|
||||
|
||||
switch (n->state)
|
||||
{
|
||||
case NEIGHBOR_EXSTART: /* Send empty packets */
|
||||
n->myimms.bit.i = 1;
|
||||
pkt = ospf_tx_buffer(ifa);
|
||||
op = &pkt->ospf_packet;
|
||||
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
|
||||
pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu);
|
||||
pkt->options = hton_opt(oa->options);
|
||||
pkt->imms = n->myimms;
|
||||
pkt->ddseq = htonl(n->dds);
|
||||
length = sizeof(struct ospf_dbdes_packet);
|
||||
op->length = htons(length);
|
||||
if (n->ifa->oa->rt == NULL)
|
||||
return;
|
||||
|
||||
OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->ifname);
|
||||
ospf_send_to(ifa, n->ip);
|
||||
break;
|
||||
|
||||
case NEIGHBOR_EXCHANGE:
|
||||
n->myimms.bit.i = 0;
|
||||
|
||||
if (next)
|
||||
{
|
||||
snode *sn;
|
||||
struct ospf_lsa_header *lsa;
|
||||
|
||||
if (n->ldd_bsize != ifa->tx_length)
|
||||
{
|
||||
mb_free(n->ldd_buffer);
|
||||
n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
|
||||
n->ldd_bsize = ifa->tx_length;
|
||||
}
|
||||
|
||||
pkt = n->ldd_buffer;
|
||||
op = (struct ospf_packet *) pkt;
|
||||
|
||||
ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
|
||||
pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu);
|
||||
pkt->ddseq = htonl(n->dds);
|
||||
pkt->options = hton_opt(oa->options);
|
||||
|
||||
j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header); /* Number of possible lsaheaders to send */
|
||||
lsa = (n->ldd_buffer + sizeof(struct ospf_dbdes_packet));
|
||||
|
||||
if (n->myimms.bit.m)
|
||||
{
|
||||
sn = s_get(&(n->dbsi));
|
||||
|
||||
DBG("Number of LSA: %d\n", j);
|
||||
for (; i > 0; i--)
|
||||
{
|
||||
struct top_hash_entry *en= (struct top_hash_entry *) sn;
|
||||
|
||||
if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa))
|
||||
{
|
||||
htonlsah(&(en->lsa), lsa);
|
||||
DBG("Working on: %d\n", i);
|
||||
DBG("\tX%01x %-1R %-1R %p\n", en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa_body);
|
||||
|
||||
lsa++;
|
||||
}
|
||||
else i++; /* No lsa added */
|
||||
|
||||
if (sn == STAIL(po->lsal))
|
||||
{
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
|
||||
sn = sn->next;
|
||||
}
|
||||
|
||||
if (sn == STAIL(po->lsal))
|
||||
{
|
||||
DBG("Number of LSA NOT sent: %d\n", i);
|
||||
DBG("M bit unset.\n");
|
||||
n->myimms.bit.m = 0; /* Unset more bit */
|
||||
}
|
||||
|
||||
s_put(&(n->dbsi), sn);
|
||||
}
|
||||
|
||||
pkt->imms.byte = n->myimms.byte;
|
||||
|
||||
length = (j - i) * sizeof(struct ospf_lsa_header) +
|
||||
sizeof(struct ospf_dbdes_packet);
|
||||
op->length = htons(length);
|
||||
|
||||
DBG("%s: DB_DES (M) prepared for %I.\n", p->name, n->ip);
|
||||
}
|
||||
|
||||
case NEIGHBOR_LOADING:
|
||||
case NEIGHBOR_FULL:
|
||||
length = n->ldd_buffer ? ntohs(((struct ospf_packet *) n->ldd_buffer)->length) : 0;
|
||||
|
||||
if (!length)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "No packet in my buffer for repeating");
|
||||
ospf_neigh_sm(n, INM_KILLNBR);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send last packet from ldd buffer */
|
||||
|
||||
OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer, "DBDES packet sent to %I via %s", n->ip, ifa->ifname);
|
||||
|
||||
sk_set_tbuf(ifa->sk, n->ldd_buffer);
|
||||
ospf_send_to(ifa, n->ip);
|
||||
sk_set_tbuf(ifa->sk, NULL);
|
||||
|
||||
if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */
|
||||
|
||||
if (!n->myimms.bit.ms)
|
||||
{
|
||||
if ((n->myimms.bit.m == 0) && (n->imms.bit.m == 0) &&
|
||||
(n->state == NEIGHBOR_EXCHANGE))
|
||||
{
|
||||
ospf_neigh_sm(n, INM_EXDONE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* Ignore it */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n)
|
||||
{
|
||||
struct ospf_lsa_header *plsa, lsa;
|
||||
struct top_hash_entry *he, *sn;
|
||||
struct ospf_area *oa = n->ifa->oa;
|
||||
struct top_graph *gr = oa->po->gr;
|
||||
struct ospf_packet *op;
|
||||
int i, j;
|
||||
|
||||
op = (struct ospf_packet *) ps;
|
||||
|
||||
plsa = (void *) (ps + 1);
|
||||
|
||||
j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
|
||||
sizeof(struct ospf_lsa_header);
|
||||
|
||||
for (i = 0; i < j; i++)
|
||||
{
|
||||
ntohlsah(plsa + i, &lsa);
|
||||
u32 dom = ospf_lsa_domain(lsa.type, n->ifa);
|
||||
if (((he = ospf_hash_find_header(gr, dom, &lsa)) == NULL) ||
|
||||
(lsa_comp(&lsa, &(he->lsa)) == 1))
|
||||
{
|
||||
/* Is this condition necessary? */
|
||||
if (ospf_hash_find_header(n->lsrqh, dom, &lsa) == NULL)
|
||||
{
|
||||
sn = ospf_hash_get_header(n->lsrqh, dom, &lsa);
|
||||
ntohlsah(plsa + i, &(sn->lsa));
|
||||
s_add_tail(&(n->lsrql), SNODE sn);
|
||||
}
|
||||
}
|
||||
}
|
||||
ospf_prepare_dbdes(p, n);
|
||||
ospf_do_send_dbdes(p, n);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
||||
struct ospf_neighbor *n)
|
||||
ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
|
||||
{
|
||||
struct proto_ospf *po = ifa->oa->po;
|
||||
struct proto *p = &po->proto;
|
||||
ASSERT(n->state > NEIGHBOR_EXSTART);
|
||||
|
||||
unsigned int size = ntohs(ps_i->length);
|
||||
if (size < sizeof(struct ospf_dbdes_packet))
|
||||
if (!n->ldd_buffer)
|
||||
{
|
||||
log(L_ERR "Bad OSPF DBDES packet from %I - too short (%u B)", n->ip, size);
|
||||
log(L_WARN "%s: No DBDES packet for retransmit", p->p.name);
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
return;
|
||||
}
|
||||
|
||||
struct ospf_dbdes_packet *ps = (void *) ps_i;
|
||||
u32 ps_ddseq = ntohl(ps->ddseq);
|
||||
u32 ps_options = ntoh_opt(ps->options);
|
||||
u16 ps_iface_mtu = ntohs(ps->iface_mtu);
|
||||
|
||||
OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->ifname);
|
||||
/* Send last packet */
|
||||
ospf_do_send_dbdes(p, n);
|
||||
}
|
||||
|
||||
static int
|
||||
ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n)
|
||||
{
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
struct ospf_lsa_header *lsas, lsa;
|
||||
struct top_hash_entry *en, *req;
|
||||
const char *err_dsc = NULL;
|
||||
u32 lsa_type, lsa_domain;
|
||||
uint i, lsa_count;
|
||||
|
||||
ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
|
||||
|
||||
for (i = 0; i < lsa_count; i++)
|
||||
{
|
||||
lsa_ntoh_hdr(lsas + i, &lsa);
|
||||
lsa_get_type_domain(&lsa, ifa, &lsa_type, &lsa_domain);
|
||||
|
||||
/* RFC 2328 10.6 and RFC 5340 4.2.2 */
|
||||
|
||||
if (!lsa_type)
|
||||
DROP1("LSA of unknown type");
|
||||
|
||||
if (!oa_is_ext(ifa->oa) && (LSA_SCOPE(lsa_type) == LSA_SCOPE_AS))
|
||||
DROP1("LSA with AS scope in stub area");
|
||||
|
||||
/* Errata 3746 to RFC 2328 - rt-summary-LSAs forbidden in stub areas */
|
||||
if (!oa_is_ext(ifa->oa) && (lsa_type == LSA_T_SUM_RT))
|
||||
DROP1("rt-summary-LSA in stub area");
|
||||
|
||||
/* Not explicitly mentioned in RFC 5340 4.2.2 but makes sense */
|
||||
if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)
|
||||
DROP1("LSA with invalid scope");
|
||||
|
||||
en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
|
||||
if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER))
|
||||
{
|
||||
/* This should be splitted to ospf_lsa_lsrq_up() */
|
||||
req = ospf_hash_get(n->lsrqh, lsa_domain, lsa.id, lsa.rt, lsa_type);
|
||||
|
||||
if (!SNODE_VALID(req))
|
||||
s_add_tail(&n->lsrql, SNODE req);
|
||||
|
||||
if (!SNODE_VALID(n->lsrqi))
|
||||
n->lsrqi = req;
|
||||
|
||||
req->lsa = lsa;
|
||||
req->lsa_body = LSA_BODY_DUMMY;
|
||||
|
||||
if (!tm_active(n->lsrq_timer))
|
||||
tm_start(n->lsrq_timer, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
drop:
|
||||
LOG_LSA1("Bad LSA (Type: %04x, Id: %R, Rt: %R) in DBDES", lsa_type, lsa.id, lsa.rt);
|
||||
LOG_LSA2(" received from nbr %R on %s - %s", n->rid, ifa->ifname, err_dsc);
|
||||
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
struct ospf_neighbor *n)
|
||||
{
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
const char *err_dsc = NULL;
|
||||
u32 rcv_ddseq, rcv_options;
|
||||
u16 rcv_iface_mtu;
|
||||
u8 rcv_imms;
|
||||
uint plen, err_val = 0;
|
||||
|
||||
/* RFC 2328 10.6 */
|
||||
|
||||
plen = ntohs(pkt->length);
|
||||
if (plen < ospf_dbdes_hdrlen(p))
|
||||
{
|
||||
LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", plen);
|
||||
return;
|
||||
}
|
||||
|
||||
OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet received from nbr %R on %s", n->rid, ifa->ifname);
|
||||
|
||||
ospf_neigh_sm(n, INM_HELLOREC);
|
||||
|
||||
if (ospf_is_v2(p))
|
||||
{
|
||||
struct ospf_dbdes2_packet *ps = (void *) pkt;
|
||||
rcv_iface_mtu = ntohs(ps->iface_mtu);
|
||||
rcv_options = ps->options;
|
||||
rcv_imms = ps->imms;
|
||||
rcv_ddseq = ntohl(ps->ddseq);
|
||||
}
|
||||
else /* OSPFv3 */
|
||||
{
|
||||
struct ospf_dbdes3_packet *ps = (void *) pkt;
|
||||
rcv_options = ntohl(ps->options);
|
||||
rcv_iface_mtu = ntohs(ps->iface_mtu);
|
||||
rcv_imms = ps->imms;
|
||||
rcv_ddseq = ntohl(ps->ddseq);
|
||||
}
|
||||
|
||||
switch (n->state)
|
||||
{
|
||||
case NEIGHBOR_DOWN:
|
||||
case NEIGHBOR_ATTEMPT:
|
||||
case NEIGHBOR_2WAY:
|
||||
OSPF_TRACE(D_PACKETS, "DBDES packet ignored - lesser state than ExStart");
|
||||
return;
|
||||
break;
|
||||
|
||||
case NEIGHBOR_INIT:
|
||||
ospf_neigh_sm(n, INM_2WAYREC);
|
||||
if (n->state != NEIGHBOR_EXSTART)
|
||||
return;
|
||||
|
||||
case NEIGHBOR_EXSTART:
|
||||
if ((ifa->type != OSPF_IT_VLINK) &&
|
||||
(rcv_iface_mtu != ifa->iface->mtu) &&
|
||||
(rcv_iface_mtu != 0) &&
|
||||
(ifa->iface->mtu != 0))
|
||||
LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)",
|
||||
n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
|
||||
|
||||
if ((ifa->type != OSPF_IT_VLINK) && (ps_iface_mtu != ifa->iface->mtu)
|
||||
&& (ps_iface_mtu != 0) && (ifa->iface->mtu != 0))
|
||||
log(L_WARN "OSPF: MTU mismatch with neighbour %I on interface %s (remote %d, local %d)",
|
||||
n->ip, ifa->ifname, ps_iface_mtu, ifa->iface->mtu);
|
||||
|
||||
if ((ps->imms.bit.m && ps->imms.bit.ms && ps->imms.bit.i)
|
||||
&& (n->rid > po->router_id) && (size == sizeof(struct ospf_dbdes_packet)))
|
||||
if ((rcv_imms == DBDES_IMMS) &&
|
||||
(n->rid > p->router_id) &&
|
||||
(plen == ospf_dbdes_hdrlen(p)))
|
||||
{
|
||||
/* I'm slave! */
|
||||
n->dds = ps_ddseq;
|
||||
n->ddr = ps_ddseq;
|
||||
n->options = ps_options;
|
||||
n->myimms.bit.ms = 0;
|
||||
n->imms.byte = ps->imms.byte;
|
||||
OSPF_TRACE(D_PACKETS, "I'm slave to %I.", n->ip);
|
||||
n->dds = rcv_ddseq;
|
||||
n->ddr = rcv_ddseq;
|
||||
n->options = rcv_options;
|
||||
n->myimms &= ~DBDES_MS;
|
||||
n->imms = rcv_imms;
|
||||
tm_stop(n->dbdes_timer);
|
||||
ospf_neigh_sm(n, INM_NEGDONE);
|
||||
ospf_dbdes_send(n, 1);
|
||||
ospf_send_dbdes(p, n);
|
||||
break;
|
||||
}
|
||||
|
||||
if (((ps->imms.bit.i == 0) && (ps->imms.bit.ms == 0)) &&
|
||||
(n->rid < po->router_id) && (n->dds == ps_ddseq))
|
||||
if (!(rcv_imms & DBDES_I) &&
|
||||
!(rcv_imms & DBDES_MS) &&
|
||||
(n->rid < p->router_id) &&
|
||||
(n->dds == rcv_ddseq))
|
||||
{
|
||||
/* I'm master! */
|
||||
n->options = ps_options;
|
||||
n->ddr = ps_ddseq - 1; /* It will be set corectly a few lines down */
|
||||
n->imms.byte = ps->imms.byte;
|
||||
OSPF_TRACE(D_PACKETS, "I'm master to %I.", n->ip);
|
||||
n->options = rcv_options;
|
||||
n->ddr = rcv_ddseq - 1; /* It will be set corectly a few lines down */
|
||||
n->imms = rcv_imms;
|
||||
ospf_neigh_sm(n, INM_NEGDONE);
|
||||
/* Continue to the NEIGHBOR_EXCHANGE case */
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("%s: Nothing happend to %I (imms=%u)\n", p->name, n->ip,
|
||||
ps->imms.byte);
|
||||
DBG("%s: Nothing happend to %I (imms=%d)\n", p->name, n->ip, rcv_imms);
|
||||
break;
|
||||
}
|
||||
|
||||
case NEIGHBOR_EXCHANGE:
|
||||
if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) &&
|
||||
(ps_ddseq == n->ddr))
|
||||
if ((rcv_imms == n->imms) &&
|
||||
(rcv_options == n->options) &&
|
||||
(rcv_ddseq == n->ddr))
|
||||
goto duplicate;
|
||||
|
||||
if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS))
|
||||
DROP("MS-bit mismatch", rcv_imms);
|
||||
|
||||
if (rcv_imms & DBDES_I)
|
||||
DROP("I-bit mismatch", rcv_imms);
|
||||
|
||||
if (rcv_options != n->options)
|
||||
DROP("options mismatch", rcv_options);
|
||||
|
||||
n->ddr = rcv_ddseq;
|
||||
n->imms = rcv_imms;
|
||||
|
||||
if (n->myimms & DBDES_MS)
|
||||
{
|
||||
/* Duplicate packet */
|
||||
OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
|
||||
if (n->myimms.bit.ms == 0)
|
||||
/* MASTER */
|
||||
|
||||
if (rcv_ddseq != n->dds)
|
||||
DROP("DD sequence number mismatch", rcv_ddseq);
|
||||
|
||||
n->dds++;
|
||||
|
||||
if (ospf_process_dbdes(p, pkt, n) < 0)
|
||||
return;
|
||||
|
||||
if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
|
||||
{
|
||||
/* Slave should retransmit dbdes packet */
|
||||
ospf_dbdes_send(n, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
n->ddr = ps_ddseq;
|
||||
|
||||
if (ps->imms.bit.ms != n->imms.bit.ms) /* M/S bit differs */
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit MS)",
|
||||
n->ip);
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ps->imms.bit.i) /* I bit is set */
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit I)",
|
||||
n->ip);
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
break;
|
||||
}
|
||||
|
||||
n->imms.byte = ps->imms.byte;
|
||||
|
||||
if (ps_options != n->options) /* Options differs */
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)",
|
||||
n->ip);
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
break;
|
||||
}
|
||||
|
||||
if (n->myimms.bit.ms)
|
||||
{
|
||||
if (ps_ddseq != n->dds) /* MASTER */
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (master)",
|
||||
n->ip);
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
tm_stop(n->dbdes_timer);
|
||||
ospf_neigh_sm(n, INM_EXDONE);
|
||||
break;
|
||||
}
|
||||
n->dds++;
|
||||
DBG("Incrementing dds\n");
|
||||
ospf_dbdes_reqladd(ps, n);
|
||||
if ((n->myimms.bit.m == 0) && (ps->imms.bit.m == 0))
|
||||
{
|
||||
ospf_neigh_sm(n, INM_EXDONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
ospf_dbdes_send(n, 1);
|
||||
}
|
||||
|
||||
ospf_send_dbdes(p, n);
|
||||
tm_start(n->dbdes_timer, n->ifa->rxmtint);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ps_ddseq != (n->dds + 1)) /* SLAVE */
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)", n->ip);
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
break;
|
||||
}
|
||||
n->ddr = ps_ddseq;
|
||||
n->dds = ps_ddseq;
|
||||
ospf_dbdes_reqladd(ps, n);
|
||||
ospf_dbdes_send(n, 1);
|
||||
}
|
||||
/* SLAVE */
|
||||
|
||||
if (rcv_ddseq != (n->dds + 1))
|
||||
DROP("DD sequence number mismatch", rcv_ddseq);
|
||||
|
||||
n->ddr = rcv_ddseq;
|
||||
n->dds = rcv_ddseq;
|
||||
|
||||
if (ospf_process_dbdes(p, pkt, n) < 0)
|
||||
return;
|
||||
|
||||
ospf_send_dbdes(p, n);
|
||||
|
||||
if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
|
||||
ospf_neigh_sm(n, INM_EXDONE);
|
||||
}
|
||||
break;
|
||||
|
||||
case NEIGHBOR_LOADING:
|
||||
case NEIGHBOR_FULL:
|
||||
if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options)
|
||||
&& (ps_ddseq == n->ddr))
|
||||
/* Only duplicate are accepted */
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
|
||||
if (n->myimms.bit.ms == 0)
|
||||
{
|
||||
/* Slave should retransmit dbdes packet */
|
||||
ospf_dbdes_send(n, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)",
|
||||
n->ip);
|
||||
DBG("PS=%u, DDR=%u, DDS=%u\n", ps_ddseq, n->ddr, n->dds);
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
}
|
||||
break;
|
||||
if ((rcv_imms == n->imms) &&
|
||||
(rcv_options == n->options) &&
|
||||
(rcv_ddseq == n->ddr))
|
||||
goto duplicate;
|
||||
|
||||
DROP("too late for DD exchange", n->state);
|
||||
|
||||
default:
|
||||
bug("Received dbdes from %I in undefined state.", n->ip);
|
||||
bug("Undefined interface state");
|
||||
}
|
||||
return;
|
||||
|
||||
duplicate:
|
||||
OSPF_TRACE(D_PACKETS, "DBDES packet is duplicate");
|
||||
|
||||
/* Slave should retransmit DBDES packet */
|
||||
if (!(n->myimms & DBDES_MS))
|
||||
ospf_rxmt_dbdes(p, n);
|
||||
return;
|
||||
|
||||
drop:
|
||||
LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)",
|
||||
n->rid, ifa->ifname, err_dsc, err_val);
|
||||
|
||||
ospf_neigh_sm(n, INM_SEQMIS);
|
||||
return;
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 1999 - 2004 Ondrej Filip <feela@network.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_OSPF_DBDES_H_
|
||||
#define _BIRD_OSPF_DBDES_H_
|
||||
|
||||
void ospf_dbdes_send(struct ospf_neighbor *n, int next);
|
||||
void ospf_dbdes_receive(struct ospf_packet *ps, struct ospf_iface *ifa,
|
||||
struct ospf_neighbor *n);
|
||||
|
||||
#endif /* _BIRD_OSPF_DBDES_H_ */
|
@ -2,6 +2,8 @@
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 1999--2004 Ondrej Filip <feela@network.cz>
|
||||
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2009--2014 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
@ -9,25 +11,26 @@
|
||||
#include "ospf.h"
|
||||
|
||||
|
||||
#ifdef OSPFv2
|
||||
struct ospf_hello_packet
|
||||
struct ospf_hello2_packet
|
||||
{
|
||||
struct ospf_packet ospf_packet;
|
||||
ip_addr netmask;
|
||||
struct ospf_packet hdr;
|
||||
union ospf_auth auth;
|
||||
|
||||
u32 netmask;
|
||||
u16 helloint;
|
||||
u8 options;
|
||||
u8 priority;
|
||||
u32 deadint;
|
||||
u32 dr;
|
||||
u32 bdr;
|
||||
|
||||
u32 neighbors[];
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef OSPFv3
|
||||
struct ospf_hello_packet
|
||||
struct ospf_hello3_packet
|
||||
{
|
||||
struct ospf_packet ospf_packet;
|
||||
struct ospf_packet hdr;
|
||||
|
||||
u32 iface_id;
|
||||
u8 priority;
|
||||
u8 options3;
|
||||
@ -37,286 +40,92 @@ struct ospf_hello_packet
|
||||
u16 deadint;
|
||||
u32 dr;
|
||||
u32 bdr;
|
||||
|
||||
u32 neighbors[];
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
||||
struct ospf_neighbor *n, ip_addr faddr)
|
||||
ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
|
||||
{
|
||||
struct proto_ospf *po = ifa->oa->po;
|
||||
struct proto *p = &po->proto;
|
||||
char *beg = "OSPF: Bad HELLO packet from ";
|
||||
unsigned int size, i, twoway, peers;
|
||||
u32 tmp;
|
||||
u32 *pnrid;
|
||||
|
||||
size = ntohs(ps_i->length);
|
||||
if (size < sizeof(struct ospf_hello_packet))
|
||||
{
|
||||
log(L_ERR "%s%I - too short (%u B)", beg, faddr, size);
|
||||
return;
|
||||
}
|
||||
|
||||
struct ospf_hello_packet *ps = (void *) ps_i;
|
||||
|
||||
OSPF_TRACE(D_PACKETS, "HELLO packet received from %I via %s", faddr, ifa->ifname);
|
||||
|
||||
#ifdef OSPFv2
|
||||
ip_addr mask = ps->netmask;
|
||||
ipa_ntoh(mask);
|
||||
if ((ifa->type != OSPF_IT_VLINK) &&
|
||||
(ifa->type != OSPF_IT_PTP) &&
|
||||
!ipa_equal(mask, ipa_mkmask(ifa->addr->pxlen)))
|
||||
{
|
||||
log(L_ERR "%s%I - netmask mismatch (%I)", beg, faddr, mask);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
tmp = ntohs(ps->helloint);
|
||||
if (tmp != ifa->helloint)
|
||||
{
|
||||
log(L_ERR "%s%I - hello interval mismatch (%d)", beg, faddr, tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef OSPFv2
|
||||
tmp = ntohl(ps->deadint);
|
||||
#else /* OSPFv3 */
|
||||
tmp = ntohs(ps->deadint);
|
||||
#endif
|
||||
if (tmp != ifa->deadint)
|
||||
{
|
||||
log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check whether bits E, N match */
|
||||
if ((ps->options ^ ifa->oa->options) & (OPT_E | OPT_N))
|
||||
{
|
||||
log(L_ERR "%s%I - area type mismatch (%x)", beg, faddr, ps->options);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef OSPFv2
|
||||
if (n && (n->rid != ntohl(ps_i->routerid)))
|
||||
{
|
||||
OSPF_TRACE(D_EVENTS,
|
||||
"Neighbor %I has changed router id from %R to %R.",
|
||||
n->ip, n->rid, ntohl(ps_i->routerid));
|
||||
ospf_neigh_remove(n);
|
||||
n = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!n)
|
||||
{
|
||||
if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
|
||||
{
|
||||
struct nbma_node *nn = find_nbma_node(ifa, faddr);
|
||||
|
||||
if (!nn && ifa->strictnbma)
|
||||
{
|
||||
log(L_WARN "Ignoring new neighbor: %I on %s", faddr, ifa->ifname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nn && (ifa->type == OSPF_IT_NBMA) &&
|
||||
(((ps->priority == 0) && nn->eligible) ||
|
||||
((ps->priority > 0) && !nn->eligible)))
|
||||
{
|
||||
log(L_ERR "Eligibility mismatch for neighbor: %I on %s", faddr, ifa->ifname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nn)
|
||||
nn->found = 1;
|
||||
}
|
||||
|
||||
OSPF_TRACE(D_EVENTS, "New neighbor found: %I on %s", faddr, ifa->ifname);
|
||||
|
||||
n = ospf_neighbor_new(ifa);
|
||||
|
||||
n->rid = ntohl(ps_i->routerid);
|
||||
n->ip = faddr;
|
||||
n->dr = ntohl(ps->dr);
|
||||
n->bdr = ntohl(ps->bdr);
|
||||
n->priority = ps->priority;
|
||||
#ifdef OSPFv3
|
||||
n->iface_id = ntohl(ps->iface_id);
|
||||
#endif
|
||||
|
||||
if (n->ifa->cf->bfd)
|
||||
ospf_neigh_update_bfd(n, n->ifa->bfd);
|
||||
}
|
||||
#ifdef OSPFv3 /* NOTE: this could also be relevant for OSPFv2 on PtP ifaces */
|
||||
else if (!ipa_equal(faddr, n->ip))
|
||||
{
|
||||
OSPF_TRACE(D_EVENTS, "Neighbor address changed from %I to %I", n->ip, faddr);
|
||||
n->ip = faddr;
|
||||
}
|
||||
#endif
|
||||
|
||||
ospf_neigh_sm(n, INM_HELLOREC);
|
||||
|
||||
pnrid = (u32 *) ((struct ospf_hello_packet *) (ps + 1));
|
||||
|
||||
peers = (size - sizeof(struct ospf_hello_packet))/ sizeof(u32);
|
||||
|
||||
twoway = 0;
|
||||
for (i = 0; i < peers; i++)
|
||||
{
|
||||
if (ntohl(pnrid[i]) == po->router_id)
|
||||
{
|
||||
DBG("%s: Twoway received from %I\n", p->name, faddr);
|
||||
ospf_neigh_sm(n, INM_2WAYREC);
|
||||
twoway = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!twoway)
|
||||
ospf_neigh_sm(n, INM_1WAYREC);
|
||||
|
||||
u32 olddr = n->dr;
|
||||
u32 oldbdr = n->bdr;
|
||||
u32 oldpriority = n->priority;
|
||||
#ifdef OSPFv3
|
||||
u32 oldiface_id = n->iface_id;
|
||||
#endif
|
||||
|
||||
n->dr = ntohl(ps->dr);
|
||||
n->bdr = ntohl(ps->bdr);
|
||||
n->priority = ps->priority;
|
||||
#ifdef OSPFv3
|
||||
n->iface_id = ntohl(ps->iface_id);
|
||||
#endif
|
||||
|
||||
|
||||
/* Check priority change */
|
||||
if (n->state >= NEIGHBOR_2WAY)
|
||||
{
|
||||
#ifdef OSPFv2
|
||||
u32 neigh = ipa_to_u32(n->ip);
|
||||
#else /* OSPFv3 */
|
||||
u32 neigh = n->rid;
|
||||
#endif
|
||||
|
||||
if (n->priority != oldpriority)
|
||||
ospf_iface_sm(ifa, ISM_NEICH);
|
||||
|
||||
#ifdef OSPFv3
|
||||
if (n->iface_id != oldiface_id)
|
||||
ospf_iface_sm(ifa, ISM_NEICH);
|
||||
#endif
|
||||
|
||||
/* Neighbor is declaring itself ad DR and there is no BDR */
|
||||
if ((n->dr == neigh) && (n->bdr == 0)
|
||||
&& (n->state != NEIGHBOR_FULL))
|
||||
ospf_iface_sm(ifa, ISM_BACKS);
|
||||
|
||||
/* Neighbor is declaring itself as BDR */
|
||||
if ((n->bdr == neigh) && (n->state != NEIGHBOR_FULL))
|
||||
ospf_iface_sm(ifa, ISM_BACKS);
|
||||
|
||||
/* Neighbor is newly declaring itself as DR or BDR */
|
||||
if (((n->dr == neigh) && (n->dr != olddr))
|
||||
|| ((n->bdr == neigh) && (n->bdr != oldbdr)))
|
||||
ospf_iface_sm(ifa, ISM_NEICH);
|
||||
|
||||
/* Neighbor is no more declaring itself as DR or BDR */
|
||||
if (((olddr == neigh) && (n->dr != olddr))
|
||||
|| ((oldbdr == neigh) && (n->bdr != oldbdr)))
|
||||
ospf_iface_sm(ifa, ISM_NEICH);
|
||||
}
|
||||
|
||||
if (ifa->type == OSPF_IT_NBMA)
|
||||
{
|
||||
if ((ifa->priority == 0) && (n->priority > 0))
|
||||
ospf_hello_send(n->ifa, OHS_HELLO, n);
|
||||
}
|
||||
ospf_neigh_sm(n, INM_HELLOREC);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
|
||||
{
|
||||
struct ospf_hello_packet *pkt;
|
||||
struct ospf_packet *op;
|
||||
struct proto *p;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
struct ospf_packet *pkt;
|
||||
struct ospf_neighbor *neigh, *n1;
|
||||
u16 length;
|
||||
int i;
|
||||
struct nbma_node *nb;
|
||||
u32 *neighbors;
|
||||
uint length;
|
||||
int i, max;
|
||||
|
||||
if (ifa->state <= OSPF_IS_LOOP)
|
||||
return;
|
||||
|
||||
if (ifa->stub)
|
||||
return; /* Don't send any packet on stub iface */
|
||||
return;
|
||||
|
||||
p = (struct proto *) (ifa->oa->po);
|
||||
DBG("%s: Hello/Poll timer fired on interface %s with IP %I\n",
|
||||
p->name, ifa->ifname, ifa->addr->ip);
|
||||
|
||||
/* Now we should send a hello packet */
|
||||
pkt = ospf_tx_buffer(ifa);
|
||||
op = &pkt->ospf_packet;
|
||||
|
||||
/* Now fill ospf_hello header */
|
||||
ospf_pkt_fill_hdr(ifa, pkt, HELLO_P);
|
||||
|
||||
#ifdef OSPFv2
|
||||
pkt->netmask = ipa_mkmask(ifa->addr->pxlen);
|
||||
ipa_hton(pkt->netmask);
|
||||
if ((ifa->type == OSPF_IT_VLINK) ||
|
||||
((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask))
|
||||
pkt->netmask = IPA_NONE;
|
||||
#endif
|
||||
if (ospf_is_v2(p))
|
||||
{
|
||||
struct ospf_hello2_packet *ps = (void *) pkt;
|
||||
|
||||
pkt->helloint = ntohs(ifa->helloint);
|
||||
pkt->priority = ifa->priority;
|
||||
if ((ifa->type == OSPF_IT_VLINK) ||
|
||||
((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask))
|
||||
ps->netmask = 0;
|
||||
else
|
||||
ps->netmask = htonl(u32_mkmask(ifa->addr->pxlen));
|
||||
|
||||
#ifdef OSPFv3
|
||||
pkt->iface_id = htonl(ifa->iface_id);
|
||||
ps->helloint = ntohs(ifa->helloint);
|
||||
ps->options = ifa->oa->options;
|
||||
ps->priority = ifa->priority;
|
||||
ps->deadint = htonl(ifa->deadint);
|
||||
ps->dr = htonl(ipa_to_u32(ifa->drip));
|
||||
ps->bdr = htonl(ipa_to_u32(ifa->bdrip));
|
||||
|
||||
pkt->options3 = ifa->oa->options >> 16;
|
||||
pkt->options2 = ifa->oa->options >> 8;
|
||||
#endif
|
||||
pkt->options = ifa->oa->options;
|
||||
length = sizeof(struct ospf_hello2_packet);
|
||||
neighbors = ps->neighbors;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct ospf_hello3_packet *ps = (void *) pkt;
|
||||
|
||||
#ifdef OSPFv2
|
||||
pkt->deadint = htonl(ifa->deadint);
|
||||
pkt->dr = htonl(ipa_to_u32(ifa->drip));
|
||||
pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
|
||||
#else /* OSPFv3 */
|
||||
pkt->deadint = htons(ifa->deadint);
|
||||
pkt->dr = htonl(ifa->drid);
|
||||
pkt->bdr = htonl(ifa->bdrid);
|
||||
#endif
|
||||
ps->iface_id = htonl(ifa->iface_id);
|
||||
ps->priority = ifa->priority;
|
||||
ps->options3 = ifa->oa->options >> 16;
|
||||
ps->options2 = ifa->oa->options >> 8;
|
||||
ps->options = ifa->oa->options;
|
||||
ps->helloint = ntohs(ifa->helloint);
|
||||
ps->deadint = htons(ifa->deadint);
|
||||
ps->dr = htonl(ifa->drid);
|
||||
ps->bdr = htonl(ifa->bdrid);
|
||||
|
||||
length = sizeof(struct ospf_hello3_packet);
|
||||
neighbors = ps->neighbors;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
max = (ospf_pkt_maxsize(ifa) - length) / sizeof(u32);
|
||||
|
||||
/* Fill all neighbors */
|
||||
i = 0;
|
||||
|
||||
if (kind != OHS_SHUTDOWN)
|
||||
{
|
||||
u32 *pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
|
||||
WALK_LIST(neigh, ifa->neigh_list)
|
||||
{
|
||||
if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_maxsize(ifa))
|
||||
if (i == max)
|
||||
{
|
||||
log(L_WARN "%s: Too many neighbors on interface %s", p->name, ifa->ifname);
|
||||
log(L_WARN "%s: Too many neighbors on %s", p->p.name, ifa->ifname);
|
||||
break;
|
||||
}
|
||||
*(pp + i) = htonl(neigh->rid);
|
||||
neighbors[i] = htonl(neigh->rid);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
length = sizeof(struct ospf_hello_packet) + i * sizeof(u32);
|
||||
op->length = htons(length);
|
||||
length += i * sizeof(u32);
|
||||
pkt->length = htons(length);
|
||||
|
||||
OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s", ifa->ifname);
|
||||
|
||||
switch(ifa->type)
|
||||
{
|
||||
@ -334,7 +143,7 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
|
||||
|
||||
int to_all = ifa->state > OSPF_IS_DROTHER;
|
||||
int me_elig = ifa->priority > 0;
|
||||
|
||||
|
||||
if (kind == OHS_POLL) /* Poll timer */
|
||||
{
|
||||
WALK_LIST(nb, ifa->nbma_list)
|
||||
@ -369,8 +178,215 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
|
||||
break;
|
||||
|
||||
default:
|
||||
bug("Bug in ospf_hello_send()");
|
||||
bug("Bug in ospf_send_hello()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
struct ospf_neighbor *n, ip_addr faddr)
|
||||
{
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
const char *err_dsc = NULL;
|
||||
u32 rcv_iface_id, rcv_helloint, rcv_deadint, rcv_dr, rcv_bdr;
|
||||
u8 rcv_options, rcv_priority;
|
||||
u32 *neighbors;
|
||||
u32 neigh_count;
|
||||
uint plen, i, err_val = 0;
|
||||
|
||||
/* RFC 2328 10.5 */
|
||||
|
||||
/*
|
||||
* We may not yet havethe associate neighbor, so we use Router ID from the
|
||||
* packet instead of one from the neighbor structure for log messages.
|
||||
*/
|
||||
u32 rcv_rid = ntohl(pkt->routerid);
|
||||
OSPF_TRACE(D_PACKETS, "HELLO packet received from nbr %R on %s", rcv_rid, ifa->ifname);
|
||||
|
||||
plen = ntohs(pkt->length);
|
||||
|
||||
if (ospf_is_v2(p))
|
||||
{
|
||||
struct ospf_hello2_packet *ps = (void *) pkt;
|
||||
|
||||
if (plen < sizeof(struct ospf_hello2_packet))
|
||||
DROP("too short", plen);
|
||||
|
||||
rcv_iface_id = 0;
|
||||
rcv_helloint = ntohs(ps->helloint);
|
||||
rcv_deadint = ntohl(ps->deadint);
|
||||
rcv_dr = ntohl(ps->dr);
|
||||
rcv_bdr = ntohl(ps->bdr);
|
||||
rcv_options = ps->options;
|
||||
rcv_priority = ps->priority;
|
||||
|
||||
int pxlen = u32_masklen(ntohl(ps->netmask));
|
||||
if ((ifa->type != OSPF_IT_VLINK) &&
|
||||
(ifa->type != OSPF_IT_PTP) &&
|
||||
(pxlen != ifa->addr->pxlen))
|
||||
DROP("prefix length mismatch", pxlen);
|
||||
|
||||
neighbors = ps->neighbors;
|
||||
neigh_count = (plen - sizeof(struct ospf_hello2_packet)) / sizeof(u32);
|
||||
}
|
||||
else /* OSPFv3 */
|
||||
{
|
||||
struct ospf_hello3_packet *ps = (void *) pkt;
|
||||
|
||||
if (plen < sizeof(struct ospf_hello3_packet))
|
||||
DROP("too short", plen);
|
||||
|
||||
rcv_iface_id = ntohl(ps->iface_id);
|
||||
rcv_helloint = ntohs(ps->helloint);
|
||||
rcv_deadint = ntohs(ps->deadint);
|
||||
rcv_dr = ntohl(ps->dr);
|
||||
rcv_bdr = ntohl(ps->bdr);
|
||||
rcv_options = ps->options;
|
||||
rcv_priority = ps->priority;
|
||||
|
||||
neighbors = ps->neighbors;
|
||||
neigh_count = (plen - sizeof(struct ospf_hello3_packet)) / sizeof(u32);
|
||||
}
|
||||
|
||||
OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s", ifa->ifname);
|
||||
if (rcv_helloint != ifa->helloint)
|
||||
DROP("hello interval mismatch", rcv_helloint);
|
||||
|
||||
if (rcv_deadint != ifa->deadint)
|
||||
DROP("dead interval mismatch", rcv_deadint);
|
||||
|
||||
/* Check whether bits E, N match */
|
||||
if ((rcv_options ^ ifa->oa->options) & (OPT_E | OPT_N))
|
||||
DROP("area type mismatch", rcv_options);
|
||||
|
||||
/* Check consistency of existing neighbor entry */
|
||||
if (n)
|
||||
{
|
||||
uint t = ifa->type;
|
||||
if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP)))
|
||||
{
|
||||
/* Neighbor identified by IP address; Router ID may change */
|
||||
if (n->rid != rcv_rid)
|
||||
{
|
||||
OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed Router ID to %R",
|
||||
n->rid, ifa->ifname, rcv_rid);
|
||||
ospf_neigh_sm(n, INM_KILLNBR);
|
||||
n = NULL;
|
||||
}
|
||||
}
|
||||
else /* OSPFv3 or OSPFv2/PtP */
|
||||
{
|
||||
/* Neighbor identified by Router ID; IP address may change */
|
||||
if (!ipa_equal(faddr, n->ip))
|
||||
{
|
||||
OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed IP address to %I",
|
||||
n->rid, ifa->ifname, n->ip, faddr);
|
||||
n->ip = faddr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!n)
|
||||
{
|
||||
if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
|
||||
{
|
||||
struct nbma_node *nn = find_nbma_node(ifa, faddr);
|
||||
|
||||
if (!nn && ifa->strictnbma)
|
||||
DROP1("new neighbor denied");
|
||||
|
||||
if (nn && (ifa->type == OSPF_IT_NBMA) &&
|
||||
(((rcv_priority == 0) && nn->eligible) ||
|
||||
((rcv_priority > 0) && !nn->eligible)))
|
||||
DROP("eligibility mismatch", rcv_priority);
|
||||
|
||||
if (nn)
|
||||
nn->found = 1;
|
||||
}
|
||||
|
||||
OSPF_TRACE(D_EVENTS, "New neighbor %R on %s, IP address %I",
|
||||
rcv_rid, ifa->ifname, faddr);
|
||||
|
||||
n = ospf_neighbor_new(ifa);
|
||||
|
||||
n->rid = rcv_rid;
|
||||
n->ip = faddr;
|
||||
n->dr = rcv_dr;
|
||||
n->bdr = rcv_bdr;
|
||||
n->priority = rcv_priority;
|
||||
n->iface_id = rcv_iface_id;
|
||||
|
||||
if (n->ifa->cf->bfd)
|
||||
ospf_neigh_update_bfd(n, n->ifa->bfd);
|
||||
}
|
||||
|
||||
u32 n_id = ospf_is_v2(p) ? ipa_to_u32(n->ip) : n->rid;
|
||||
|
||||
u32 old_dr = n->dr;
|
||||
u32 old_bdr = n->bdr;
|
||||
u32 old_priority = n->priority;
|
||||
u32 old_iface_id = n->iface_id;
|
||||
|
||||
n->dr = rcv_dr;
|
||||
n->bdr = rcv_bdr;
|
||||
n->priority = rcv_priority;
|
||||
n->iface_id = rcv_iface_id;
|
||||
|
||||
|
||||
/* Update inactivity timer */
|
||||
ospf_neigh_sm(n, INM_HELLOREC);
|
||||
|
||||
/* RFC 2328 9.5.1 - non-eligible routers reply to hello on NBMA nets */
|
||||
if (ifa->type == OSPF_IT_NBMA)
|
||||
if ((ifa->priority == 0) && (n->priority > 0))
|
||||
ospf_send_hello(n->ifa, OHS_HELLO, n);
|
||||
|
||||
|
||||
/* Examine list of neighbors */
|
||||
for (i = 0; i < neigh_count; i++)
|
||||
if (neighbors[i] == htonl(p->router_id))
|
||||
goto found_self;
|
||||
|
||||
ospf_neigh_sm(n, INM_1WAYREC);
|
||||
return;
|
||||
|
||||
found_self:
|
||||
ospf_neigh_sm(n, INM_2WAYREC);
|
||||
|
||||
|
||||
if (n->iface_id != old_iface_id)
|
||||
{
|
||||
/* If neighbor is DR, also update cached DR interface ID */
|
||||
if (ifa->drid == n->rid)
|
||||
ifa->dr_iface_id = n->iface_id;
|
||||
|
||||
/* RFC 5340 4.4.3 Event 4 - change of neighbor's interface ID */
|
||||
ospf_notify_rt_lsa(ifa->oa);
|
||||
|
||||
/* Missed in RFC 5340 4.4.3 Event 4 - (Px-)Net-LSA uses iface_id to ref Link-LSAs */
|
||||
ospf_notify_net_lsa(ifa);
|
||||
}
|
||||
|
||||
if (ifa->state == OSPF_IS_WAITING)
|
||||
{
|
||||
/* Neighbor is declaring itself DR (and there is no BDR) or as BDR */
|
||||
if (((n->dr == n_id) && (n->bdr == 0)) || (n->bdr == n_id))
|
||||
ospf_iface_sm(ifa, ISM_BACKS);
|
||||
}
|
||||
else if (ifa->state >= OSPF_IS_DROTHER)
|
||||
{
|
||||
/* Neighbor changed priority or started/stopped declaring itself as DR/BDR */
|
||||
if ((n->priority != old_priority) ||
|
||||
((n->dr == n_id) && (old_dr != n_id)) ||
|
||||
((n->dr != n_id) && (old_dr == n_id)) ||
|
||||
((n->bdr == n_id) && (old_bdr != n_id)) ||
|
||||
((n->bdr != n_id) && (old_bdr == n_id)))
|
||||
ospf_iface_sm(ifa, ISM_NEICH);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
drop:
|
||||
LOG_PKT("Bad HELLO packet from nbr %R on %s - %s (%u)",
|
||||
rcv_rid, ifa->ifname, err_dsc, err_val);
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 1999 - 2004 Ondrej Filip <feela@network.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_OSPF_HELLO_H_
|
||||
#define _BIRD_OSPF_HELLO_H_
|
||||
|
||||
void ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
||||
struct ospf_neighbor *n, ip_addr faddr);
|
||||
void ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn);
|
||||
|
||||
#define OHS_HELLO 0
|
||||
#define OHS_POLL 1
|
||||
#define OHS_SHUTDOWN 2
|
||||
|
||||
#endif /* _BIRD_OSPF_HELLO_H_ */
|
File diff suppressed because it is too large
Load Diff
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 1999--2005 Ondrej Filip <feela@network.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_OSPF_IFACE_H_
|
||||
#define _BIRD_OSPF_IFACE_H_
|
||||
|
||||
void ospf_iface_chstate(struct ospf_iface *ifa, u8 state);
|
||||
void ospf_iface_sm(struct ospf_iface *ifa, int event);
|
||||
struct ospf_iface *ospf_iface_find(struct proto_ospf *p, struct iface *what);
|
||||
void ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface);
|
||||
void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a);
|
||||
void ospf_iface_info(struct ospf_iface *ifa);
|
||||
void ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip);
|
||||
void ospf_iface_new_vlink(struct proto_ospf *po, struct ospf_iface_patt *ip);
|
||||
void ospf_iface_remove(struct ospf_iface *ifa);
|
||||
void ospf_iface_shutdown(struct ospf_iface *ifa);
|
||||
int ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new);
|
||||
void ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac);
|
||||
|
||||
int ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen);
|
||||
|
||||
void ospf_open_vlink_sk(struct proto_ospf *po);
|
||||
|
||||
struct nbma_node *find_nbma_node_in(list *nnl, ip_addr ip);
|
||||
|
||||
static inline struct nbma_node *
|
||||
find_nbma_node(struct ospf_iface *ifa, ip_addr ip)
|
||||
{ return find_nbma_node_in(&ifa->nbma_list, ip); }
|
||||
|
||||
#endif /* _BIRD_OSPF_IFACE_H_ */
|
@ -1,7 +1,9 @@
|
||||
/*
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 2000-2004 Ondrej Filip <feela@network.cz>
|
||||
* (c) 2000--2004 Ondrej Filip <feela@network.cz>
|
||||
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2009--2014 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
@ -9,184 +11,171 @@
|
||||
#include "ospf.h"
|
||||
|
||||
|
||||
/*
|
||||
struct ospf_lsack_packet
|
||||
{
|
||||
struct ospf_packet ospf_packet;
|
||||
struct ospf_lsa_header lsh[];
|
||||
struct ospf_packet hdr;
|
||||
// union ospf_auth auth;
|
||||
|
||||
struct ospf_lsa_header lsas[];
|
||||
};
|
||||
*/
|
||||
|
||||
struct lsa_node
|
||||
{
|
||||
node n;
|
||||
struct ospf_lsa_header lsa;
|
||||
};
|
||||
|
||||
|
||||
char *s_queue[] = { "direct", "delayed" };
|
||||
|
||||
|
||||
static void ospf_dump_lsack(struct proto *p, struct ospf_lsack_packet *pkt)
|
||||
static inline void
|
||||
ospf_lsack_body(struct ospf_proto *p, struct ospf_packet *pkt,
|
||||
struct ospf_lsa_header **body, uint *count)
|
||||
{
|
||||
struct ospf_packet *op = &pkt->ospf_packet;
|
||||
uint plen = ntohs(pkt->length);
|
||||
uint hlen = ospf_pkt_hdrlen(p);
|
||||
|
||||
ASSERT(op->type == LSACK_P);
|
||||
ospf_dump_common(p, op);
|
||||
*body = ((void *) pkt) + hlen;
|
||||
*count = (plen - hlen) / sizeof(struct ospf_lsa_header);
|
||||
}
|
||||
|
||||
unsigned int i, j;
|
||||
j = (ntohs(op->length) - sizeof(struct ospf_lsack_packet)) /
|
||||
sizeof(struct ospf_lsa_header);
|
||||
static void
|
||||
ospf_dump_lsack(struct ospf_proto *p, struct ospf_packet *pkt)
|
||||
{
|
||||
struct ospf_lsa_header *lsas;
|
||||
uint i, lsa_count;
|
||||
|
||||
for (i = 0; i < j; i++)
|
||||
ospf_dump_lsahdr(p, pkt->lsh + i);
|
||||
ASSERT(pkt->type == LSACK_P);
|
||||
ospf_dump_common(p, pkt);
|
||||
|
||||
ospf_lsack_body(p, pkt, &lsas, &lsa_count);
|
||||
for (i = 0; i < lsa_count; i++)
|
||||
ospf_dump_lsahdr(p, lsas + i);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* =====================================
|
||||
* Note, that h is in network endianity!
|
||||
* =====================================
|
||||
*/
|
||||
|
||||
void
|
||||
ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h,
|
||||
int queue)
|
||||
ospf_enqueue_lsack(struct ospf_neighbor *n, struct ospf_lsa_header *h_n, int queue)
|
||||
{
|
||||
struct lsah_n *no = mb_alloc(n->pool, sizeof(struct lsah_n));
|
||||
memcpy(&no->lsa, h, sizeof(struct ospf_lsa_header));
|
||||
/* Note that h_n is in network endianity */
|
||||
struct lsa_node *no = mb_alloc(n->pool, sizeof(struct lsa_node));
|
||||
memcpy(&no->lsa, h_n, sizeof(struct ospf_lsa_header));
|
||||
add_tail(&n->ackl[queue], NODE no);
|
||||
DBG("Adding (%s) ack for %R, ID: %R, RT: %R, Type: %u\n", s_queue[queue],
|
||||
n->rid, ntohl(h->id), ntohl(h->rt), h->type);
|
||||
DBG("Adding %s ack for %R, ID: %R, RT: %R, Type: %u\n",
|
||||
(queue == ACKL_DIRECT) ? "direct" : "delayed",
|
||||
n->rid, ntohl(h_n->id), ntohl(h_n->rt), h_n->type);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_lsack_send(struct ospf_neighbor *n, int queue)
|
||||
ospf_reset_lsack_queue(struct ospf_neighbor *n)
|
||||
{
|
||||
struct ospf_packet *op;
|
||||
struct ospf_lsack_packet *pk;
|
||||
u16 len, i = 0;
|
||||
struct ospf_lsa_header *h;
|
||||
struct lsah_n *no;
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
struct proto *p = &n->ifa->oa->po->proto;
|
||||
struct lsa_node *no;
|
||||
|
||||
if (EMPTY_LIST(n->ackl[queue]))
|
||||
return;
|
||||
|
||||
pk = ospf_tx_buffer(ifa);
|
||||
op = &pk->ospf_packet;
|
||||
|
||||
ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
|
||||
h = pk->lsh;
|
||||
|
||||
while (!EMPTY_LIST(n->ackl[queue]))
|
||||
WALK_LIST_FIRST(no, n->ackl[ACKL_DELAY])
|
||||
{
|
||||
no = (struct lsah_n *) HEAD(n->ackl[queue]);
|
||||
memcpy(h + i, &no->lsa, sizeof(struct ospf_lsa_header));
|
||||
DBG("Iter %u ID: %R, RT: %R, Type: %04x\n", i, ntohl((h + i)->id),
|
||||
ntohl((h + i)->rt), (h + i)->type);
|
||||
i++;
|
||||
rem_node(NODE no);
|
||||
mb_free(no);
|
||||
if ((i * sizeof(struct ospf_lsa_header) +
|
||||
sizeof(struct ospf_lsack_packet)) > ospf_pkt_maxsize(n->ifa))
|
||||
{
|
||||
if (!EMPTY_LIST(n->ackl[queue]))
|
||||
{
|
||||
len =
|
||||
sizeof(struct ospf_lsack_packet) +
|
||||
i * sizeof(struct ospf_lsa_header);
|
||||
op->length = htons(len);
|
||||
DBG("Sending and continuing! Len=%u\n", len);
|
||||
}
|
||||
}
|
||||
|
||||
OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname);
|
||||
static inline void
|
||||
ospf_send_lsack_(struct ospf_proto *p, struct ospf_neighbor *n, int queue)
|
||||
{
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
struct ospf_lsa_header *lsas;
|
||||
struct ospf_packet *pkt;
|
||||
struct lsa_node *no;
|
||||
uint i, lsa_max, length;
|
||||
|
||||
if (ifa->type == OSPF_IT_BCAST)
|
||||
{
|
||||
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
|
||||
ospf_send_to_all(ifa);
|
||||
else if (ifa->cf->real_bcast)
|
||||
ospf_send_to_bdr(ifa);
|
||||
else
|
||||
ospf_send_to(ifa, AllDRouters);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
|
||||
ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
|
||||
else
|
||||
ospf_send_to_bdr(ifa);
|
||||
}
|
||||
/* RFC 2328 13.5 */
|
||||
|
||||
ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
pkt = ospf_tx_buffer(ifa);
|
||||
ospf_pkt_fill_hdr(ifa, pkt, LSACK_P);
|
||||
ospf_lsack_body(p, pkt, &lsas, &lsa_max);
|
||||
|
||||
for (i = 0; i < lsa_max && !EMPTY_LIST(n->ackl[queue]); i++)
|
||||
{
|
||||
no = (struct lsa_node *) HEAD(n->ackl[queue]);
|
||||
memcpy(&lsas[i], &no->lsa, sizeof(struct ospf_lsa_header));
|
||||
DBG("Iter %u ID: %R, RT: %R, Type: %04x\n",
|
||||
i, ntohl(lsas[i].id), ntohl(lsas[i].rt), lsas[i].type);
|
||||
rem_node(NODE no);
|
||||
mb_free(no);
|
||||
}
|
||||
|
||||
len = sizeof(struct ospf_lsack_packet) + i * sizeof(struct ospf_lsa_header);
|
||||
op->length = htons(len);
|
||||
DBG("Sending! Len=%u\n", len);
|
||||
length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsa_header);
|
||||
pkt->length = htons(length);
|
||||
|
||||
OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname);
|
||||
OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet sent via %s", ifa->ifname);
|
||||
|
||||
if (ifa->type == OSPF_IT_BCAST)
|
||||
{
|
||||
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
|
||||
ospf_send_to_all(ifa);
|
||||
else if (ifa->cf->real_bcast)
|
||||
ospf_send_to_bdr(ifa);
|
||||
else
|
||||
ospf_send_to(ifa, AllDRouters);
|
||||
ospf_send_to_des(ifa);
|
||||
}
|
||||
else
|
||||
ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
||||
ospf_send_lsack(struct ospf_proto *p, struct ospf_neighbor *n, int queue)
|
||||
{
|
||||
while (!EMPTY_LIST(n->ackl[queue]))
|
||||
ospf_send_lsack_(p, n, queue);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_receive_lsack(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
struct ospf_neighbor *n)
|
||||
{
|
||||
struct proto *p = &ifa->oa->po->proto;
|
||||
struct ospf_lsa_header lsa;
|
||||
struct top_hash_entry *en;
|
||||
unsigned int i, lsano;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
struct ospf_lsa_header lsa, *lsas;
|
||||
struct top_hash_entry *ret, *en;
|
||||
uint i, lsa_count;
|
||||
u32 lsa_type, lsa_domain;
|
||||
|
||||
unsigned int size = ntohs(ps_i->length);
|
||||
if (size < sizeof(struct ospf_lsack_packet))
|
||||
/* RFC 2328 13.7 */
|
||||
|
||||
/* No need to check length, lsack has only basic header */
|
||||
|
||||
OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet received from nbr %R on %s", n->rid, ifa->ifname);
|
||||
|
||||
if (n->state < NEIGHBOR_EXCHANGE)
|
||||
{
|
||||
log(L_ERR "Bad OSPF LSACK packet from %I - too short (%u B)", n->ip, size);
|
||||
OSPF_TRACE(D_PACKETS, "LSACK packet ignored - lesser state than Exchange");
|
||||
return;
|
||||
}
|
||||
|
||||
struct ospf_lsack_packet *ps = (void *) ps_i;
|
||||
OSPF_PACKET(ospf_dump_lsack, ps, "LSACK packet received from %I via %s", n->ip, ifa->ifname);
|
||||
ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */
|
||||
|
||||
ospf_neigh_sm(n, INM_HELLOREC);
|
||||
|
||||
if (n->state < NEIGHBOR_EXCHANGE)
|
||||
return;
|
||||
|
||||
lsano = (size - sizeof(struct ospf_lsack_packet)) /
|
||||
sizeof(struct ospf_lsa_header);
|
||||
for (i = 0; i < lsano; i++)
|
||||
ospf_lsack_body(p, pkt, &lsas, &lsa_count);
|
||||
for (i = 0; i < lsa_count; i++)
|
||||
{
|
||||
ntohlsah(ps->lsh + i, &lsa);
|
||||
u32 dom = ospf_lsa_domain(lsa.type, n->ifa);
|
||||
if ((en = ospf_hash_find_header(n->lsrth, dom, &lsa)) == NULL)
|
||||
continue; /* pg 155 */
|
||||
lsa_ntoh_hdr(&lsas[i], &lsa);
|
||||
lsa_get_type_domain(&lsa, n->ifa, &lsa_type, &lsa_domain);
|
||||
|
||||
if (lsa_comp(&lsa, &en->lsa) != CMP_SAME) /* pg 156 */
|
||||
ret = ospf_hash_find(n->lsrth, lsa_domain, lsa.id, lsa.rt, lsa_type);
|
||||
if (!ret)
|
||||
continue;
|
||||
|
||||
if (lsa_comp(&lsa, &ret->lsa) != CMP_SAME)
|
||||
{
|
||||
if ((lsa.sn == LSA_MAXSEQNO) && (lsa.age == LSA_MAXAGE))
|
||||
continue;
|
||||
|
||||
OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip);
|
||||
OSPF_TRACE(D_PACKETS, "Type: %04x, Id: %R, Rt: %R",
|
||||
lsa.type, lsa.id, lsa.rt);
|
||||
OSPF_TRACE(D_PACKETS, "I have: Age: %4u, Seq: %08x, Sum: %04x",
|
||||
en->lsa.age, en->lsa.sn, en->lsa.checksum);
|
||||
OSPF_TRACE(D_PACKETS, "He has: Age: %4u, Seq: %08x, Sum: %04x",
|
||||
lsa.age, lsa.sn, lsa.checksum);
|
||||
OSPF_TRACE(D_PACKETS, "Strange LSACK from nbr %R on %s", n->rid, ifa->ifname);
|
||||
OSPF_TRACE(D_PACKETS, " Type: %04x, Id: %R, Rt: %R",
|
||||
lsa_type, lsa.id, lsa.rt);
|
||||
OSPF_TRACE(D_PACKETS, " I have: Seq: %08x, Age: %4u, Sum: %04x",
|
||||
ret->lsa.sn, ret->lsa.age, ret->lsa.checksum);
|
||||
OSPF_TRACE(D_PACKETS, " It has: Seq: %08x, Age: %4u, Sum: %04x",
|
||||
lsa.sn, lsa.age, lsa.checksum);
|
||||
continue;
|
||||
}
|
||||
|
||||
DBG("Deleting LS Id: %R RT: %R Type: %u from LS Retl for neighbor %R\n",
|
||||
lsa.id, lsa.rt, lsa.type, n->rid);
|
||||
s_rem_node(SNODE en);
|
||||
ospf_hash_delete(n->lsrth, en);
|
||||
DBG("Deleting LSA (Type: %04x Id: %R Rt: %R) from lsrtl for neighbor %R\n",
|
||||
lsa_type, lsa.id, lsa.rt, n->rid);
|
||||
|
||||
en = ospf_hash_find_entry(p->gr, ret);
|
||||
ospf_lsa_lsrt_down_(en, n, ret);
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 2000--2004 Ondrej Filip <feela@network.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_OSPF_LSACK_H_
|
||||
#define _BIRD_OSPF_LSACK_H_
|
||||
|
||||
struct lsah_n
|
||||
{
|
||||
node n;
|
||||
struct ospf_lsa_header lsa;
|
||||
};
|
||||
|
||||
void ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
||||
struct ospf_neighbor *n);
|
||||
void ospf_lsack_send(struct ospf_neighbor *n, int queue);
|
||||
void ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h,
|
||||
int queue);
|
||||
|
||||
#endif /* _BIRD_OSPF_LSACK_H_ */
|
@ -2,103 +2,21 @@
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 1999--2004 Ondrej Filip <feela@network.cz>
|
||||
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2009--2014 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "ospf.h"
|
||||
|
||||
void
|
||||
flush_lsa(struct top_hash_entry *en, struct proto_ospf *po)
|
||||
{
|
||||
struct proto *p = &po->proto;
|
||||
|
||||
OSPF_TRACE(D_EVENTS,
|
||||
"Going to remove LSA Type: %04x, Id: %R, Rt: %R, Age: %u, Seqno: 0x%x",
|
||||
en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.age, en->lsa.sn);
|
||||
s_rem_node(SNODE en);
|
||||
if (en->lsa_body != NULL)
|
||||
mb_free(en->lsa_body);
|
||||
en->lsa_body = NULL;
|
||||
ospf_hash_delete(po->gr, en);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_flush_area(struct proto_ospf *po, u32 areaid)
|
||||
{
|
||||
struct top_hash_entry *en, *nxt;
|
||||
|
||||
WALK_SLIST_DELSAFE(en, nxt, po->lsal)
|
||||
{
|
||||
if ((LSA_SCOPE(&en->lsa) == LSA_SCOPE_AREA) && (en->domain == areaid))
|
||||
flush_lsa(en, po);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ospf_age
|
||||
* @po: ospf protocol
|
||||
*
|
||||
* This function is periodicaly invoked from ospf_disp(). It computes the new
|
||||
* age of all LSAs and old (@age is higher than %LSA_MAXAGE) LSAs are flushed
|
||||
* whenever possible. If an LSA originated by the router itself is older
|
||||
* than %LSREFRESHTIME a new instance is originated.
|
||||
*
|
||||
* The RFC says that a router should check the checksum of every LSA to detect
|
||||
* hardware problems. BIRD does not do this to minimalize CPU utilization.
|
||||
*
|
||||
* If routing table calculation is scheduled, it also invalidates the old routing
|
||||
* table calculation results.
|
||||
*/
|
||||
void
|
||||
ospf_age(struct proto_ospf *po)
|
||||
{
|
||||
struct proto *p = &po->proto;
|
||||
struct top_hash_entry *en, *nxt;
|
||||
int flush = can_flush_lsa(po);
|
||||
|
||||
WALK_SLIST_DELSAFE(en, nxt, po->lsal)
|
||||
{
|
||||
if (en->lsa.age == LSA_MAXAGE)
|
||||
{
|
||||
if (flush)
|
||||
flush_lsa(en, po);
|
||||
continue;
|
||||
}
|
||||
if ((en->lsa.rt == po->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);
|
||||
en->lsa.sn++;
|
||||
en->lsa.age = 0;
|
||||
en->inst_t = now;
|
||||
en->ini_age = 0;
|
||||
lsasum_calculate(&en->lsa, en->lsa_body);
|
||||
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)
|
||||
{
|
||||
if (flush)
|
||||
{
|
||||
flush_lsa(en, po);
|
||||
schedule_rtcalc(po);
|
||||
}
|
||||
else
|
||||
en->lsa.age = LSA_MAXAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CPU_BIG_ENDIAN
|
||||
void
|
||||
htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
|
||||
lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
|
||||
{
|
||||
n->age = htons(h->age);
|
||||
#ifdef OSPFv2
|
||||
n->options = h->options;
|
||||
#endif
|
||||
n->type = htont(h->type);
|
||||
n->type_raw = htons(h->type_raw);
|
||||
n->id = htonl(h->id);
|
||||
n->rt = htonl(h->rt);
|
||||
n->sn = htonl(h->sn);
|
||||
@ -107,13 +25,10 @@ htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
|
||||
}
|
||||
|
||||
void
|
||||
ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
|
||||
lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
|
||||
{
|
||||
h->age = ntohs(n->age);
|
||||
#ifdef OSPFv2
|
||||
h->options = n->options;
|
||||
#endif
|
||||
h->type = ntoht(n->type);
|
||||
h->type_raw = ntohs(n->type_raw);
|
||||
h->id = ntohl(n->id);
|
||||
h->rt = ntohl(n->rt);
|
||||
h->sn = ntohl(n->sn);
|
||||
@ -122,28 +37,120 @@ ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
|
||||
}
|
||||
|
||||
void
|
||||
htonlsab(void *h, void *n, u16 len)
|
||||
lsa_hton_body(void *h, void *n, u16 len)
|
||||
{
|
||||
u32 *hid = h;
|
||||
u32 *nid = n;
|
||||
unsigned i;
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < (len / sizeof(u32)); i++)
|
||||
nid[i] = htonl(hid[i]);
|
||||
}
|
||||
|
||||
void
|
||||
ntohlsab(void *n, void *h, u16 len)
|
||||
lsa_ntoh_body(void *n, void *h, u16 len)
|
||||
{
|
||||
u32 *nid = n;
|
||||
u32 *hid = h;
|
||||
unsigned i;
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < (len / sizeof(u32)); i++)
|
||||
hid[i] = ntohl(nid[i]);
|
||||
}
|
||||
#endif /* little endian */
|
||||
|
||||
|
||||
|
||||
int
|
||||
lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa)
|
||||
{
|
||||
/* Handle inactive vlinks */
|
||||
if (ifa->state == OSPF_IS_DOWN)
|
||||
return 0;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define LSA_V2_TMAX 8
|
||||
static const u16 lsa_v2_types[LSA_V2_TMAX] =
|
||||
{0, LSA_T_RT, LSA_T_NET, LSA_T_SUM_NET, LSA_T_SUM_RT, LSA_T_EXT, 0, LSA_T_NSSA};
|
||||
|
||||
void
|
||||
lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain)
|
||||
{
|
||||
if (ospf_is_v2(ifa->oa->po))
|
||||
{
|
||||
itype = itype & LSA_T_V2_MASK;
|
||||
itype = (itype < LSA_V2_TMAX) ? lsa_v2_types[itype] : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For unkown LSAs without U-bit change scope to LSA_SCOPE_LINK */
|
||||
if (unknown_lsa_type(itype) && !(itype & LSA_UBIT))
|
||||
itype = itype & ~LSA_SCOPE_MASK;
|
||||
}
|
||||
|
||||
*otype = itype;
|
||||
|
||||
switch (LSA_SCOPE(itype))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void
|
||||
buf_dump(const char *hdr, const byte *buf, int blen)
|
||||
@ -188,8 +195,8 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body)
|
||||
u16 length = h->length;
|
||||
|
||||
// log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length);
|
||||
htonlsah(h, h);
|
||||
htonlsab1(body, length - sizeof(struct ospf_lsa_header));
|
||||
lsa_hton_hdr(h, h);
|
||||
lsa_hton_body1(body, length - sizeof(struct ospf_lsa_header));
|
||||
|
||||
/*
|
||||
char buf[1024];
|
||||
@ -202,8 +209,8 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body)
|
||||
|
||||
// log(L_WARN "Checksum result %4x", h->checksum);
|
||||
|
||||
ntohlsah(h, h);
|
||||
ntohlsab1(body, length - sizeof(struct ospf_lsa_header));
|
||||
lsa_ntoh_hdr(h, h);
|
||||
lsa_ntoh_body1(body, length - sizeof(struct ospf_lsa_header));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -231,7 +238,7 @@ lsasum_check(struct ospf_lsa_header *h, void *body)
|
||||
q = ep;
|
||||
for (p = sp; p < q; p++)
|
||||
{
|
||||
/*
|
||||
/*
|
||||
* I count with bytes from header and than from body
|
||||
* but if there is no body, it's appended to header
|
||||
* (probably checksum in update receiving) and I go on
|
||||
@ -292,33 +299,204 @@ lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
|
||||
return CMP_SAME;
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
lsa_walk_rt2(struct ospf_lsa_rt_walk *rt)
|
||||
{
|
||||
if (rt->buf >= rt->bufend)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
|
||||
rt->type = l->type;
|
||||
rt->metric = l->metric;
|
||||
rt->id = l->id;
|
||||
rt->data = l->data;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
lsa_walk_rt3(struct ospf_lsa_rt_walk *rt)
|
||||
{
|
||||
while (rt->buf >= rt->bufend)
|
||||
{
|
||||
rt->en = ospf_hash_find_rt3_next(rt->en);
|
||||
if (!rt->en)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
return 1;
|
||||
}
|
||||
|
||||
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
|
||||
lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, ip_addr *ip, int *pxlen, u8 *pxopts, u32 *metric)
|
||||
{
|
||||
if (ospf2)
|
||||
{
|
||||
struct ospf_lsa_sum2 *ls = en->lsa_body;
|
||||
*ip = ipa_from_u32(en->lsa.id & ls->netmask);
|
||||
*pxlen = u32_masklen(ls->netmask);
|
||||
*pxopts = 0;
|
||||
*metric = ls->metric & LSA_METRIC_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct ospf_lsa_sum3_net *ls = en->lsa_body;
|
||||
u16 rest;
|
||||
lsa_get_ipv6_prefix(ls->prefix, ip, pxlen, pxopts, &rest);
|
||||
*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
|
||||
lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt)
|
||||
{
|
||||
if (ospf2)
|
||||
{
|
||||
struct ospf_lsa_ext2 *ext = en->lsa_body;
|
||||
rt->ip = ipa_from_u32(en->lsa.id & ext->netmask);
|
||||
rt->pxlen = u32_masklen(ext->netmask);
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct ospf_lsa_ext3 *ext = en->lsa_body;
|
||||
u16 rest;
|
||||
u32 *buf = lsa_get_ipv6_prefix(ext->rest, &rt->ip, &rt->pxlen, &rt->pxopts, &rest);
|
||||
rt->metric = ext->metric & LSA_METRIC_MASK;
|
||||
rt->ebit = ext->metric & LSA_EXT3_EBIT;
|
||||
|
||||
rt->fbit = ext->metric & LSA_EXT3_FBIT;
|
||||
if (rt->fbit)
|
||||
buf = lsa_get_ipv6_addr(buf, &rt->fwaddr);
|
||||
else
|
||||
rt->fwaddr = IPA_NONE;
|
||||
|
||||
rt->tag = (ext->metric & LSA_EXT3_TBIT) ? *buf++ : 0;
|
||||
rt->propagate = rt->pxopts & OPT_PX_P;
|
||||
}
|
||||
}
|
||||
|
||||
#define HDRLEN sizeof(struct ospf_lsa_header)
|
||||
|
||||
static int
|
||||
lsa_validate_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
|
||||
lsa_validate_rt2(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);
|
||||
uint i = 0;
|
||||
void *buf = body;
|
||||
void *bufend = buf + lsa->length - HDRLEN;
|
||||
buf += sizeof(struct ospf_lsa_rt);
|
||||
|
||||
#ifdef OSPFv2
|
||||
if (body->links != max)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < max; i++)
|
||||
while (buf < bufend)
|
||||
{
|
||||
u8 type = rtl[i].type;
|
||||
if (!((type == LSART_PTP) ||
|
||||
(type == LSART_NET) ||
|
||||
#ifdef OSPFv2
|
||||
(type == LSART_STUB) ||
|
||||
#endif
|
||||
(type == LSART_VLNK)))
|
||||
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)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lsa_validate_rt3(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
|
||||
{
|
||||
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
|
||||
return 0;
|
||||
|
||||
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;
|
||||
@ -333,37 +511,18 @@ lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef OSPFv2
|
||||
|
||||
static int
|
||||
lsa_validate_sum(struct ospf_lsa_header *lsa, struct ospf_lsa_sum *body)
|
||||
lsa_validate_sum2(struct ospf_lsa_header *lsa, struct ospf_lsa_sum2 *body)
|
||||
{
|
||||
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum)))
|
||||
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum2)))
|
||||
return 0;
|
||||
|
||||
/* First field should have TOS = 0, we ignore other TOS fields */
|
||||
if ((body->metric & LSA_SUM_TOS) != 0)
|
||||
if ((body->metric & LSA_SUM2_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)
|
||||
@ -372,36 +531,48 @@ pxlen(u32 *buf)
|
||||
}
|
||||
|
||||
static int
|
||||
lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_net *body)
|
||||
lsa_validate_sum3_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body)
|
||||
{
|
||||
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum_net) + 4))
|
||||
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum3_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) +
|
||||
if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_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)
|
||||
lsa_validate_sum3_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body)
|
||||
{
|
||||
if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum_rt)))
|
||||
if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body)
|
||||
lsa_validate_ext2(struct ospf_lsa_header *lsa, struct ospf_lsa_ext2 *body)
|
||||
{
|
||||
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext) + 4))
|
||||
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)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lsa_validate_ext3(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body)
|
||||
{
|
||||
if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext3) + 4))
|
||||
return 0;
|
||||
|
||||
u8 pxl = pxlen(body->rest);
|
||||
@ -409,23 +580,23 @@ lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body)
|
||||
return 0;
|
||||
|
||||
int len = IPV6_PREFIX_SPACE(pxl);
|
||||
if (body->metric & LSA_EXT_FBIT) // forwardinf address
|
||||
if (body->metric & LSA_EXT3_FBIT) // forwardinf address
|
||||
len += 16;
|
||||
if (body->metric & LSA_EXT_TBIT) // route tag
|
||||
if (body->metric & LSA_EXT3_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))
|
||||
if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext3) + len))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, unsigned int offset, u8 *pbuf)
|
||||
lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, uint offset, u8 *pbuf)
|
||||
{
|
||||
unsigned int bound = lsa->length - HDRLEN - 4;
|
||||
uint bound = lsa->length - HDRLEN - 4;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < pxcount; i++)
|
||||
@ -436,7 +607,7 @@ lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, unsigned int offse
|
||||
u8 pxl = pxlen((u32 *) (pbuf + offset));
|
||||
if (pxl > MAX_PREFIX_LENGTH)
|
||||
return 0;
|
||||
|
||||
|
||||
offset += IPV6_PREFIX_SPACE(pxl);
|
||||
}
|
||||
|
||||
@ -464,8 +635,6 @@ lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body)
|
||||
return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* lsa_validate - check whether given LSA is valid
|
||||
@ -477,85 +646,48 @@ lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body)
|
||||
*/
|
||||
|
||||
int
|
||||
lsa_validate(struct ospf_lsa_header *lsa, void *body)
|
||||
lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body)
|
||||
{
|
||||
switch (lsa->type)
|
||||
if (ospf2)
|
||||
{
|
||||
switch (lsa_type)
|
||||
{
|
||||
case LSA_T_RT:
|
||||
return lsa_validate_rt(lsa, body);
|
||||
return lsa_validate_rt2(lsa, body);
|
||||
case LSA_T_NET:
|
||||
return lsa_validate_net(lsa, body);
|
||||
case LSA_T_SUM_NET:
|
||||
return lsa_validate_sum_net(lsa, body);
|
||||
return lsa_validate_sum2(lsa, body);
|
||||
case LSA_T_SUM_RT:
|
||||
return lsa_validate_sum_rt(lsa, body);
|
||||
return lsa_validate_sum2(lsa, body);
|
||||
case LSA_T_EXT:
|
||||
case LSA_T_NSSA:
|
||||
return lsa_validate_ext(lsa, body);
|
||||
#ifdef OSPFv3
|
||||
return lsa_validate_ext2(lsa, body);
|
||||
default:
|
||||
return 0; /* Should not happen, unknown LSAs are already rejected */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (lsa_type)
|
||||
{
|
||||
case LSA_T_RT:
|
||||
return lsa_validate_rt3(lsa, body);
|
||||
case LSA_T_NET:
|
||||
return lsa_validate_net(lsa, body);
|
||||
case LSA_T_SUM_NET:
|
||||
return lsa_validate_sum3_net(lsa, body);
|
||||
case LSA_T_SUM_RT:
|
||||
return lsa_validate_sum3_rt(lsa, body);
|
||||
case LSA_T_EXT:
|
||||
case LSA_T_NSSA:
|
||||
return lsa_validate_ext3(lsa, body);
|
||||
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;
|
||||
return 1; /* Unknown LSAs are OK in OSPFv3 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* lsa_install_new - install new LSA into database
|
||||
* @po: OSPF protocol
|
||||
* @lsa: LSA header
|
||||
* @domain: domain of LSA
|
||||
* @body: pointer to LSA body
|
||||
*
|
||||
* 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 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;
|
||||
struct top_hash_entry *en;
|
||||
|
||||
if ((en = ospf_hash_find_header(po->gr, domain, lsa)) == NULL)
|
||||
{
|
||||
en = ospf_hash_get_header(po->gr, domain, lsa);
|
||||
change = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
|
||||
s_rem_node(SNODE en);
|
||||
}
|
||||
|
||||
DBG("Inst lsa: Id: %R, Rt: %R, Type: %u, Age: %u, Sum: %u, Sn: 0x%x\n",
|
||||
lsa->id, lsa->rt, lsa->type, lsa->age, lsa->checksum, lsa->sn);
|
||||
|
||||
s_add_tail(&po->lsal, SNODE en);
|
||||
en->inst_t = now;
|
||||
if (en->lsa_body != NULL)
|
||||
mb_free(en->lsa_body);
|
||||
en->lsa_body = body;
|
||||
memcpy(&en->lsa, lsa, sizeof(struct ospf_lsa_header));
|
||||
en->ini_age = en->lsa.age;
|
||||
|
||||
if (change)
|
||||
schedule_rtcalc(po);
|
||||
|
||||
return en;
|
||||
}
|
||||
|
@ -1,42 +1,63 @@
|
||||
/*
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 1999 - 2000 Ondrej Filip <feela@network.cz>
|
||||
* (c) 1999--2000 Ondrej Filip <feela@network.cz>
|
||||
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2009--2014 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_OSPF_LSALIB_H_
|
||||
#define _BIRD_OSPF_LSALIB_H_
|
||||
|
||||
#ifdef CPU_BIG_ENDIAN
|
||||
static inline void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { *n = *h; };
|
||||
static inline void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { *h = *n; };
|
||||
static inline void htonlsab(void *h, void *n, u16 len) { ASSERT(h != n); memcpy(n, h, len); };
|
||||
static inline void ntohlsab(void *n, void *h, u16 len) { ASSERT(n != h); memcpy(h, n, len); };
|
||||
static inline void htonlsab1(void *h, u16 len) { };
|
||||
static inline void ntohlsab1(void *n, u16 len) { };
|
||||
static inline void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { *n = *h; };
|
||||
static inline void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { *h = *n; };
|
||||
static inline void lsa_hton_body(void *h, void *n, u16 len) { ASSERT(h != n); memcpy(n, h, len); };
|
||||
static inline void lsa_ntoh_body(void *n, void *h, u16 len) { ASSERT(n != h); memcpy(h, n, len); };
|
||||
static inline void lsa_hton_body1(void *h, u16 len) { };
|
||||
static inline void lsa_ntoh_body1(void *n, u16 len) { };
|
||||
#else
|
||||
void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n);
|
||||
void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h);
|
||||
void htonlsab(void *h, void *n, u16 len);
|
||||
void ntohlsab(void *n, void *h, u16 len);
|
||||
static inline void htonlsab1(void *h, u16 len) { htonlsab(h, h, len); };
|
||||
static inline void ntohlsab1(void *n, u16 len) { ntohlsab(n, n, len); };
|
||||
void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n);
|
||||
void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h);
|
||||
void lsa_hton_body(void *h, void *n, u16 len);
|
||||
void lsa_ntoh_body(void *n, void *h, u16 len);
|
||||
static inline void lsa_hton_body1(void *h, u16 len) { lsa_hton_body(h, h, len); };
|
||||
static inline void lsa_ntoh_body1(void *n, u16 len) { lsa_ntoh_body(n, n, len); };
|
||||
#endif
|
||||
|
||||
struct ospf_lsa_rt_walk {
|
||||
struct top_hash_entry *en;
|
||||
void *buf, *bufend;
|
||||
int ospf2;
|
||||
u16 type, metric;
|
||||
u32 id, data, lif, nif;
|
||||
};
|
||||
|
||||
|
||||
void lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain);
|
||||
|
||||
static inline void lsa_get_type_domain(struct ospf_lsa_header *lsa, struct ospf_iface *ifa, u32 *otype, u32 *domain)
|
||||
{ lsa_get_type_domain_(lsa->type_raw, ifa, otype, domain); }
|
||||
|
||||
static inline u32 lsa_get_etype(struct ospf_lsa_header *h, struct ospf_proto *p)
|
||||
{ return ospf_is_v2(p) ? (h->type_raw & LSA_T_V2_MASK) : h->type_raw; }
|
||||
|
||||
|
||||
int lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa);
|
||||
|
||||
void lsasum_calculate(struct ospf_lsa_header *header, void *body);
|
||||
u16 lsasum_check(struct ospf_lsa_header *h, void *body);
|
||||
#define CMP_NEWER 1
|
||||
#define CMP_SAME 0
|
||||
#define CMP_OLDER -1
|
||||
int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2);
|
||||
int lsa_validate(struct ospf_lsa_header *lsa, void *body);
|
||||
struct top_hash_entry * lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body);
|
||||
void ospf_age(struct proto_ospf *po);
|
||||
void flush_lsa(struct top_hash_entry *en, struct proto_ospf *po);
|
||||
void ospf_flush_area(struct proto_ospf *po, u32 areaid);
|
||||
|
||||
void lsa_walk_rt_init(struct ospf_proto *po, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt);
|
||||
int lsa_walk_rt(struct ospf_lsa_rt_walk *rt);
|
||||
void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, ip_addr *ip, int *pxlen, u8 *pxopts, u32 *metric);
|
||||
void lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options);
|
||||
void lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt);
|
||||
int lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body);
|
||||
|
||||
#endif /* _BIRD_OSPF_LSALIB_H_ */
|
||||
|
@ -2,6 +2,8 @@
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 2000--2004 Ondrej Filip <feela@network.cz>
|
||||
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2009--2014 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
@ -9,138 +11,136 @@
|
||||
#include "ospf.h"
|
||||
|
||||
|
||||
/*
|
||||
struct ospf_lsreq_packet
|
||||
{
|
||||
struct ospf_packet ospf_packet;
|
||||
struct ospf_lsreq_header lsh[];
|
||||
struct ospf_packet hdr;
|
||||
// union ospf_auth auth;
|
||||
|
||||
struct ospf_lsreq_header lsrs[];
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
static void ospf_dump_lsreq(struct proto *p, struct ospf_lsreq_packet *pkt)
|
||||
static inline void
|
||||
ospf_lsreq_body(struct ospf_proto *p, struct ospf_packet *pkt,
|
||||
struct ospf_lsreq_header **body, uint *count)
|
||||
{
|
||||
struct ospf_packet *op = &pkt->ospf_packet;
|
||||
uint plen = ntohs(pkt->length);
|
||||
uint hlen = ospf_pkt_hdrlen(p);
|
||||
|
||||
ASSERT(op->type == LSREQ_P);
|
||||
ospf_dump_common(p, op);
|
||||
|
||||
unsigned int i, j;
|
||||
j = (ntohs(op->length) - sizeof(struct ospf_lsreq_packet)) /
|
||||
sizeof(struct ospf_lsreq_header);
|
||||
|
||||
for (i = 0; i < j; i++)
|
||||
log(L_TRACE "%s: LSR Type: %04x, Id: %R, Rt: %R", p->name,
|
||||
htonl(pkt->lsh[i].type), htonl(pkt->lsh[i].id), htonl(pkt->lsh[i].rt));
|
||||
*body = ((void *) pkt) + hlen;
|
||||
*count = (plen - hlen) / sizeof(struct ospf_lsreq_header);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_lsreq_send(struct ospf_neighbor *n)
|
||||
static void
|
||||
ospf_dump_lsreq(struct ospf_proto *p, struct ospf_packet *pkt)
|
||||
{
|
||||
snode *sn;
|
||||
struct top_hash_entry *en;
|
||||
struct ospf_lsreq_packet *pk;
|
||||
struct ospf_packet *op;
|
||||
struct ospf_lsreq_header *lsh;
|
||||
u16 length;
|
||||
int i, j;
|
||||
struct proto *p = &n->ifa->oa->po->proto;
|
||||
struct ospf_lsreq_header *lsrs;
|
||||
uint i, lsr_count;
|
||||
|
||||
pk = ospf_tx_buffer(n->ifa);
|
||||
op = &pk->ospf_packet;
|
||||
ASSERT(pkt->type == LSREQ_P);
|
||||
ospf_dump_common(p, pkt);
|
||||
|
||||
ospf_pkt_fill_hdr(n->ifa, pk, LSREQ_P);
|
||||
ospf_lsreq_body(p, pkt, &lsrs, &lsr_count);
|
||||
for (i = 0; i < lsr_count; i++)
|
||||
log(L_TRACE "%s: LSR Type: %04x, Id: %R, Rt: %R", p->p.name,
|
||||
ntohl(lsrs[i].type), ntohl(lsrs[i].id), ntohl(lsrs[i].rt));
|
||||
}
|
||||
|
||||
sn = SHEAD(n->lsrql);
|
||||
if (EMPTY_SLIST(n->lsrql))
|
||||
|
||||
void
|
||||
ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n)
|
||||
{
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
struct ospf_lsreq_header *lsrs;
|
||||
struct top_hash_entry *req;
|
||||
struct ospf_packet *pkt;
|
||||
uint i, lsr_max, length;
|
||||
|
||||
/* RFC 2328 10.9 */
|
||||
|
||||
/* ASSERT((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrql)); */
|
||||
|
||||
pkt = ospf_tx_buffer(ifa);
|
||||
ospf_pkt_fill_hdr(ifa, pkt, LSREQ_P);
|
||||
ospf_lsreq_body(p, pkt, &lsrs, &lsr_max);
|
||||
|
||||
i = 0;
|
||||
WALK_SLIST(req, n->lsrql)
|
||||
{
|
||||
if (n->state == NEIGHBOR_LOADING)
|
||||
ospf_neigh_sm(n, INM_LOADDONE);
|
||||
return;
|
||||
}
|
||||
|
||||
i = j = (ospf_pkt_maxsize(n->ifa) - sizeof(struct ospf_lsreq_packet)) /
|
||||
sizeof(struct ospf_lsreq_header);
|
||||
lsh = pk->lsh;
|
||||
|
||||
for (; i > 0; i--)
|
||||
{
|
||||
en = (struct top_hash_entry *) sn;
|
||||
lsh->type = htonl(en->lsa.type);
|
||||
lsh->rt = htonl(en->lsa.rt);
|
||||
lsh->id = htonl(en->lsa.id);
|
||||
DBG("Requesting %uth LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
|
||||
i, en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age);
|
||||
lsh++;
|
||||
if (sn == STAIL(n->lsrql))
|
||||
if (i == lsr_max)
|
||||
break;
|
||||
sn = sn->next;
|
||||
|
||||
DBG("Requesting %uth LSA: Type: %04u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
|
||||
i, req->lsa_type, req->lsa.id, req->lsa.rt, req->lsa.sn, req->lsa.age);
|
||||
|
||||
u32 etype = lsa_get_etype(&req->lsa, p);
|
||||
lsrs[i].type = htonl(etype);
|
||||
lsrs[i].rt = htonl(req->lsa.rt);
|
||||
lsrs[i].id = htonl(req->lsa.id);
|
||||
i++;
|
||||
}
|
||||
if (i != 0)
|
||||
i--;
|
||||
|
||||
length =
|
||||
sizeof(struct ospf_lsreq_packet) + (j -
|
||||
i) * sizeof(struct ospf_lsreq_header);
|
||||
op->length = htons(length);
|
||||
/* We store the position to see whether requested LSAs have been received */
|
||||
n->lsrqi = req;
|
||||
|
||||
OSPF_PACKET(ospf_dump_lsreq, pk, "LSREQ packet sent to %I via %s", n->ip, n->ifa->ifname);
|
||||
ospf_send_to(n->ifa, n->ip);
|
||||
length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsreq_header);
|
||||
pkt->length = htons(length);
|
||||
|
||||
OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet sent to nbr %R on %s", n->rid, ifa->ifname);
|
||||
ospf_send_to(ifa, n->ip);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
||||
ospf_receive_lsreq(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
struct ospf_neighbor *n)
|
||||
{
|
||||
struct ospf_area *oa = ifa->oa;
|
||||
struct proto_ospf *po = oa->po;
|
||||
struct proto *p = &po->proto;
|
||||
struct ospf_lsreq_header *lsh;
|
||||
struct l_lsr_head *llsh;
|
||||
list uplist;
|
||||
slab *upslab;
|
||||
int i, lsano;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
struct ospf_lsreq_header *lsrs;
|
||||
uint i, lsr_count;
|
||||
|
||||
unsigned int size = ntohs(ps_i->length);
|
||||
if (size < sizeof(struct ospf_lsreq_packet))
|
||||
{
|
||||
log(L_ERR "Bad OSPF LSREQ packet from %I - too short (%u B)", n->ip, size);
|
||||
return;
|
||||
}
|
||||
/* RFC 2328 10.7 */
|
||||
|
||||
struct ospf_lsreq_packet *ps = (void *) ps_i;
|
||||
OSPF_PACKET(ospf_dump_lsreq, ps, "LSREQ packet received from %I via %s", n->ip, ifa->ifname);
|
||||
/* No need to check length, lsreq has only basic header */
|
||||
|
||||
OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet received from nbr %R on %s", n->rid, ifa->ifname);
|
||||
|
||||
if (n->state < NEIGHBOR_EXCHANGE)
|
||||
return;
|
||||
|
||||
ospf_neigh_sm(n, INM_HELLOREC);
|
||||
|
||||
lsh = ps->lsh;
|
||||
init_list(&uplist);
|
||||
upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
|
||||
|
||||
lsano = (size - sizeof(struct ospf_lsreq_packet)) /
|
||||
sizeof(struct ospf_lsreq_header);
|
||||
for (i = 0; i < lsano; lsh++, i++)
|
||||
{
|
||||
u32 hid = ntohl(lsh->id);
|
||||
u32 hrt = ntohl(lsh->rt);
|
||||
u32 htype = ntohl(lsh->type);
|
||||
u32 dom = ospf_lsa_domain(htype, ifa);
|
||||
DBG("Processing requested LSA: Type: %u, ID: %R, RT: %R\n", lsh->type, hid, hrt);
|
||||
llsh = sl_alloc(upslab);
|
||||
llsh->lsh.id = hid;
|
||||
llsh->lsh.rt = hrt;
|
||||
llsh->lsh.type = htype;
|
||||
add_tail(&uplist, NODE llsh);
|
||||
if (ospf_hash_find(po->gr, dom, hid, hrt, htype) == NULL)
|
||||
OSPF_TRACE(D_PACKETS, "LSREQ packet ignored - lesser state than Exchange");
|
||||
return;
|
||||
}
|
||||
|
||||
ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */
|
||||
|
||||
ospf_lsreq_body(p, pkt, &lsrs, &lsr_count);
|
||||
|
||||
struct top_hash_entry *en, *entries[lsr_count];
|
||||
|
||||
for (i = 0; i < lsr_count; i++)
|
||||
{
|
||||
u32 id, rt, type, domain;
|
||||
|
||||
id = ntohl(lsrs[i].id);
|
||||
rt = ntohl(lsrs[i].rt);
|
||||
lsa_get_type_domain_(ntohl(lsrs[i].type), ifa, &type, &domain);
|
||||
|
||||
DBG("Processing requested LSA: Type: %04x, Id: %R, Rt: %R\n", type, id, rt);
|
||||
|
||||
en = ospf_hash_find(p->gr, domain, id, rt, type);
|
||||
if (!en)
|
||||
{
|
||||
log(L_WARN "Received bad LSREQ from %I: Type: %04x, Id: %R, Rt: %R",
|
||||
n->ip, htype, hid, hrt);
|
||||
LOG_LSA1("Bad LSR (Type: %04x, Id: %R, Rt: %R) in LSREQ", type, id, rt);
|
||||
LOG_LSA2(" received from nbr %R on %s - LSA is missing", n->rid, ifa->ifname);
|
||||
|
||||
ospf_neigh_sm(n, INM_BADLSREQ);
|
||||
rfree(upslab);
|
||||
return;
|
||||
}
|
||||
|
||||
entries[i] = en;
|
||||
}
|
||||
ospf_lsupd_send_list(n, &uplist);
|
||||
rfree(upslab);
|
||||
|
||||
ospf_send_lsupd(p, entries, lsr_count, n);
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 2000--2004 Ondrej Filip <feela@network.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_OSPF_LSREQ_H_
|
||||
#define _BIRD_OSPF_LSREQ_H_
|
||||
|
||||
void ospf_lsreq_send(struct ospf_neighbor *n);
|
||||
void ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
|
||||
struct ospf_neighbor *n);
|
||||
|
||||
#endif /* _BIRD_OSPF_LSREQ_H_ */
|
1140
proto/ospf/lsupd.c
1140
proto/ospf/lsupd.c
File diff suppressed because it is too large
Load Diff
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 2000--2004 Ondrej Filip <feela@network.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_OSPF_LSUPD_H_
|
||||
#define _BIRD_OSPF_LSUPD_H_
|
||||
|
||||
void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n);
|
||||
void ospf_dump_common(struct proto *p, struct ospf_packet *op);
|
||||
void ospf_lsupd_send_list(struct ospf_neighbor *n, list * l);
|
||||
void ospf_lsupd_receive(struct ospf_packet *ps_i,
|
||||
struct ospf_iface *ifa, struct ospf_neighbor *n);
|
||||
int ospf_lsupd_flood(struct proto_ospf *po,
|
||||
struct ospf_neighbor *n, struct ospf_lsa_header *hn,
|
||||
struct ospf_lsa_header *hh, u32 domain, int rtl);
|
||||
void ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en);
|
||||
int ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_iface *ifa);
|
||||
|
||||
|
||||
#endif /* _BIRD_OSPF_LSUPD_H_ */
|
File diff suppressed because it is too large
Load Diff
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 1999 - 2004 Ondrej Filip <feela@network.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_OSPF_NEIGHBOR_H_
|
||||
#define _BIRD_OSPF_NEIGHBOR_H_
|
||||
|
||||
struct ospf_neighbor *ospf_neighbor_new(struct ospf_iface *ifa);
|
||||
void ospf_neigh_sm(struct ospf_neighbor *n, int event);
|
||||
void bdr_election(struct ospf_iface *ifa);
|
||||
struct ospf_neighbor *find_neigh(struct ospf_iface *ifa, u32 rid);
|
||||
struct ospf_neighbor *find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip);
|
||||
void ospf_neigh_remove(struct ospf_neighbor *n);
|
||||
void ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd);
|
||||
void ospf_sh_neigh_info(struct ospf_neighbor *n);
|
||||
|
||||
#endif /* _BIRD_OSPF_NEIGHBOR_H_ */
|
1178
proto/ospf/ospf.c
1178
proto/ospf/ospf.c
File diff suppressed because it is too large
Load Diff
1625
proto/ospf/ospf.h
1625
proto/ospf/ospf.h
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,8 @@
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 1999--2005 Ondrej Filip <feela@network.cz>
|
||||
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2009--2014 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
@ -13,234 +15,196 @@
|
||||
void
|
||||
ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
|
||||
{
|
||||
struct proto_ospf *po = ifa->oa->po;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
struct ospf_packet *pkt;
|
||||
|
||||
pkt = (struct ospf_packet *) buf;
|
||||
|
||||
pkt->version = OSPF_VERSION;
|
||||
|
||||
pkt->version = ospf_get_version(p);
|
||||
pkt->type = h_type;
|
||||
|
||||
pkt->routerid = htonl(po->router_id);
|
||||
pkt->length = htons(ospf_pkt_maxsize(ifa));
|
||||
pkt->routerid = htonl(p->router_id);
|
||||
pkt->areaid = htonl(ifa->oa->areaid);
|
||||
|
||||
#ifdef OSPFv3
|
||||
pkt->instance_id = ifa->instance_id;
|
||||
#endif
|
||||
|
||||
#ifdef OSPFv2
|
||||
pkt->autype = htons(ifa->autype);
|
||||
#endif
|
||||
|
||||
pkt->checksum = 0;
|
||||
pkt->instance_id = ifa->instance_id;
|
||||
pkt->autype = ifa->autype;
|
||||
}
|
||||
|
||||
unsigned
|
||||
uint
|
||||
ospf_pkt_maxsize(struct ospf_iface *ifa)
|
||||
{
|
||||
unsigned headers = SIZE_OF_IP_HEADER;
|
||||
uint headers = SIZE_OF_IP_HEADER;
|
||||
|
||||
#ifdef OSPFv2
|
||||
/* Relevant just for OSPFv2 */
|
||||
if (ifa->autype == OSPF_AUTH_CRYPT)
|
||||
headers += OSPF_AUTH_CRYPT_SIZE;
|
||||
#endif
|
||||
|
||||
return ifa->tx_length - headers;
|
||||
}
|
||||
|
||||
#ifdef OSPFv2
|
||||
|
||||
/* We assume OSPFv2 in ospf_pkt_finalize() */
|
||||
static void
|
||||
ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
|
||||
{
|
||||
struct password_item *passwd = NULL;
|
||||
void *tail;
|
||||
struct MD5Context ctxt;
|
||||
char password[OSPF_AUTH_CRYPT_SIZE];
|
||||
union ospf_auth *auth = (void *) (pkt + 1);
|
||||
uint plen = ntohs(pkt->length);
|
||||
|
||||
pkt->checksum = 0;
|
||||
pkt->autype = htons(ifa->autype);
|
||||
bzero(&pkt->u, sizeof(union ospf_auth));
|
||||
pkt->autype = ifa->autype;
|
||||
bzero(auth, sizeof(union ospf_auth));
|
||||
|
||||
/* Compatibility note: pkt->u may contain anything if autype is
|
||||
/* Compatibility note: auth may contain anything if autype is
|
||||
none, but nonzero values do not work with Mikrotik OSPF */
|
||||
|
||||
switch(ifa->autype)
|
||||
switch (ifa->autype)
|
||||
{
|
||||
case OSPF_AUTH_SIMPLE:
|
||||
passwd = password_find(ifa->passwords, 1);
|
||||
if (!passwd)
|
||||
{
|
||||
log( L_ERR "No suitable password found for authentication" );
|
||||
return;
|
||||
}
|
||||
password_cpy(pkt->u.password, passwd->password, sizeof(union ospf_auth));
|
||||
case OSPF_AUTH_NONE:
|
||||
pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet) -
|
||||
sizeof(union ospf_auth), (pkt + 1),
|
||||
ntohs(pkt->length) -
|
||||
sizeof(struct ospf_packet), NULL);
|
||||
break;
|
||||
case OSPF_AUTH_CRYPT:
|
||||
passwd = password_find(ifa->passwords, 0);
|
||||
if (!passwd)
|
||||
{
|
||||
log( L_ERR "No suitable password found for authentication" );
|
||||
return;
|
||||
}
|
||||
case OSPF_AUTH_SIMPLE:
|
||||
passwd = password_find(ifa->passwords, 1);
|
||||
if (!passwd)
|
||||
{
|
||||
log(L_ERR "No suitable password found for authentication");
|
||||
return;
|
||||
}
|
||||
strncpy(auth->password, passwd->password, sizeof(auth->password));
|
||||
|
||||
/* Perhaps use random value to prevent replay attacks after
|
||||
reboot when system does not have independent RTC? */
|
||||
if (!ifa->csn)
|
||||
{
|
||||
ifa->csn = (u32) now;
|
||||
ifa->csn_use = now;
|
||||
}
|
||||
case OSPF_AUTH_NONE:
|
||||
{
|
||||
void *body = (void *) (auth + 1);
|
||||
uint blen = plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth);
|
||||
pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet), body, blen, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
/* We must have sufficient delay between sending a packet and increasing
|
||||
CSN to prevent reordering of packets (in a network) with different CSNs */
|
||||
if ((now - ifa->csn_use) > 1)
|
||||
ifa->csn++;
|
||||
case OSPF_AUTH_CRYPT:
|
||||
passwd = password_find(ifa->passwords, 0);
|
||||
if (!passwd)
|
||||
{
|
||||
log(L_ERR "No suitable password found for authentication");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Perhaps use random value to prevent replay attacks after
|
||||
reboot when system does not have independent RTC? */
|
||||
if (!ifa->csn)
|
||||
{
|
||||
ifa->csn = (u32) now;
|
||||
ifa->csn_use = now;
|
||||
}
|
||||
|
||||
pkt->u.md5.keyid = passwd->id;
|
||||
pkt->u.md5.len = OSPF_AUTH_CRYPT_SIZE;
|
||||
pkt->u.md5.zero = 0;
|
||||
pkt->u.md5.csn = htonl(ifa->csn);
|
||||
tail = ((void *)pkt) + ntohs(pkt->length);
|
||||
MD5Init(&ctxt);
|
||||
MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
|
||||
password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE);
|
||||
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
|
||||
MD5Final(tail, &ctxt);
|
||||
break;
|
||||
default:
|
||||
bug("Unknown authentication type");
|
||||
/* We must have sufficient delay between sending a packet and increasing
|
||||
CSN to prevent reordering of packets (in a network) with different CSNs */
|
||||
if ((now - ifa->csn_use) > 1)
|
||||
ifa->csn++;
|
||||
|
||||
ifa->csn_use = now;
|
||||
|
||||
auth->md5.zero = 0;
|
||||
auth->md5.keyid = passwd->id;
|
||||
auth->md5.len = OSPF_AUTH_CRYPT_SIZE;
|
||||
auth->md5.csn = htonl(ifa->csn);
|
||||
|
||||
void *tail = ((void *) pkt) + plen;
|
||||
char password[OSPF_AUTH_CRYPT_SIZE];
|
||||
strncpy(password, passwd->password, sizeof(password));
|
||||
|
||||
struct MD5Context ctxt;
|
||||
MD5Init(&ctxt);
|
||||
MD5Update(&ctxt, (char *) pkt, plen);
|
||||
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
|
||||
MD5Final(tail, &ctxt);
|
||||
break;
|
||||
|
||||
default:
|
||||
bug("Unknown authentication type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* We assume OSPFv2 in ospf_pkt_checkauth() */
|
||||
static int
|
||||
ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size)
|
||||
ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int len)
|
||||
{
|
||||
struct proto_ospf *po = ifa->oa->po;
|
||||
struct proto *p = &po->proto;
|
||||
struct password_item *pass = NULL, *ptmp;
|
||||
void *tail;
|
||||
char md5sum[OSPF_AUTH_CRYPT_SIZE];
|
||||
char password[OSPF_AUTH_CRYPT_SIZE];
|
||||
struct MD5Context ctxt;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
union ospf_auth *auth = (void *) (pkt + 1);
|
||||
struct password_item *pass = NULL;
|
||||
const char *err_dsc = NULL;
|
||||
uint err_val = 0;
|
||||
|
||||
uint plen = ntohs(pkt->length);
|
||||
u8 autype = pkt->autype;
|
||||
|
||||
if (pkt->autype != htons(ifa->autype))
|
||||
if (autype != ifa->autype)
|
||||
DROP("authentication method mismatch", autype);
|
||||
|
||||
switch (autype)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", ntohs(pkt->autype));
|
||||
return 0;
|
||||
}
|
||||
case OSPF_AUTH_NONE:
|
||||
return 1;
|
||||
|
||||
switch(ifa->autype)
|
||||
{
|
||||
case OSPF_AUTH_NONE:
|
||||
return 1;
|
||||
break;
|
||||
case OSPF_AUTH_SIMPLE:
|
||||
pass = password_find(ifa->passwords, 1);
|
||||
if (!pass)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: no password found");
|
||||
return 0;
|
||||
}
|
||||
password_cpy(password, pass->password, sizeof(union ospf_auth));
|
||||
case OSPF_AUTH_SIMPLE:
|
||||
pass = password_find(ifa->passwords, 1);
|
||||
if (!pass)
|
||||
DROP1("no password found");
|
||||
|
||||
if (memcmp(pkt->u.password, password, sizeof(union ospf_auth)))
|
||||
{
|
||||
char ppass[sizeof(union ospf_auth) + 1];
|
||||
bzero(ppass, (sizeof(union ospf_auth) + 1));
|
||||
memcpy(ppass, pkt->u.password, sizeof(union ospf_auth));
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: different passwords (%s)", ppass);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
break;
|
||||
case OSPF_AUTH_CRYPT:
|
||||
if (pkt->u.md5.len != OSPF_AUTH_CRYPT_SIZE)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest");
|
||||
return 0;
|
||||
}
|
||||
if (!password_verify(pass, auth->password, sizeof(auth->password)))
|
||||
DROP("wrong password", pass->id);
|
||||
|
||||
if (ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE > size)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: size mismatch (%d vs %d)",
|
||||
ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE, size);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
tail = ((void *)pkt) + ntohs(pkt->length);
|
||||
case OSPF_AUTH_CRYPT:
|
||||
if (auth->md5.len != OSPF_AUTH_CRYPT_SIZE)
|
||||
DROP("invalid MD5 digest length", auth->md5.len);
|
||||
|
||||
if (ifa->passwords)
|
||||
{
|
||||
WALK_LIST(ptmp, *(ifa->passwords))
|
||||
{
|
||||
if (pkt->u.md5.keyid != ptmp->id) continue;
|
||||
if ((ptmp->accfrom > now_real) || (ptmp->accto < now_real)) continue;
|
||||
pass = ptmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (plen + OSPF_AUTH_CRYPT_SIZE > len)
|
||||
DROP("length mismatch", len);
|
||||
|
||||
if (!pass)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: no suitable md5 password found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n)
|
||||
{
|
||||
u32 rcv_csn = ntohl(pkt->u.md5.csn);
|
||||
if(rcv_csn < n->csn)
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number (rcv %d, old %d)", rcv_csn, n->csn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n->csn = rcv_csn;
|
||||
}
|
||||
|
||||
MD5Init(&ctxt);
|
||||
MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
|
||||
password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE);
|
||||
MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
|
||||
MD5Final(md5sum, &ctxt);
|
||||
if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE))
|
||||
{
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type");
|
||||
u32 rcv_csn = ntohl(auth->md5.csn);
|
||||
if (n && (rcv_csn < n->csn))
|
||||
// DROP("lower sequence number", rcv_csn);
|
||||
{
|
||||
/* We want to report both new and old CSN */
|
||||
LOG_PKT_AUTH("Authentication failed for nbr %R on %s - "
|
||||
"lower sequence number (rcv %u, old %u)",
|
||||
n->rid, ifa->ifname, rcv_csn, n->csn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pass = password_find_by_id(ifa->passwords, auth->md5.keyid);
|
||||
if (!pass)
|
||||
DROP("no suitable password found", auth->md5.keyid);
|
||||
|
||||
void *tail = ((void *) pkt) + plen;
|
||||
char passwd[OSPF_AUTH_CRYPT_SIZE];
|
||||
char md5sum[OSPF_AUTH_CRYPT_SIZE];
|
||||
|
||||
strncpy(passwd, pass->password, OSPF_AUTH_CRYPT_SIZE);
|
||||
|
||||
struct MD5Context ctxt;
|
||||
MD5Init(&ctxt);
|
||||
MD5Update(&ctxt, (char *) pkt, plen);
|
||||
MD5Update(&ctxt, passwd, OSPF_AUTH_CRYPT_SIZE);
|
||||
MD5Final(md5sum, &ctxt);
|
||||
|
||||
if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE))
|
||||
DROP("wrong MD5 digest", pass->id);
|
||||
|
||||
if (n)
|
||||
n->csn = rcv_csn;
|
||||
|
||||
return 1;
|
||||
|
||||
default:
|
||||
bug("Unknown authentication type");
|
||||
}
|
||||
|
||||
drop:
|
||||
LOG_PKT_AUTH("Authentication failed for nbr %R on %s - %s (%u)",
|
||||
(n ? n->rid : ntohl(pkt->routerid)), ifa->ifname, err_dsc, err_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* OSPFv3 authentication not yet supported */
|
||||
|
||||
static inline void
|
||||
ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
|
||||
{ }
|
||||
|
||||
static int
|
||||
ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size)
|
||||
{ return 1; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* ospf_rx_hook
|
||||
* @sk: socket we received the packet.
|
||||
@ -251,13 +215,10 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_
|
||||
* non generic functions.
|
||||
*/
|
||||
int
|
||||
ospf_rx_hook(sock *sk, int size)
|
||||
ospf_rx_hook(sock *sk, int len)
|
||||
{
|
||||
char *mesg = "OSPF: Bad packet from ";
|
||||
|
||||
/* We want just packets from sk->iface. Unfortunately, on BSD we
|
||||
cannot filter out other packets at kernel level and we receive
|
||||
all packets on all sockets */
|
||||
/* We want just packets from sk->iface. Unfortunately, on BSD we cannot filter
|
||||
out other packets at kernel level and we receive all packets on all sockets */
|
||||
if (sk->lifindex != sk->iface->index)
|
||||
return 1;
|
||||
|
||||
@ -266,71 +227,65 @@ ospf_rx_hook(sock *sk, int size)
|
||||
|
||||
/* Initially, the packet is associated with the 'master' iface */
|
||||
struct ospf_iface *ifa = sk->data;
|
||||
struct proto_ospf *po = ifa->oa->po;
|
||||
// struct proto *p = &po->proto;
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
const char *err_dsc = NULL;
|
||||
uint err_val = 0;
|
||||
|
||||
int src_local, dst_local UNUSED, dst_mcast;
|
||||
int src_local, dst_local, dst_mcast;
|
||||
src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen);
|
||||
dst_local = ipa_equal(sk->laddr, ifa->addr->ip);
|
||||
dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, AllDRouters);
|
||||
dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, ifa->des_routers);
|
||||
|
||||
#ifdef OSPFv2
|
||||
/* First, we eliminate packets with strange address combinations.
|
||||
* In OSPFv2, they might be for other ospf_ifaces (with different IP
|
||||
* prefix) on the same real iface, so we don't log it. We enforce
|
||||
* that (src_local || dst_local), therefore we are eliminating all
|
||||
* such cases.
|
||||
*/
|
||||
if (dst_mcast && !src_local)
|
||||
return 1;
|
||||
if (!dst_mcast && !dst_local)
|
||||
return 1;
|
||||
|
||||
/* Ignore my own broadcast packets */
|
||||
if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip))
|
||||
return 1;
|
||||
#else /* OSPFv3 */
|
||||
|
||||
/* In OSPFv3, src_local and dst_local mean link-local.
|
||||
* RFC 5340 says that local (non-vlink) packets use
|
||||
* link-local src address, but does not enforce it. Strange.
|
||||
*/
|
||||
if (dst_mcast && !src_local)
|
||||
log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr);
|
||||
#endif
|
||||
|
||||
/* Second, we check packet size, checksum, and the protocol version */
|
||||
struct ospf_packet *ps = (struct ospf_packet *) ip_skip_header(sk->rbuf, &size);
|
||||
|
||||
if (ps == NULL)
|
||||
if (ospf_is_v2(p))
|
||||
{
|
||||
log(L_ERR "%s%I - bad IP header", mesg, sk->faddr);
|
||||
return 1;
|
||||
/* First, we eliminate packets with strange address combinations.
|
||||
* In OSPFv2, they might be for other ospf_ifaces (with different IP
|
||||
* prefix) on the same real iface, so we don't log it. We enforce
|
||||
* that (src_local || dst_local), therefore we are eliminating all
|
||||
* such cases.
|
||||
*/
|
||||
if (dst_mcast && !src_local)
|
||||
return 1;
|
||||
if (!dst_mcast && !dst_local)
|
||||
return 1;
|
||||
|
||||
/* Ignore my own broadcast packets */
|
||||
if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In OSPFv3, src_local and dst_local mean link-local.
|
||||
* RFC 5340 says that local (non-vlink) packets use
|
||||
* link-local src address, but does not enforce it. Strange.
|
||||
*/
|
||||
if (dst_mcast && !src_local)
|
||||
LOG_PKT_WARN("Multicast packet received from non-link-local %I via %s",
|
||||
sk->faddr, ifa->ifname);
|
||||
}
|
||||
|
||||
/* Second, we check packet length, checksum, and the protocol version */
|
||||
struct ospf_packet *pkt = (void *) sk_rx_buffer(sk, &len);
|
||||
|
||||
|
||||
if (pkt == NULL)
|
||||
DROP("bad IP header", len);
|
||||
|
||||
if (ifa->check_ttl && (sk->rcv_ttl < 255))
|
||||
{
|
||||
log(L_ERR "%s%I - TTL %d (< 255)", mesg, sk->faddr, sk->rcv_ttl);
|
||||
return 1;
|
||||
}
|
||||
DROP("wrong TTL", sk->rcv_ttl);
|
||||
|
||||
if ((unsigned) size < sizeof(struct ospf_packet))
|
||||
{
|
||||
log(L_ERR "%s%I - too short (%u bytes)", mesg, sk->faddr, size);
|
||||
return 1;
|
||||
}
|
||||
if (len < sizeof(struct ospf_packet))
|
||||
DROP("too short", len);
|
||||
|
||||
uint plen = ntohs(ps->length);
|
||||
if (pkt->version != ospf_get_version(p))
|
||||
DROP("version mismatch", pkt->version);
|
||||
|
||||
uint plen = ntohs(pkt->length);
|
||||
if ((plen < sizeof(struct ospf_packet)) || ((plen % 4) != 0))
|
||||
{
|
||||
log(L_ERR "%s%I - invalid length (%u)", mesg, sk->faddr, plen);
|
||||
return 1;
|
||||
}
|
||||
DROP("invalid length", plen);
|
||||
|
||||
if (sk->flags & SKF_TRUNCATED)
|
||||
{
|
||||
log(L_WARN "%s%I - too large (%d/%d)", mesg, sk->faddr, plen, size);
|
||||
|
||||
/* If we have dynamic buffers and received truncated message, we expand RX buffer */
|
||||
|
||||
uint bs = plen + 256;
|
||||
@ -339,168 +294,149 @@ ospf_rx_hook(sock *sk, int size)
|
||||
if (!ifa->cf->rx_buffer && (bs > sk->rbsize))
|
||||
sk_set_rbsize(sk, bs);
|
||||
|
||||
return 1;
|
||||
DROP("truncated", plen);
|
||||
}
|
||||
|
||||
if (plen > size)
|
||||
if (plen > len)
|
||||
DROP("length mismatch", plen);
|
||||
|
||||
if (ospf_is_v2(p) && (pkt->autype != OSPF_AUTH_CRYPT))
|
||||
{
|
||||
log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, plen, size);
|
||||
return 1;
|
||||
}
|
||||
uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth);
|
||||
uint blen = plen - hlen;
|
||||
void *body = ((void *) pkt) + hlen;
|
||||
|
||||
if (ps->version != OSPF_VERSION)
|
||||
{
|
||||
log(L_ERR "%s%I - version %u", mesg, sk->faddr, ps->version);
|
||||
return 1;
|
||||
if (!ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL))
|
||||
DROP1("invalid checksum");
|
||||
}
|
||||
|
||||
#ifdef OSPFv2
|
||||
if ((ps->autype != htons(OSPF_AUTH_CRYPT)) &&
|
||||
(!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet),
|
||||
plen - sizeof(struct ospf_packet), NULL)))
|
||||
{
|
||||
log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Third, we resolve associated iface and handle vlinks. */
|
||||
|
||||
u32 areaid = ntohl(ps->areaid);
|
||||
u32 rid = ntohl(ps->routerid);
|
||||
u32 areaid = ntohl(pkt->areaid);
|
||||
u32 rid = ntohl(pkt->routerid);
|
||||
u8 instance_id = pkt->instance_id;
|
||||
|
||||
if ((areaid == ifa->oa->areaid)
|
||||
#ifdef OSPFv3
|
||||
&& (ps->instance_id == ifa->instance_id)
|
||||
#endif
|
||||
)
|
||||
if (areaid == ifa->oa->areaid)
|
||||
{
|
||||
/* It is real iface, source should be local (in OSPFv2) */
|
||||
#ifdef OSPFv2
|
||||
if (!src_local)
|
||||
/* Matching area ID */
|
||||
|
||||
if (instance_id != ifa->instance_id)
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
else if (dst_mcast || (areaid != 0))
|
||||
{
|
||||
/* Obvious mismatch */
|
||||
|
||||
#ifdef OSPFv2
|
||||
/* We ignore mismatch in OSPFv3, because there might be
|
||||
other instance with different instance ID */
|
||||
log(L_ERR "%s%I - area does not match (%R vs %R)",
|
||||
mesg, sk->faddr, areaid, ifa->oa->areaid);
|
||||
#endif
|
||||
/* It is real iface, source should be local (in OSPFv2) */
|
||||
if (ospf_is_v2(p) && !src_local)
|
||||
DROP1("strange source address");
|
||||
|
||||
goto found;
|
||||
}
|
||||
else if ((areaid == 0) && !dst_mcast)
|
||||
{
|
||||
/* Backbone area ID and possible vlink packet */
|
||||
|
||||
if ((p->areano == 1) || !oa_is_ext(ifa->oa))
|
||||
return 1;
|
||||
|
||||
struct ospf_iface *iff = NULL;
|
||||
WALK_LIST(iff, p->iface_list)
|
||||
{
|
||||
if ((iff->type == OSPF_IT_VLINK) &&
|
||||
(iff->voa == ifa->oa) &&
|
||||
(iff->instance_id == instance_id) &&
|
||||
(iff->vid == rid))
|
||||
{
|
||||
/* Vlink should be UP */
|
||||
if (iff->state != OSPF_IS_PTP)
|
||||
return 1;
|
||||
|
||||
ifa = iff;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Cannot find matching vlink. It is either misconfigured vlink; NBMA or
|
||||
* PtMP with misconfigured area ID, or packet for some other instance (that
|
||||
* is possible even if instance_id == ifa->instance_id, because it may be
|
||||
* also vlink packet in the other instance, which is different namespace).
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Some vlink? */
|
||||
struct ospf_iface *iff = NULL;
|
||||
/* Non-matching area ID but cannot be vlink packet */
|
||||
|
||||
WALK_LIST(iff, po->iface_list)
|
||||
{
|
||||
if ((iff->type == OSPF_IT_VLINK) &&
|
||||
(iff->voa == ifa->oa) &&
|
||||
#ifdef OSPFv3
|
||||
(iff->instance_id == ps->instance_id) &&
|
||||
#endif
|
||||
(iff->vid == rid))
|
||||
{
|
||||
/* Vlink should be UP */
|
||||
if (iff->state != OSPF_IS_PTP)
|
||||
return 1;
|
||||
|
||||
ifa = iff;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
if (instance_id != ifa->instance_id)
|
||||
return 1;
|
||||
|
||||
#ifdef OSPFv2
|
||||
log(L_WARN "OSPF: Received packet for unknown vlink (ID %R, IP %I)", rid, sk->faddr);
|
||||
#endif
|
||||
return 1;
|
||||
DROP("area mismatch", areaid);
|
||||
}
|
||||
|
||||
found:
|
||||
|
||||
found:
|
||||
if (ifa->stub) /* This shouldn't happen */
|
||||
return 1;
|
||||
|
||||
if (ipa_equal(sk->laddr, AllDRouters) && (ifa->sk_dr == 0))
|
||||
if (ipa_equal(sk->laddr, ifa->des_routers) && (ifa->sk_dr == 0))
|
||||
return 1;
|
||||
|
||||
if (rid == po->router_id)
|
||||
{
|
||||
log(L_ERR "%s%I - received my own router ID!", mesg, sk->faddr);
|
||||
return 1;
|
||||
}
|
||||
if (rid == p->router_id)
|
||||
DROP1("my own router ID");
|
||||
|
||||
if (rid == 0)
|
||||
{
|
||||
log(L_ERR "%s%I - router id = 0.0.0.0", mesg, sk->faddr);
|
||||
return 1;
|
||||
}
|
||||
DROP1("zero router ID");
|
||||
|
||||
#ifdef OSPFv2
|
||||
/* In OSPFv2, neighbors are identified by either IP or Router ID, base on network type */
|
||||
/* In OSPFv2, neighbors are identified by either IP or Router ID, based on network type */
|
||||
uint t = ifa->type;
|
||||
struct ospf_neighbor *n;
|
||||
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
|
||||
if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP)))
|
||||
n = find_neigh_by_ip(ifa, sk->faddr);
|
||||
else
|
||||
n = find_neigh(ifa, rid);
|
||||
#else
|
||||
struct ospf_neighbor *n = find_neigh(ifa, rid);
|
||||
#endif
|
||||
|
||||
if(!n && (ps->type != HELLO_P))
|
||||
if (!n && (pkt->type != HELLO_P))
|
||||
{
|
||||
log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)",
|
||||
sk->faddr, ifa->ifname);
|
||||
OSPF_TRACE(D_PACKETS, "Non-HELLO packet received from unknown nbr %R on %s, src %I",
|
||||
rid, ifa->ifname, sk->faddr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ospf_pkt_checkauth(n, ifa, ps, size))
|
||||
{
|
||||
log(L_ERR "%s%I - authentication failed", mesg, sk->faddr);
|
||||
/* ospf_pkt_checkauth() has its own error logging */
|
||||
if (ospf_is_v2(p) && !ospf_pkt_checkauth(n, ifa, pkt, len))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Dump packet
|
||||
pu8=(u8 *)(sk->rbuf+5*4);
|
||||
for(i=0;i<ntohs(ps->length);i+=4)
|
||||
DBG("%s: received %u,%u,%u,%u\n",p->name, pu8[i+0], pu8[i+1], pu8[i+2],
|
||||
pu8[i+3]);
|
||||
DBG("%s: received size: %u\n",p->name,size);
|
||||
*/
|
||||
|
||||
switch (ps->type)
|
||||
switch (pkt->type)
|
||||
{
|
||||
case HELLO_P:
|
||||
DBG("%s: Hello received.\n", p->name);
|
||||
ospf_hello_receive(ps, ifa, n, sk->faddr);
|
||||
ospf_receive_hello(pkt, ifa, n, sk->faddr);
|
||||
break;
|
||||
|
||||
case DBDES_P:
|
||||
DBG("%s: Database description received.\n", p->name);
|
||||
ospf_dbdes_receive(ps, ifa, n);
|
||||
ospf_receive_dbdes(pkt, ifa, n);
|
||||
break;
|
||||
|
||||
case LSREQ_P:
|
||||
DBG("%s: Link state request received.\n", p->name);
|
||||
ospf_lsreq_receive(ps, ifa, n);
|
||||
ospf_receive_lsreq(pkt, ifa, n);
|
||||
break;
|
||||
|
||||
case LSUPD_P:
|
||||
DBG("%s: Link state update received.\n", p->name);
|
||||
ospf_lsupd_receive(ps, ifa, n);
|
||||
ospf_receive_lsupd(pkt, ifa, n);
|
||||
break;
|
||||
|
||||
case LSACK_P:
|
||||
DBG("%s: Link state ack received.\n", p->name);
|
||||
ospf_lsack_receive(ps, ifa, n);
|
||||
ospf_receive_lsack(pkt, ifa, n);
|
||||
break;
|
||||
|
||||
default:
|
||||
log(L_ERR "%s%I - wrong type %u", mesg, sk->faddr, ps->type);
|
||||
return 1;
|
||||
DROP("invalid packet type", pkt->type);
|
||||
};
|
||||
return 1;
|
||||
|
||||
drop:
|
||||
LOG_PKT("Bad packet from %I via %s - %s (%u)",
|
||||
sk->faddr, ifa->ifname, err_dsc, err_val);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -508,7 +444,7 @@ void
|
||||
ospf_tx_hook(sock * sk)
|
||||
{
|
||||
struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
|
||||
// struct proto *p = (struct proto *) (ifa->oa->po);
|
||||
// struct proto *p = (struct proto *) (ifa->oa->p);
|
||||
log(L_ERR "OSPF: TX hook called on %s", ifa->ifname);
|
||||
}
|
||||
*/
|
||||
@ -517,16 +453,35 @@ void
|
||||
ospf_err_hook(sock * sk, int err)
|
||||
{
|
||||
struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
|
||||
struct proto *p = &(ifa->oa->po->proto);
|
||||
log(L_ERR "%s: Socket error on %s: %M", p->name, ifa->ifname, err);
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
log(L_ERR "%s: Socket error on %s: %M", p->p.name, ifa->ifname, err);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_verr_hook(sock *sk, int err)
|
||||
{
|
||||
struct proto_ospf *po = (struct proto_ospf *) (sk->data);
|
||||
struct proto *p = &po->proto;
|
||||
log(L_ERR "%s: Vlink socket error: %M", p->name, err);
|
||||
struct ospf_proto *p = (struct ospf_proto *) (sk->data);
|
||||
log(L_ERR "%s: Vlink socket error: %M", p->p.name, err);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
|
||||
{
|
||||
sock *sk = ifa->sk;
|
||||
struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
|
||||
int plen = ntohs(pkt->length);
|
||||
|
||||
if (ospf_is_v2(ifa->oa->po))
|
||||
{
|
||||
if (ifa->autype == OSPF_AUTH_CRYPT)
|
||||
plen += OSPF_AUTH_CRYPT_SIZE;
|
||||
|
||||
ospf_pkt_finalize(ifa, pkt);
|
||||
}
|
||||
|
||||
int done = sk_send_to(sk, plen, dst, 0);
|
||||
if (!done)
|
||||
log(L_WARN "OSPF: TX queue full on %s", ifa->ifname);
|
||||
}
|
||||
|
||||
void
|
||||
@ -542,28 +497,8 @@ ospf_send_to_agt(struct ospf_iface *ifa, u8 state)
|
||||
void
|
||||
ospf_send_to_bdr(struct ospf_iface *ifa)
|
||||
{
|
||||
if (!ipa_equal(ifa->drip, IPA_NONE))
|
||||
if (ipa_nonzero(ifa->drip))
|
||||
ospf_send_to(ifa, ifa->drip);
|
||||
if (!ipa_equal(ifa->bdrip, IPA_NONE))
|
||||
if (ipa_nonzero(ifa->bdrip))
|
||||
ospf_send_to(ifa, ifa->bdrip);
|
||||
}
|
||||
|
||||
void
|
||||
ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
|
||||
{
|
||||
sock *sk = ifa->sk;
|
||||
struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
|
||||
int len = ntohs(pkt->length);
|
||||
|
||||
#ifdef OSPFv2
|
||||
if (ifa->autype == OSPF_AUTH_CRYPT)
|
||||
len += OSPF_AUTH_CRYPT_SIZE;
|
||||
#endif
|
||||
|
||||
ospf_pkt_finalize(ifa, pkt);
|
||||
|
||||
int done = sk_send_to(sk, len, dst, 0);
|
||||
if (!done)
|
||||
log(L_WARN "OSPF: TX queue full on %s", ifa->ifname);
|
||||
}
|
||||
|
||||
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 1999--2004 Ondrej Filip <feela@network.cz>
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_OSPF_PACKET_H_
|
||||
#define _BIRD_OSPF_PACKET_H_
|
||||
|
||||
void ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type);
|
||||
uint ospf_pkt_maxsize(struct ospf_iface *ifa);
|
||||
int ospf_rx_hook(sock * sk, int size);
|
||||
// void ospf_tx_hook(sock * sk);
|
||||
void ospf_err_hook(sock * sk, int err);
|
||||
void ospf_verr_hook(sock *sk, int err);
|
||||
void ospf_send_to_agt(struct ospf_iface *ifa, u8 state);
|
||||
void ospf_send_to_bdr(struct ospf_iface *ifa);
|
||||
void ospf_send_to(struct ospf_iface *ifa, ip_addr ip);
|
||||
|
||||
static inline void ospf_send_to_all(struct ospf_iface *ifa) { ospf_send_to(ifa, ifa->all_routers); }
|
||||
|
||||
static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; }
|
||||
|
||||
|
||||
#endif /* _BIRD_OSPF_PACKET_H_ */
|
1066
proto/ospf/rt.c
1066
proto/ospf/rt.c
File diff suppressed because it is too large
Load Diff
@ -2,17 +2,18 @@
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 2000--2004 Ondrej Filip <feela@network.cz>
|
||||
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2009--2014 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_OSPF_RT_H_
|
||||
#define _BIRD_OSPF_RT_H_
|
||||
|
||||
#define ORT_UNDEF -1
|
||||
#define ORT_ROUTER 1
|
||||
|
||||
#define ORT_NET 0
|
||||
#define ORT_ROUTER 1
|
||||
|
||||
typedef struct orta
|
||||
{
|
||||
@ -28,12 +29,17 @@ typedef struct orta
|
||||
#define ORTA_ASBR OPT_RT_E
|
||||
#define ORTA_ABR OPT_RT_B
|
||||
/*
|
||||
* For ORT_NET routes, the field is almost unused with one
|
||||
* exception: ORTA_PREF for external routes means that the route is
|
||||
* preferred in AS external route selection according to 16.4.1. -
|
||||
* it is intra-area path using non-backbone area. In other words,
|
||||
* the forwarding address (or ASBR if forwarding address is zero) is
|
||||
* intra-area (type == RTS_OSPF) and its area is not a backbone.
|
||||
* For ORT_NET routes, there are just several flags for external routes:
|
||||
*
|
||||
* ORTA_PREF for external routes means that the route is preferred in AS
|
||||
* external route selection according to 16.4.1. - it is intra-area path using
|
||||
* non-backbone area. In other words, the forwarding address (or ASBR if
|
||||
* forwarding address is zero) is intra-area (type == RTS_OSPF) and its area
|
||||
* is not a backbone.
|
||||
*
|
||||
* ORTA_NSSA means that the entry represents an NSSA route, and ORTA_PROP
|
||||
* means that the NSSA route has propagate-bit set. These flags are used in
|
||||
* NSSA translation.
|
||||
*/
|
||||
#define ORTA_PREF 0x80000000
|
||||
#define ORTA_NSSA 0x40000000
|
||||
@ -54,31 +60,35 @@ orta;
|
||||
typedef struct ort
|
||||
{
|
||||
/*
|
||||
* We use fn.x0 to mark persistent rt entries, that are needed for summary
|
||||
* LSAs that don't have 'proper' rt entry (area networks + default to stubs)
|
||||
* to keep uid stable (used for LSA ID in OSPFv3 - see fibnode_to_lsaid()).
|
||||
* Most OSPF routing table entries are for computed OSPF routes, these have
|
||||
* defined n.type. There are also few other cases: entries for configured area
|
||||
* networks (these have area_net field set) and entries for external routes
|
||||
* exported to OSPF (these have external_rte field set). These entries are
|
||||
* kept even if they do not contain 'proper' rt entry. That is needed to keep
|
||||
* allocated stable UID numbers (fn.uid), which are used as LSA IDs in OSPFv3
|
||||
* (see fibnode_to_lsaid()) for related LSAs (network summary LSAs in the
|
||||
* first case, external or NSSA LSAs in the second case). Entries for external
|
||||
* routes also have a second purpose - to prevent NSSA translation of received
|
||||
* NSSA routes if regular external routes were already originated for the same
|
||||
* network (see check_nssa_lsa()).
|
||||
*
|
||||
* We use fn.x1 to note whether the external route was originated
|
||||
* from the route export (in ospf_rt_notify()) or from the NSSA
|
||||
* route translation (in check_nssa_lsa()).
|
||||
*
|
||||
* old_* values are here to represent the last route update. old_rta
|
||||
* is cached (we keep reference), mainly for multipath nexthops.
|
||||
* old_rta == NULL means route wasn not in the last update, in that
|
||||
* case other old_* values are not valid.
|
||||
* old_* values are here to represent the last route update. old_rta is cached
|
||||
* (we keep reference), mainly for multipath nexthops. old_rta == NULL means
|
||||
* route was not in the last update, in that case other old_* values are not
|
||||
* valid.
|
||||
*/
|
||||
struct fib_node fn;
|
||||
orta n;
|
||||
u32 old_metric1, old_metric2, old_tag, old_rid;
|
||||
rta *old_rta;
|
||||
u8 external_rte;
|
||||
u8 area_net;
|
||||
}
|
||||
ort;
|
||||
|
||||
static inline int rt_is_nssa(ort *nf)
|
||||
{ return nf->n.options & ORTA_NSSA; }
|
||||
|
||||
#define EXT_EXPORT 1
|
||||
#define EXT_NSSA 2
|
||||
|
||||
/*
|
||||
* Invariants for structs top_hash_entry (nodes of LSA db)
|
||||
@ -90,7 +100,7 @@ static inline int rt_is_nssa(ort *nf)
|
||||
* - beware, nhs is not valid after SPF calculation
|
||||
*
|
||||
* Invariants for structs orta nodes of fib tables po->rtf, oa->rtr:
|
||||
* - nodes may be invalid (fn.type == 0), in that case other invariants don't hold
|
||||
* - nodes may be invalid (n.type == 0), in that case other invariants don't hold
|
||||
* - n.metric1 may be at most a small multiple of LSINFINITY,
|
||||
* therefore sums do not overflow
|
||||
* - n.oa is always non-NULL
|
||||
@ -114,7 +124,7 @@ static inline int rt_is_nssa(ort *nf)
|
||||
* appear in ASBR pre-selection and external routes processing.
|
||||
*/
|
||||
|
||||
void ospf_rt_spf(struct proto_ospf *po);
|
||||
void ospf_rt_spf(struct ospf_proto *p);
|
||||
void ospf_rt_initort(struct fib_node *fn);
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,8 @@
|
||||
* BIRD -- OSPF
|
||||
*
|
||||
* (c) 1999--2004 Ondrej Filip <feela@network.cz>
|
||||
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2009--2014 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
@ -16,79 +18,204 @@ struct top_hash_entry
|
||||
in intra-area routing table calculation */
|
||||
struct top_hash_entry *next; /* Next in hash chain */
|
||||
struct ospf_lsa_header lsa;
|
||||
u16 lsa_type; /* lsa.type processed and converted to common values (LSA_T_*) */
|
||||
u16 init_age; /* Initial value for lsa.age during inst_time */
|
||||
u32 domain; /* Area ID for area-wide LSAs, Iface ID for link-wide LSAs */
|
||||
// struct ospf_area *oa;
|
||||
void *lsa_body;
|
||||
bird_clock_t inst_t; /* Time of installation into DB */
|
||||
void *lsa_body; /* May be NULL if LSA was flushed but hash entry was kept */
|
||||
void *next_lsa_body; /* For postponed LSA origination */
|
||||
u16 next_lsa_blen; /* For postponed LSA origination */
|
||||
u16 next_lsa_opts; /* For postponed LSA origination */
|
||||
bird_clock_t inst_time; /* Time of installation into DB */
|
||||
struct ort *nf; /* Reference fibnode for sum and ext LSAs, NULL for otherwise */
|
||||
struct mpnh *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */
|
||||
ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */
|
||||
#ifdef OSPFv3
|
||||
u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */
|
||||
#endif
|
||||
u32 dist; /* Distance from the root */
|
||||
u16 ini_age;
|
||||
int ret_count; /* Number of retransmission lists referencing the entry */
|
||||
u8 color;
|
||||
#define OUTSPF 0
|
||||
#define CANDIDATE 1
|
||||
#define INSPF 2
|
||||
u8 mode; /* LSA generated during RT calculation (LSA_RTCALC or LSA_STALE)*/
|
||||
u8 nhs_reuse; /* Whether nhs nodes can be reused during merging.
|
||||
See a note in rt.c:merge_nexthops() */
|
||||
};
|
||||
|
||||
|
||||
/* Prevents ospf_hash_find() to ignore the entry, for p->lsrqh and p->lsrth */
|
||||
#define LSA_BODY_DUMMY ((void *) 1)
|
||||
|
||||
/*
|
||||
* LSA entry life cycle
|
||||
*
|
||||
* LSA entries are created by ospf_originate_lsa() (for locally originated LSAs)
|
||||
* or ospf_install_lsa() (for LSAs received from neighbors). A regular (like
|
||||
* newly originated) LSA entry has defined lsa_body nad lsa.age < %LSA_MAXAGE.
|
||||
* When the LSA is requested to be flushed by ospf_flush_lsa(), the lsa.age is
|
||||
* set to %LSA_MAXAGE and flooded. Flush process is finished asynchronously,
|
||||
* when (at least) flooding is acknowledged by neighbors. This is detected in
|
||||
* ospf_update_lsadb(), then ospf_clear_lsa() is called to free the LSA body but
|
||||
* the LSA entry is kept. Such LSA does not formally exist, we keep an empty
|
||||
* entry (until regular timeout) to know inst_time and lsa.sn in the case of
|
||||
* later reorigination. After the timeout, LSA is removed by ospf_remove_lsa().
|
||||
*
|
||||
* When LSA origination is requested (by ospf_originate_lsa()). but it is not
|
||||
* possible to do that immediately (because of MinLSInterval or because the
|
||||
* sequence number is wrapping), The new LSA is scheduled for later origination
|
||||
* in next_lsa_* fields of the LSA entry. The later origination is handled by
|
||||
* ospf_originate_next_lsa() called from ospf_update_lsadb(). We can see that
|
||||
* both real origination and final flush is asynchronous to ospf_originate_lsa()
|
||||
* and ospf_flush_lsa().
|
||||
*
|
||||
* LSA entry therefore could be in three basic states:
|
||||
* R - regular (lsa.age < %LSA_MAXAGE, lsa_body != NULL)
|
||||
* F - flushing (lsa.age == %LSA_MAXAGE, lsa_body != NULL)
|
||||
* E - empty (lsa.age == %LSA_MAXAGE, lsa_body == NULL)
|
||||
*
|
||||
* And these states are doubled based on whether the next LSA is scheduled
|
||||
* (next_lsa_body != NULL, -n suffix) or not (next_lsa_body == NULL). We also
|
||||
* use X for a state of non-existentce. We have this basic state graph
|
||||
* (transitions from any state to R are omitted for clarity):
|
||||
*
|
||||
* X --> R ---> F ---> E --> X
|
||||
* | \ / | |
|
||||
* | \/ | |
|
||||
* | /\ | |
|
||||
* | / \ | |
|
||||
* Rn --> Fn --> En
|
||||
*
|
||||
* The transitions are:
|
||||
*
|
||||
* any state -> R - new LSA origination requested and executed
|
||||
* R -> Rn, F -> Fn, E -> En - new LSA origination requested and postponed
|
||||
* R -> Fn - new LSA origination requested, seqnum wrapping
|
||||
* Rn,Fn,En -> R - postponed LSA finally originated
|
||||
* R -> R - LSA refresh done
|
||||
* R -> Fn - LSA refresh with seqnum wrapping
|
||||
* R -> F, Rn -> Fn - LSA age timeout
|
||||
* R,Rn,Fn -> F, En -> E - LSA flush requested
|
||||
* F -> E, Fn -> En - LSA flush done (acknowledged)
|
||||
* E -> X - LSA real age timeout (or immediate for received LSA)
|
||||
*
|
||||
* The 'origination requested' and 'flush requested' transitions are triggered
|
||||
* and done by ospf_originate_lsa() and ospf_flush_lsa(), the rest is handled
|
||||
* asynchronously by ospf_update_lsadb().
|
||||
*
|
||||
* The situation is significantly simpler for non-local (received) LSAs - there
|
||||
* is no postponed origination and after flushing is done, LSAs are immediately
|
||||
* removed, so it is just X -> R -> F -> X, or X -> F -> X (when MaxAge LSA is
|
||||
* received).
|
||||
*
|
||||
* There are also some special cases related to handling of received unknown
|
||||
* self-originated LSAs in ospf_advance_lsa():
|
||||
* X -> F - LSA is received and immediately flushed
|
||||
* R,Rn -> Fn - LSA with MaxSeqNo received and flushed, current LSA scheduled
|
||||
*/
|
||||
|
||||
|
||||
#define LSA_M_BASIC 0
|
||||
#define LSA_M_EXPORT 1
|
||||
#define LSA_M_RTCALC 2
|
||||
#define LSA_M_STALE 3
|
||||
|
||||
/*
|
||||
* LSA entry modes:
|
||||
*
|
||||
* LSA_M_BASIC - The LSA is explicitly originated using ospf_originate_lsa() and
|
||||
* explicitly flushed using ospf_flush_lsa(). When the LSA is changed, the
|
||||
* routing table calculation is scheduled. This is also the mode used for LSAs
|
||||
* received from neighbors. Example: Router-LSAs, Network-LSAs.
|
||||
*
|
||||
* LSA_M_EXPORT - like LSA_M_BASIC, but the routing table calculation does not
|
||||
* depend on the LSA. Therefore, the calculation is not scheduled when the LSA
|
||||
* is changed. Example: AS-external-LSAs for exported routes.
|
||||
*
|
||||
* LSA_M_RTCALC - The LSA has to be requested using ospf_originate_lsa() during
|
||||
* each routing table calculation, otherwise it is flushed automatically at the
|
||||
* end of the calculation. The LSA is a result of the calculation and not a
|
||||
* source for it. Therefore, the calculation is not scheduled when the LSA is
|
||||
* changed. Example: Summary-LSAs.
|
||||
*
|
||||
* LSA_M_STALE - Temporary state for LSA_M_RTCALC that is not requested during
|
||||
* the current routing table calculation.
|
||||
*
|
||||
*
|
||||
* Note that we do not schedule the routing table calculation when the age of
|
||||
* LSA_M_BASIC LSA is changed to MaxAge because of the sequence number wrapping,
|
||||
* As it will be switched back to a regular one ASAP.
|
||||
*/
|
||||
|
||||
|
||||
struct top_graph
|
||||
{
|
||||
pool *pool; /* Pool we allocate from */
|
||||
slab *hash_slab; /* Slab for hash entries */
|
||||
struct top_hash_entry **hash_table; /* Hashing (modelled a`la fib) */
|
||||
unsigned int hash_size;
|
||||
unsigned int hash_order;
|
||||
unsigned int hash_mask;
|
||||
unsigned int hash_entries;
|
||||
unsigned int hash_entries_min, hash_entries_max;
|
||||
uint ospf2; /* Whether it is for OSPFv2 or OSPFv3 */
|
||||
uint hash_size;
|
||||
uint hash_order;
|
||||
uint hash_mask;
|
||||
uint hash_entries;
|
||||
uint hash_entries_min, hash_entries_max;
|
||||
};
|
||||
|
||||
struct top_graph *ospf_top_new(pool *);
|
||||
void ospf_top_free(struct top_graph *);
|
||||
void ospf_top_dump(struct top_graph *, struct proto *);
|
||||
u32 ospf_lsa_domain(u32 type, struct ospf_iface *ifa);
|
||||
struct top_hash_entry *ospf_hash_find_header(struct top_graph *f, u32 domain,
|
||||
struct ospf_lsa_header *h);
|
||||
struct top_hash_entry *ospf_hash_get_header(struct top_graph *f, u32 domain,
|
||||
struct ospf_lsa_header *h);
|
||||
|
||||
struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr,
|
||||
u32 type);
|
||||
struct top_hash_entry *ospf_hash_get(struct top_graph *, u32 domain, u32 lsa, u32 rtr,
|
||||
u32 type);
|
||||
void ospf_hash_delete(struct top_graph *, struct top_hash_entry *);
|
||||
void originate_rt_lsa(struct ospf_area *oa);
|
||||
void update_rt_lsa(struct ospf_area *oa);
|
||||
void originate_net_lsa(struct ospf_iface *ifa);
|
||||
void update_net_lsa(struct ospf_iface *ifa);
|
||||
void update_link_lsa(struct ospf_iface *ifa);
|
||||
int can_flush_lsa(struct proto_ospf *po);
|
||||
|
||||
void originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric);
|
||||
void originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32 options UNUSED);
|
||||
void flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type);
|
||||
void originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, u32 metric, ip_addr fwaddr, u32 tag, int pbit);
|
||||
void flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int nssa);
|
||||
|
||||
|
||||
#ifdef OSPFv2
|
||||
struct top_hash_entry * ospf_hash_find_net(struct top_graph *f, u32 domain, u32 lsa);
|
||||
|
||||
static inline struct top_hash_entry *
|
||||
ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr)
|
||||
struct ospf_new_lsa
|
||||
{
|
||||
return ospf_hash_find(f, domain, rtr, rtr, LSA_T_RT);
|
||||
}
|
||||
u16 type;
|
||||
u8 mode;
|
||||
u32 dom;
|
||||
u32 id;
|
||||
u16 opts;
|
||||
u16 length;
|
||||
struct ospf_iface *ifa;
|
||||
struct ort *nf;
|
||||
};
|
||||
|
||||
struct top_graph *ospf_top_new(struct ospf_proto *p, pool *pool);
|
||||
void ospf_top_free(struct top_graph *f);
|
||||
|
||||
struct top_hash_entry * ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body);
|
||||
struct top_hash_entry * ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa);
|
||||
void ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_lsa_header *lsa, u32 type, u32 domain, void *body);
|
||||
void ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en);
|
||||
void ospf_update_lsadb(struct ospf_proto *p);
|
||||
|
||||
static inline void ospf_flush2_lsa(struct ospf_proto *p, struct top_hash_entry **en)
|
||||
{ if (*en) { ospf_flush_lsa(p, *en); *en = NULL; } }
|
||||
|
||||
void ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric);
|
||||
void ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric, u32 options);
|
||||
void ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit);
|
||||
|
||||
void ospf_rt_notify(struct proto *P, rtable *tbl, net *n, rte *new, rte *old, ea_list *attrs);
|
||||
void ospf_update_topology(struct ospf_proto *p);
|
||||
|
||||
struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr, u32 type);
|
||||
struct top_hash_entry *ospf_hash_get(struct top_graph *, u32 domain, u32 lsa, u32 rtr, u32 type);
|
||||
void ospf_hash_delete(struct top_graph *, struct top_hash_entry *);
|
||||
|
||||
static inline struct top_hash_entry * ospf_hash_find_entry(struct top_graph *f, struct top_hash_entry *en)
|
||||
{ return ospf_hash_find(f, en->domain, en->lsa.id, en->lsa.rt, en->lsa_type); }
|
||||
|
||||
static inline struct top_hash_entry * ospf_hash_get_entry(struct top_graph *f, struct top_hash_entry *en)
|
||||
{ return ospf_hash_get(f, en->domain, en->lsa.id, en->lsa.rt, en->lsa_type); }
|
||||
|
||||
#else /* OSPFv3 */
|
||||
struct top_hash_entry * ospf_hash_find_rt(struct top_graph *f, u32 domain, u32 rtr);
|
||||
struct top_hash_entry * ospf_hash_find_rt_first(struct top_graph *f, u32 domain, u32 rtr);
|
||||
struct top_hash_entry * ospf_hash_find_rt_next(struct top_hash_entry *e);
|
||||
#endif
|
||||
struct top_hash_entry * ospf_hash_find_rt3_first(struct top_graph *f, u32 domain, u32 rtr);
|
||||
struct top_hash_entry * ospf_hash_find_rt3_next(struct top_hash_entry *e);
|
||||
|
||||
struct top_hash_entry * ospf_hash_find_net2(struct top_graph *f, u32 domain, u32 id);
|
||||
|
||||
/* In OSPFv2, id is network IP prefix (lsa.id) while lsa.rt field is unknown
|
||||
In OSPFv3, id is lsa.rt of DR while nif is neighbor iface id (lsa.id) */
|
||||
static inline struct top_hash_entry *
|
||||
ospf_hash_find_net(struct top_graph *f, u32 domain, u32 id, u32 nif)
|
||||
{
|
||||
return f->ospf2 ?
|
||||
ospf_hash_find_net2(f, domain, id) :
|
||||
ospf_hash_find(f, domain, nif, id, LSA_T_NET);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _BIRD_OSPF_TOPOLOGY_H_ */
|
||||
|
@ -343,7 +343,7 @@ radv_send_ra(struct radv_iface *ifa, int shutdown)
|
||||
}
|
||||
|
||||
RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
|
||||
sk_send_to(ifa->sk, ifa->plen, AllNodes, 0);
|
||||
sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -432,7 +432,7 @@ radv_sk_open(struct radv_iface *ifa)
|
||||
if (sk_setup_multicast(sk) < 0)
|
||||
goto err;
|
||||
|
||||
if (sk_join_group(sk, AllRouters) < 0)
|
||||
if (sk_join_group(sk, IP6_ALL_ROUTERS) < 0)
|
||||
goto err;
|
||||
|
||||
ifa->sk = sk;
|
||||
|
@ -26,9 +26,6 @@
|
||||
|
||||
#define ICMPV6_PROTO 58
|
||||
|
||||
#define AllNodes _MI(0xFF020000, 0, 0, 1) /* FF02::1 */
|
||||
#define AllRouters _MI(0xFF020000, 0, 0, 2) /* FF02::2 */
|
||||
|
||||
#define ICMPV6_RS 133
|
||||
#define ICMPV6_RA 134
|
||||
|
||||
|
@ -95,7 +95,7 @@ rip_incoming_authentication( struct proto *p, struct rip_block_auth *block, stru
|
||||
}
|
||||
|
||||
memcpy(md5sum_packet, tail->md5, 16);
|
||||
password_cpy(tail->md5, pass->password, 16);
|
||||
strncpy(tail->md5, pass->password, 16);
|
||||
|
||||
MD5Init(&ctxt);
|
||||
MD5Update(&ctxt, (char *) packet, ntohs(block->packetlen) + sizeof(struct rip_block_auth) );
|
||||
@ -131,7 +131,7 @@ rip_outgoing_authentication( struct proto *p, struct rip_block_auth *block, stru
|
||||
block->mustbeFFFF = 0xffff;
|
||||
switch (P_CF->authtype) {
|
||||
case AT_PLAINTEXT:
|
||||
password_cpy( (char *) (&block->packetlen), passwd->password, 16);
|
||||
strncpy( (char *) (&block->packetlen), passwd->password, 16);
|
||||
return PACKETLEN(num);
|
||||
case AT_MD5:
|
||||
{
|
||||
@ -156,7 +156,7 @@ rip_outgoing_authentication( struct proto *p, struct rip_block_auth *block, stru
|
||||
tail->mustbeFFFF = 0xffff;
|
||||
tail->mustbe0001 = 0x0100;
|
||||
|
||||
password_cpy(tail->md5, passwd->password, 16);
|
||||
strncpy(tail->md5, passwd->password, 16);
|
||||
MD5Init(&ctxt);
|
||||
MD5Update(&ctxt, (char *) packet, PACKETLEN(num) + sizeof(struct rip_md5_tail));
|
||||
MD5Final(tail->md5, &ctxt);
|
||||
|
@ -305,7 +305,7 @@ advertise_entry( struct proto *p, struct rip_block *b, ip_addr whotoldme, struct
|
||||
A.flags = 0;
|
||||
#ifndef IPV6
|
||||
A.gw = ipa_nonzero(b->nexthop) ? b->nexthop : whotoldme;
|
||||
pxlen = ipa_mklen(b->netmask);
|
||||
pxlen = ipa_masklen(b->netmask);
|
||||
#else
|
||||
/* FIXME: next hop is in other packet for v6 */
|
||||
A.gw = whotoldme;
|
||||
@ -365,7 +365,7 @@ process_block( struct proto *p, struct rip_block *block, ip_addr whotoldme, stru
|
||||
|
||||
#ifndef IPV6
|
||||
metric = ntohl( block->metric );
|
||||
pxlen = ipa_mklen(block->netmask);
|
||||
pxlen = ipa_masklen(block->netmask);
|
||||
#else
|
||||
metric = block->metric;
|
||||
pxlen = block->pxlen;
|
||||
@ -447,7 +447,7 @@ rip_process_packet( struct proto *p, struct rip_packet *packet, int num, ip_addr
|
||||
ipa_ntoh( block->netmask );
|
||||
ipa_ntoh( block->nexthop );
|
||||
if (packet->heading.version == RIP_V1) /* FIXME (nonurgent): switch to disable this? */
|
||||
block->netmask = ipa_class_mask(block->network);
|
||||
block->netmask = ip4_class_mask(ipa_to_ip4(block->network));
|
||||
#endif
|
||||
process_block( p, block, whotoldme, iface );
|
||||
}
|
||||
@ -721,7 +721,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_
|
||||
#ifndef IPV6
|
||||
rif->sock->daddr = ipa_from_u32(0xe0000009);
|
||||
#else
|
||||
rif->sock->daddr = ipa_build(0xff020000, 0, 0, 9);
|
||||
rif->sock->daddr = IP6_RIP_ROUTERS;
|
||||
#endif
|
||||
} else {
|
||||
rif->sock->daddr = new->addr->brd;
|
||||
@ -812,7 +812,7 @@ rip_if_notify(struct proto *p, unsigned c, struct iface *iface)
|
||||
#ifndef IPV6
|
||||
lock->addr = ipa_from_u32(0xe0000009);
|
||||
#else
|
||||
ip_pton("FF02::9", &lock->addr);
|
||||
lock->addr = IP6_RIP_ROUTERS;
|
||||
#endif
|
||||
else
|
||||
lock->addr = iface->addr->brd;
|
||||
|
@ -382,7 +382,7 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
|
||||
if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
|
||||
SKIP("strange class/scope\n");
|
||||
|
||||
int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_mklen(imask);
|
||||
int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_masklen(imask);
|
||||
if (pxlen < 0)
|
||||
{ log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
|
||||
|
||||
@ -653,7 +653,7 @@ krt_read_addr(struct ks_msg *msg, int scan)
|
||||
ibrd = ipa_from_sa(&brd);
|
||||
|
||||
|
||||
if ((masklen = ipa_mklen(imask)) < 0)
|
||||
if ((masklen = ipa_masklen(imask)) < 0)
|
||||
{
|
||||
log(L_ERR "KIF: Invalid masklen %I for %s", imask, iface->name);
|
||||
return;
|
||||
|
@ -7,7 +7,7 @@
|
||||
#define _BIRD_CONFIG_H_
|
||||
|
||||
/* BIRD version */
|
||||
#define BIRD_VERSION "1.4.5"
|
||||
#define BIRD_VERSION "1.5.0pre"
|
||||
|
||||
/* Include parameters determined by configure script */
|
||||
#include "sysdep/autoconf.h"
|
||||
|
@ -764,6 +764,29 @@ sk_set_tos6(sock *s, int tos)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline byte *
|
||||
sk_skip_ip_header(byte *pkt, int *len)
|
||||
{
|
||||
if ((*len < 20) || ((*pkt & 0xf0) != 0x40))
|
||||
return NULL;
|
||||
|
||||
int hlen = (*pkt & 0x0f) * 4;
|
||||
if ((hlen < 20) || (hlen > *len))
|
||||
return NULL;
|
||||
|
||||
*len -= hlen;
|
||||
return pkt + hlen;
|
||||
}
|
||||
|
||||
byte *
|
||||
sk_rx_buffer(sock *s, int *len)
|
||||
{
|
||||
if (sk_is_ipv4(s) && (s->type == SK_IP))
|
||||
return sk_skip_ip_header(s->rbuf, len);
|
||||
else
|
||||
return s->rbuf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Public socket functions
|
||||
|
@ -34,6 +34,12 @@ extern bird_clock_t now; /* Relative, monotonic time in seconds */
|
||||
extern bird_clock_t now_real; /* Time in seconds since fixed known epoch */
|
||||
extern bird_clock_t boot_time;
|
||||
|
||||
static inline int
|
||||
tm_active(timer *t)
|
||||
{
|
||||
return t->expires != 0;
|
||||
}
|
||||
|
||||
static inline bird_clock_t
|
||||
tm_remains(timer *t)
|
||||
{
|
||||
|
@ -47,19 +47,9 @@ typedef struct sockaddr_bird {
|
||||
|
||||
#ifdef IPV6
|
||||
#define BIRD_AF AF_INET6
|
||||
#define _MI6(x1,x2,x3,x4) _MI(x1, x2, x3, x4)
|
||||
#define ipa_is_link_local(x) ipa_has_link_scope(x)
|
||||
#define ipa_from_sa(x) ipa_from_sa6(x)
|
||||
#define ipa_from_u32(x) _MI6(0,0,0xffff,x)
|
||||
#define ipa_to_u32(x) _I3(x)
|
||||
#else
|
||||
#define BIRD_AF AF_INET
|
||||
#define _I0(X) 0
|
||||
#define _I1(X) 0
|
||||
#define _I2(X) 0
|
||||
#define _I3(X) 0
|
||||
#define _MI6(x1,x2,x3,x4) IPA_NONE
|
||||
#define ipa_is_link_local(x) 0
|
||||
#define ipa_from_sa(x) ipa_from_sa4(x)
|
||||
#endif
|
||||
|
||||
@ -75,7 +65,7 @@ static inline ip_addr ipa_from_in4(struct in_addr a)
|
||||
{ return ipa_from_u32(ntohl(a.s_addr)); }
|
||||
|
||||
static inline ip_addr ipa_from_in6(struct in6_addr a)
|
||||
{ return _MI6(ntohl(a.s6_addr32[0]), ntohl(a.s6_addr32[1]), ntohl(a.s6_addr32[2]), ntohl(a.s6_addr32[3])); }
|
||||
{ return ipa_build6(ntohl(a.s6_addr32[0]), ntohl(a.s6_addr32[1]), ntohl(a.s6_addr32[2]), ntohl(a.s6_addr32[3])); }
|
||||
|
||||
static inline ip_addr ipa_from_sa4(sockaddr *sa)
|
||||
{ return ipa_from_in4(((struct sockaddr_in *) sa)->sin_addr); }
|
||||
@ -86,8 +76,14 @@ static inline ip_addr ipa_from_sa6(sockaddr *sa)
|
||||
static inline struct in_addr ipa_to_in4(ip_addr a)
|
||||
{ return (struct in_addr) { htonl(ipa_to_u32(a)) }; }
|
||||
|
||||
#ifdef IPV6
|
||||
static inline struct in6_addr ipa_to_in6(ip_addr a)
|
||||
{ return (struct in6_addr) { .s6_addr32 = { htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a)) } }; }
|
||||
#else
|
||||
/* Temporary dummy */
|
||||
static inline struct in6_addr ipa_to_in6(ip_addr a)
|
||||
{ return (struct in6_addr) { .s6_addr32 = { 0, 0, 0, 0 } }; }
|
||||
#endif
|
||||
|
||||
void sockaddr_fill(sockaddr *sa, int af, ip_addr a, struct iface *ifa, uint port);
|
||||
int sockaddr_read(sockaddr *sa, int af, ip_addr *a, struct iface **ifa, uint *port);
|
||||
|
Loading…
Reference in New Issue
Block a user