0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-09-19 11:55:21 +00:00

Merge remote-tracking branch 'origin/soft-int'

This commit is contained in:
Ondrej Zajicek 2015-02-21 11:39:45 +01:00
commit 7730553b7e
60 changed files with 7239 additions and 7240 deletions

4
NEWS
View File

@ -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.

View File

@ -124,22 +124,24 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
}
{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
#ifdef IPV6
if (ipv4_pton_u32(yytext, &cf_lval.i32))
return RTRID;
ip4_addr a;
if (!ip4_pton(yytext, &a))
cf_error("Invalid IPv4 address %s", yytext);
#ifdef IPV6
cf_lval.i32 = ip4_to_u32(a);
return RTRID;
#else
if (ip_pton(yytext, &cf_lval.a))
cf_lval.a = ipa_from_ip4(a);
return IPA;
cf_error("Invalid IP address %s", yytext);
#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

View File

@ -187,7 +187,7 @@ pxlen:
$$ = $2;
}
| ':' ipa {
$$ = ipa_mklen($2);
$$ = ipa_masklen($2);
if ($$ < 0) cf_error("Invalid netmask %I", $2);
}
;

View File

@ -2292,6 +2292,7 @@ networks.
<code>
protocol ospf &lt;name&gt; {
rfc1583compat &lt;switch&gt;;
instance id &lt;num&gt;;
stub router &lt;switch&gt;;
tick &lt;num&gt;;
ecmp &lt;switch&gt; [limit &lt;num&gt;];
@ -2336,6 +2337,7 @@ protocol ospf &lt;name&gt; {
tx length &lt;num&gt;;
type [broadcast|bcast|pointopoint|ptp|
nonbroadcast|nbma|pointomultipoint|ptmp];
link lsa suppression &lt;switch&gt;;
strict nonbroadcast &lt;switch&gt;;
real broadcast &lt;switch&gt;;
ptp netmask &lt;switch&gt;;
@ -2378,14 +2380,24 @@ protocol ospf &lt;name&gt; {
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
@ -2492,17 +2504,21 @@ protocol ospf &lt;name&gt; {
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,7 +2549,7 @@ protocol ospf &lt;name&gt; {
<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
@ -2600,9 +2616,16 @@ protocol ospf &lt;name&gt; {
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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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
View File

@ -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

465
lib/ip.h
View File

@ -9,32 +9,274 @@
#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
*/
/* Address scope */
#define SCOPE_HOST 0
#define SCOPE_LINK 1
#define SCOPE_SITE 2
@ -42,26 +284,199 @@
#define SCOPE_UNIVERSE 4
#define SCOPE_UNDEFINED 5
char *ip_scope_text(unsigned);
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); }
/*
* Network prefixes
* Miscellaneous IP prefix manipulation
*/
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);
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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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 *);

View File

@ -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 */

View File

@ -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)
{
if (c & IF_CHANGE_DOWN)
neigh_ifa_update(a);
ifa_notify_change_(c, a);
if (c & IF_CHANGE_UP)
neigh_ifa_update(a);
ifa_notify_change_dep(c, 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

View File

@ -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");
}

View File

@ -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 ... */

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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))

View File

@ -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;

View File

@ -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;

View File

@ -21,7 +21,9 @@ static list *this_nets;
static struct area_net_config *this_pref;
static struct ospf_stubnet_config *this_stubnet;
#ifdef OSPFv2
static inline int ospf_cfg_is_v2(void) { return OSPF_CFG->ospf2; }
static inline int ospf_cfg_is_v3(void) { return ! OSPF_CFG->ospf2; }
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;
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));
@ -102,25 +99,26 @@ ospf_proto_finish(void)
if (!cf->abr && !EMPTY_LIST(cf->vlink_list))
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 '}'
@ -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 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,18 +289,19 @@ 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 ; }
| 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"); }
@ -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:
@ -349,7 +347,7 @@ nbma_eligible:
| 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);
@ -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,11 +380,11 @@ 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:

View File

@ -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,112 +11,102 @@
#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);
}
/**
* ospf_dbdes_send - 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.
* When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
* does not reply, I don't create a new packet but just send the content
* of the buffer.
*/
void
ospf_dbdes_send(struct ospf_neighbor *n, int next)
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_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;
struct ospf_packet *pkt;
uint length;
/* FIXME ??? */
if ((oa->rt == NULL) || (EMPTY_LIST(po->lsal)))
update_rt_lsa(oa);
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);
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;
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);
@ -123,308 +115,366 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next)
}
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)
if (ospf_is_v2(p))
{
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++;
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 i++; /* No lsa added */
if (sn == STAIL(po->lsal))
else /* OSPFv3 */
{
i--;
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;
}
sn = sn->next;
}
if (sn == STAIL(po->lsal))
if ((en->lsa.age < LSA_MAXAGE) &&
lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
{
DBG("Number of LSA NOT sent: %d\n", i);
DBG("M bit unset.\n");
n->myimms.bit.m = 0; /* Unset more bit */
lsa_hton_hdr(&(en->lsa), lsas + i);
i++;
}
s_put(&(n->dbsi), sn);
en = SNODE_NEXT(en);
}
pkt->imms.byte = n->myimms.byte;
s_put(&(n->dbsi), SNODE en);
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);
length += i * sizeof(struct ospf_lsa_header);
}
case NEIGHBOR_LOADING:
case NEIGHBOR_FULL:
length = n->ldd_buffer ? ntohs(((struct ospf_packet *) n->ldd_buffer)->length) : 0;
if (ospf_is_v2(p))
((struct ospf_dbdes2_packet *) pkt)->imms = n->myimms;
else
((struct ospf_dbdes3_packet *) pkt)->imms = n->myimms;
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;
}
pkt->length = htons(length);
}
static void
ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n)
ospf_do_send_dbdes(struct ospf_proto *p, 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;
struct ospf_iface *ifa = n->ifa;
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_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_send_dbdes - transmit database description packet
* @n: neighbor
*
* 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.
* When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
* does not reply, I don't create a new packet but just send the content
* of the buffer.
*/
void
ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
{
/* RFC 2328 10.8 */
ASSERT((n->state == NEIGHBOR_EXSTART) || (n->state == NEIGHBOR_EXCHANGE));
if (n->ifa->oa->rt == NULL)
return;
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);
/* Send last packet */
ospf_do_send_dbdes(p, n);
}
OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->ifname);
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))
{
/* Duplicate packet */
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;
}
if ((rcv_imms == n->imms) &&
(rcv_options == n->options) &&
(rcv_ddseq == n->ddr))
goto duplicate;
n->ddr = ps_ddseq;
if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS))
DROP("MS-bit mismatch", rcv_imms);
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 (rcv_imms & DBDES_I)
DROP("I-bit mismatch", rcv_imms);
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;
}
if (rcv_options != n->options)
DROP("options mismatch", rcv_options);
n->imms.byte = ps->imms.byte;
n->ddr = rcv_ddseq;
n->imms = rcv_imms;
if (ps_options != n->options) /* Options differs */
if (n->myimms & DBDES_MS)
{
OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)",
n->ip);
ospf_neigh_sm(n, INM_SEQMIS);
break;
}
/* MASTER */
if (rcv_ddseq != n->dds)
DROP("DD sequence number mismatch", rcv_ddseq);
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);
break;
}
n->dds++;
DBG("Incrementing dds\n");
ospf_dbdes_reqladd(ps, n);
if ((n->myimms.bit.m == 0) && (ps->imms.bit.m == 0))
if (ospf_process_dbdes(p, pkt, n) < 0)
return;
if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
{
tm_stop(n->dbdes_timer);
ospf_neigh_sm(n, INM_EXDONE);
break;
}
ospf_send_dbdes(p, n);
tm_start(n->dbdes_timer, n->ifa->rxmtint);
}
else
{
/* 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);
}
else
{
ospf_dbdes_send(n, 1);
}
}
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);
}
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);
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("Undefined interface state");
}
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);
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);
}
break;
default:
bug("Received dbdes from %I in undefined state.", n->ip);
}
return;
}

View File

@ -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_ */

View File

@ -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 (ospf_is_v2(p))
{
struct ospf_hello2_packet *ps = (void *) pkt;
if ((ifa->type == OSPF_IT_VLINK) ||
((ifa->type == OSPF_IT_PTP) && !ifa->ptp_netmask))
pkt->netmask = IPA_NONE;
#endif
ps->netmask = 0;
else
ps->netmask = htonl(u32_mkmask(ifa->addr->pxlen));
pkt->helloint = ntohs(ifa->helloint);
pkt->priority = ifa->priority;
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));
#ifdef OSPFv3
pkt->iface_id = htonl(ifa->iface_id);
length = sizeof(struct ospf_hello2_packet);
neighbors = ps->neighbors;
}
else
{
struct ospf_hello3_packet *ps = (void *) pkt;
pkt->options3 = ifa->oa->options >> 16;
pkt->options2 = ifa->oa->options >> 8;
#endif
pkt->options = ifa->oa->options;
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);
#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
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)
{
@ -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()");
}
}
OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s", ifa->ifname);
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);
}
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);
}

View File

@ -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

View File

@ -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_ */

View File

@ -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;
/* RFC 2328 13.5 */
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);
}
length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsa_header);
pkt->length = htons(length);
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);
}
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);
}
ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
i = 0;
}
}
}
len = sizeof(struct ospf_lsack_packet) + i * sizeof(struct ospf_lsa_header);
op->length = htons(len);
DBG("Sending! Len=%u\n", len);
OSPF_PACKET(ospf_dump_lsack, pk, "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))
{
log(L_ERR "Bad OSPF LSACK packet from %I - too short (%u B)", n->ip, size);
return;
}
/* RFC 2328 13.7 */
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);
/* No need to check length, lsack has only basic header */
ospf_neigh_sm(n, INM_HELLOREC);
OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet received from nbr %R on %s", n->rid, ifa->ifname);
if (n->state < NEIGHBOR_EXCHANGE)
{
OSPF_TRACE(D_PACKETS, "LSACK packet ignored - lesser state than Exchange");
return;
}
lsano = (size - sizeof(struct ospf_lsack_packet)) /
sizeof(struct ospf_lsa_header);
for (i = 0; i < lsano; 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 */
ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */
if (lsa_comp(&lsa, &en->lsa) != CMP_SAME) /* pg 156 */
ospf_lsack_body(p, pkt, &lsas, &lsa_count);
for (i = 0; i < lsa_count; i++)
{
if ((lsa.sn == LSA_MAXSEQNO) && (lsa.age == LSA_MAXAGE))
lsa_ntoh_hdr(&lsas[i], &lsa);
lsa_get_type_domain(&lsa, n->ifa, &lsa_type, &lsa_domain);
ret = ospf_hash_find(n->lsrth, lsa_domain, lsa.id, lsa.rt, lsa_type);
if (!ret)
continue;
OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip);
if (lsa_comp(&lsa, &ret->lsa) != CMP_SAME)
{
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: 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);
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);
}
}

View File

@ -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_ */

View File

@ -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));
}
/*
@ -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++)
@ -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;
}

View File

@ -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_ */

View File

@ -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);
}
static void
ospf_dump_lsreq(struct ospf_proto *p, struct ospf_packet *pkt)
{
struct ospf_lsreq_header *lsrs;
uint i, lsr_count;
ASSERT(pkt->type == LSREQ_P);
ospf_dump_common(p, pkt);
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));
}
void
ospf_lsreq_send(struct ospf_neighbor *n)
ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n)
{
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_iface *ifa = n->ifa;
struct ospf_lsreq_header *lsrs;
struct top_hash_entry *req;
struct ospf_packet *pkt;
uint i, lsr_max, length;
pk = ospf_tx_buffer(n->ifa);
op = &pk->ospf_packet;
/* RFC 2328 10.9 */
ospf_pkt_fill_hdr(n->ifa, pk, LSREQ_P);
/* ASSERT((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrql)); */
sn = SHEAD(n->lsrql);
if (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;
}
if (i != 0)
i--;
length =
sizeof(struct ospf_lsreq_packet) + (j -
i) * sizeof(struct ospf_lsreq_header);
op->length = htons(length);
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);
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);
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++;
}
/* We store the position to see whether requested LSAs have been received */
n->lsrqi = req;
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)
{
OSPF_TRACE(D_PACKETS, "LSREQ packet ignored - lesser state than Exchange");
return;
}
ospf_neigh_sm(n, INM_HELLOREC);
ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */
lsh = ps->lsh;
init_list(&uplist);
upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
ospf_lsreq_body(p, pkt, &lsrs, &lsr_count);
lsano = (size - sizeof(struct ospf_lsreq_packet)) /
sizeof(struct ospf_lsreq_header);
for (i = 0; i < lsano; lsh++, i++)
struct top_hash_entry *en, *entries[lsr_count];
for (i = 0; i < lsr_count; 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)
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);
}

View File

@ -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_ */

File diff suppressed because it is too large Load Diff

View File

@ -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_ */

View File

@ -1,47 +1,57 @@
/*
* BIRD -- OSPF
*
* (c) 1999 - 2004 Ondrej Filip <feela@network.cz>
* (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"
char *ospf_ns[] = { " down",
" attempt",
" init",
" 2way",
" exstart",
"exchange",
" loading",
" full"
const char *ospf_ns_names[] = {
"Down", "Attempt", "Init", "2-Way", "ExStart", "Exchange", "Loading", "Full"
};
const char *ospf_inm[] =
{ "hello received", "neighbor start", "2-way received",
"negotiation done", "exstart done", "bad ls request", "load done",
"adjacency ok?", "sequence mismatch", "1-way received", "kill neighbor",
"inactivity timer", "line down"
const char *ospf_inm_names[] = {
"HelloReceived", "Start", "2-WayReceived", "NegotiationDone", "ExchangeDone",
"BadLSReq", "LoadingDone", "AdjOK?", "SeqNumberMismatch", "1-WayReceived",
"KillNbr", "InactivityTimer", "LLDown"
};
static void neigh_chstate(struct ospf_neighbor *n, u8 state);
static struct ospf_neighbor *electbdr(list nl);
static struct ospf_neighbor *electdr(list nl);
static void neighbor_timer_hook(timer * timer);
static void rxmt_timer_hook(timer * timer);
static int can_do_adj(struct ospf_neighbor *n);
static void inactivity_timer_hook(timer * timer);
static void dbdes_timer_hook(timer *t);
static void lsrq_timer_hook(timer *t);
static void lsrt_timer_hook(timer *t);
static void ackd_timer_hook(timer *t);
static void
init_lists(struct ospf_neighbor *n)
init_lists(struct ospf_proto *p, struct ospf_neighbor *n)
{
s_init_list(&(n->lsrql));
n->lsrqh = ospf_top_new(n->pool);
s_init(&(n->lsrqi), &(n->lsrql));
n->lsrqi = SHEAD(n->lsrql);
n->lsrqh = ospf_top_new(p, n->pool);
s_init_list(&(n->lsrtl));
n->lsrth = ospf_top_new(n->pool);
s_init(&(n->lsrti), &(n->lsrtl));
n->lsrth = ospf_top_new(p, n->pool);
}
static void
release_lsrtl(struct ospf_proto *p, struct ospf_neighbor *n)
{
struct top_hash_entry *ret, *en;
WALK_SLIST(ret, n->lsrtl)
{
en = ospf_hash_find_entry(p->gr, ret);
if (en)
en->ret_count--;
}
}
/* Resets LSA request and retransmit lists.
@ -49,19 +59,26 @@ init_lists(struct ospf_neighbor *n)
* it is reset during entering EXCHANGE state.
*/
static void
reset_lists(struct ospf_neighbor *n)
reset_lists(struct ospf_proto *p, struct ospf_neighbor *n)
{
release_lsrtl(p, n);
ospf_top_free(n->lsrqh);
ospf_top_free(n->lsrth);
init_lists(n);
ospf_reset_lsack_queue(n);
tm_stop(n->dbdes_timer);
tm_stop(n->lsrq_timer);
tm_stop(n->lsrt_timer);
tm_stop(n->ackd_timer);
init_lists(p, n);
}
struct ospf_neighbor *
ospf_neighbor_new(struct ospf_iface *ifa)
{
struct proto *p = (struct proto *) (ifa->oa->po);
struct proto_ospf *po = ifa->oa->po;
struct pool *pool = rp_new(p->pool, "OSPF Neighbor");
struct ospf_proto *p = ifa->oa->po;
struct pool *pool = rp_new(p->p.pool, "OSPF Neighbor");
struct ospf_neighbor *n = mb_allocz(pool, sizeof(struct ospf_neighbor));
n->pool = pool;
@ -71,103 +88,281 @@ ospf_neighbor_new(struct ospf_iface *ifa)
n->csn = 0;
n->state = NEIGHBOR_DOWN;
init_lists(n);
s_init(&(n->dbsi), &(po->lsal));
init_lists(p, n);
s_init(&(n->dbsi), &(p->lsal));
n->inactim = tm_new(pool);
n->inactim->data = n;
n->inactim->randomize = 0;
n->inactim->hook = neighbor_timer_hook;
n->inactim->recurrent = 0;
DBG("%s: Installing inactivity timer.\n", p->name);
n->rxmt_timer = tm_new(pool);
n->rxmt_timer->data = n;
n->rxmt_timer->randomize = 0;
n->rxmt_timer->hook = rxmt_timer_hook;
n->rxmt_timer->recurrent = ifa->rxmtint;
tm_start(n->rxmt_timer, n->ifa->rxmtint);
DBG("%s: Installing rxmt timer.\n", p->name);
n->ackd_timer = tm_new(pool);
n->ackd_timer->data = n;
n->ackd_timer->randomize = 0;
n->ackd_timer->hook = ackd_timer_hook;
n->ackd_timer->recurrent = ifa->rxmtint / 2;
init_list(&n->ackl[ACKL_DIRECT]);
init_list(&n->ackl[ACKL_DELAY]);
tm_start(n->ackd_timer, n->ifa->rxmtint / 2);
DBG("%s: Installing ackd timer.\n", p->name);
n->inactim = tm_new_set(pool, inactivity_timer_hook, n, 0, 0);
n->dbdes_timer = tm_new_set(pool, dbdes_timer_hook, n, 0, ifa->rxmtint);
n->lsrq_timer = tm_new_set(pool, lsrq_timer_hook, n, 0, ifa->rxmtint);
n->lsrt_timer = tm_new_set(pool, lsrt_timer_hook, n, 0, ifa->rxmtint);
n->ackd_timer = tm_new_set(pool, ackd_timer_hook, n, 0, ifa->rxmtint / 2);
return (n);
}
static void
ospf_neigh_down(struct ospf_neighbor *n)
{
struct ospf_iface *ifa = n->ifa;
struct ospf_proto *p = ifa->oa->po;
if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
{
struct nbma_node *nn = find_nbma_node(ifa, n->ip);
if (nn)
nn->found = 0;
}
s_get(&(n->dbsi));
release_lsrtl(p, n);
rem_node(NODE n);
rfree(n->pool);
OSPF_TRACE(D_EVENTS, "Neighbor %R on %s removed", n->rid, ifa->ifname);
}
/**
* neigh_chstate - handles changes related to new or lod state of neighbor
* ospf_neigh_chstate - handles changes related to new or lod state of neighbor
* @n: OSPF neighbor
* @state: new state
*
* Many actions have to be taken acording to a change of state of a neighbor. It
* starts rxmt timers, call interface state machine etc.
*/
static void
neigh_chstate(struct ospf_neighbor *n, u8 state)
{
u8 oldstate;
oldstate = n->state;
if (oldstate != state)
ospf_neigh_chstate(struct ospf_neighbor *n, u8 state)
{
struct ospf_iface *ifa = n->ifa;
struct proto_ospf *po = ifa->oa->po;
struct proto *p = &po->proto;
struct ospf_proto *p = ifa->oa->po;
u8 old_state = n->state;
int old_fadj = ifa->fadj;
if (state == old_state)
return;
OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed state from %s to %s",
n->rid, ifa->ifname, ospf_ns_names[old_state], ospf_ns_names[state]);
n->state = state;
OSPF_TRACE(D_EVENTS, "Neighbor %I changes state from \"%s\" to \"%s\".",
n->ip, ospf_ns[oldstate], ospf_ns[state]);
/* Increase number of partial adjacencies */
if ((state == NEIGHBOR_EXCHANGE) || (state == NEIGHBOR_LOADING))
p->padj++;
if ((state == NEIGHBOR_2WAY) && (oldstate < NEIGHBOR_2WAY))
ospf_iface_sm(ifa, ISM_NEICH);
if ((state < NEIGHBOR_2WAY) && (oldstate >= NEIGHBOR_2WAY))
ospf_iface_sm(ifa, ISM_NEICH);
/* Decrease number of partial adjacencies */
if ((old_state == NEIGHBOR_EXCHANGE) || (old_state == NEIGHBOR_LOADING))
p->padj--;
if (oldstate == NEIGHBOR_FULL) /* Decrease number of adjacencies */
{
ifa->fadj--;
schedule_rt_lsa(ifa->oa);
if (ifa->type == OSPF_IT_VLINK) schedule_rt_lsa(ifa->voa);
schedule_net_lsa(ifa);
}
if (state == NEIGHBOR_FULL) /* Increase number of adjacencies */
{
/* Increase number of full adjacencies */
if (state == NEIGHBOR_FULL)
ifa->fadj++;
schedule_rt_lsa(ifa->oa);
if (ifa->type == OSPF_IT_VLINK) schedule_rt_lsa(ifa->voa);
schedule_net_lsa(ifa);
/* Decrease number of full adjacencies */
if (old_state == NEIGHBOR_FULL)
ifa->fadj--;
if (ifa->fadj != old_fadj)
{
/* RFC 2328 12.4 Event 4 - neighbor enters/leaves Full state */
ospf_notify_rt_lsa(ifa->oa);
ospf_notify_net_lsa(ifa);
/* RFC 2328 12.4 Event 8 - vlink state change */
if (ifa->type == OSPF_IT_VLINK)
ospf_notify_rt_lsa(ifa->voa);
}
if (state == NEIGHBOR_EXSTART)
{
if (n->adj == 0) /* First time adjacency */
{
/* First time adjacency */
if (n->adj == 0)
n->dds = random_u32();
}
n->dds++;
n->myimms.byte = 0;
n->myimms.bit.ms = 1;
n->myimms.bit.m = 1;
n->myimms.bit.i = 1;
n->myimms = DBDES_IMMS;
tm_start(n->dbdes_timer, 0);
tm_start(n->ackd_timer, ifa->rxmtint / 2);
}
if (state > NEIGHBOR_EXSTART)
n->myimms.bit.i = 0;
n->myimms &= ~DBDES_I;
/* Generate NeighborChange event if needed, see RFC 2328 9.2 */
if ((state == NEIGHBOR_2WAY) && (old_state < NEIGHBOR_2WAY))
ospf_iface_sm(ifa, ISM_NEICH);
if ((state < NEIGHBOR_2WAY) && (old_state >= NEIGHBOR_2WAY))
ospf_iface_sm(ifa, ISM_NEICH);
}
/**
* ospf_neigh_sm - ospf neighbor state machine
* @n: neighor
* @event: actual event
*
* This part implements the neighbor state machine as described in 10.3 of
* RFC 2328. The only difference is that state %NEIGHBOR_ATTEMPT is not
* used. We discover neighbors on nonbroadcast networks in the
* same way as on broadcast networks. The only difference is in
* sending hello packets. These are sent to IPs listed in
* @ospf_iface->nbma_list .
*/
void
ospf_neigh_sm(struct ospf_neighbor *n, int event)
{
struct ospf_proto *p = n->ifa->oa->po;
DBG("Neighbor state machine for %R on %s, event %s\n",
n->rid, n->ifa->ifname, ospf_inm_names[event]);
switch (event)
{
case INM_START:
ospf_neigh_chstate(n, NEIGHBOR_ATTEMPT);
/* NBMA are used different way */
break;
case INM_HELLOREC:
if (n->state < NEIGHBOR_INIT)
ospf_neigh_chstate(n, NEIGHBOR_INIT);
/* Restart inactivity timer */
tm_start(n->inactim, n->ifa->deadint);
break;
case INM_2WAYREC:
if (n->state < NEIGHBOR_2WAY)
ospf_neigh_chstate(n, NEIGHBOR_2WAY);
if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n))
ospf_neigh_chstate(n, NEIGHBOR_EXSTART);
break;
case INM_NEGDONE:
if (n->state == NEIGHBOR_EXSTART)
{
ospf_neigh_chstate(n, NEIGHBOR_EXCHANGE);
/* Reset DB summary list iterator */
s_get(&(n->dbsi));
s_init(&(n->dbsi), &p->lsal);
/* Add MaxAge LSA entries to retransmission list */
ospf_add_flushed_to_lsrt(p, n);
}
else
bug("NEGDONE and I'm not in EXSTART?");
break;
case INM_EXDONE:
if (!EMPTY_SLIST(n->lsrql))
ospf_neigh_chstate(n, NEIGHBOR_LOADING);
else
ospf_neigh_chstate(n, NEIGHBOR_FULL);
break;
case INM_LOADDONE:
ospf_neigh_chstate(n, NEIGHBOR_FULL);
break;
case INM_ADJOK:
/* Can In build adjacency? */
if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n))
{
ospf_neigh_chstate(n, NEIGHBOR_EXSTART);
}
else if ((n->state >= NEIGHBOR_EXSTART) && !can_do_adj(n))
{
reset_lists(p, n);
ospf_neigh_chstate(n, NEIGHBOR_2WAY);
}
break;
case INM_SEQMIS:
case INM_BADLSREQ:
if (n->state >= NEIGHBOR_EXCHANGE)
{
reset_lists(p, n);
ospf_neigh_chstate(n, NEIGHBOR_EXSTART);
}
break;
case INM_KILLNBR:
case INM_LLDOWN:
case INM_INACTTIM:
/* No need for reset_lists() */
ospf_neigh_chstate(n, NEIGHBOR_DOWN);
ospf_neigh_down(n);
break;
case INM_1WAYREC:
reset_lists(p, n);
ospf_neigh_chstate(n, NEIGHBOR_INIT);
break;
default:
bug("%s: INM - Unknown event?", p->p.name);
break;
}
}
static int
can_do_adj(struct ospf_neighbor *n)
{
struct ospf_iface *ifa = n->ifa;
struct ospf_proto *p = ifa->oa->po;
int i = 0;
switch (ifa->type)
{
case OSPF_IT_PTP:
case OSPF_IT_PTMP:
case OSPF_IT_VLINK:
i = 1;
break;
case OSPF_IT_BCAST:
case OSPF_IT_NBMA:
switch (ifa->state)
{
case OSPF_IS_DOWN:
case OSPF_IS_LOOP:
bug("%s: Iface %s in down state?", p->p.name, ifa->ifname);
break;
case OSPF_IS_WAITING:
DBG("%s: Neighbor? on iface %s\n", p->p.name, ifa->ifname);
break;
case OSPF_IS_DROTHER:
if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid))
&& (n->state >= NEIGHBOR_2WAY))
i = 1;
break;
case OSPF_IS_PTP:
case OSPF_IS_BACKUP:
case OSPF_IS_DR:
if (n->state >= NEIGHBOR_2WAY)
i = 1;
break;
default:
bug("%s: Iface %s in unknown state?", p->p.name, ifa->ifname);
break;
}
break;
default:
bug("%s: Iface %s is unknown type?", p->p.name, ifa->ifname);
break;
}
DBG("%s: Iface %s can_do_adj=%d\n", p->p.name, ifa->ifname, i);
return i;
}
static inline u32 neigh_get_id(struct ospf_proto *p, struct ospf_neighbor *n)
{ return ospf_is_v2(p) ? ipa_to_u32(n->ip) : n->rid; }
static struct ospf_neighbor *
electbdr(list nl)
elect_bdr(struct ospf_proto *p, list nl)
{
struct ospf_neighbor *neigh, *n1, *n2;
u32 nid;
@ -176,11 +371,7 @@ electbdr(list nl)
n2 = NULL;
WALK_LIST(neigh, nl) /* First try those decl. themselves */
{
#ifdef OSPFv2
nid = ipa_to_u32(neigh->ip);
#else /* OSPFv3 */
nid = neigh->rid;
#endif
nid = neigh_get_id(p, neigh);
if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
if (neigh->priority > 0) /* Eligible */
@ -225,7 +416,7 @@ electbdr(list nl)
}
static struct ospf_neighbor *
electdr(list nl)
elect_dr(struct ospf_proto *p, list nl)
{
struct ospf_neighbor *neigh, *n;
u32 nid;
@ -233,11 +424,7 @@ electdr(list nl)
n = NULL;
WALK_LIST(neigh, nl) /* And now DR */
{
#ifdef OSPFv2
nid = ipa_to_u32(neigh->ip);
#else /* OSPFv3 */
nid = neigh->rid;
#endif
nid = neigh_get_id(p, neigh);
if (neigh->state >= NEIGHBOR_2WAY) /* Higher than 2WAY */
if (neigh->priority > 0) /* Eligible */
@ -261,189 +448,23 @@ electdr(list nl)
return (n);
}
static int
can_do_adj(struct ospf_neighbor *n)
{
struct ospf_iface *ifa;
struct proto *p;
int i;
ifa = n->ifa;
p = (struct proto *) (ifa->oa->po);
i = 0;
switch (ifa->type)
{
case OSPF_IT_PTP:
case OSPF_IT_PTMP:
case OSPF_IT_VLINK:
i = 1;
break;
case OSPF_IT_BCAST:
case OSPF_IT_NBMA:
switch (ifa->state)
{
case OSPF_IS_DOWN:
case OSPF_IS_LOOP:
bug("%s: Iface %s in down state?", p->name, ifa->ifname);
break;
case OSPF_IS_WAITING:
DBG("%s: Neighbor? on iface %s\n", p->name, ifa->ifname);
break;
case OSPF_IS_DROTHER:
if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid))
&& (n->state >= NEIGHBOR_2WAY))
i = 1;
break;
case OSPF_IS_PTP:
case OSPF_IS_BACKUP:
case OSPF_IS_DR:
if (n->state >= NEIGHBOR_2WAY)
i = 1;
break;
default:
bug("%s: Iface %s in unknown state?", p->name, ifa->ifname);
break;
}
break;
default:
bug("%s: Iface %s is unknown type?", p->name, ifa->ifname);
break;
}
DBG("%s: Iface %s can_do_adj=%d\n", p->name, ifa->ifname, i);
return i;
}
/**
* ospf_neigh_sm - ospf neighbor state machine
* @n: neighor
* @event: actual event
*
* This part implements the neighbor state machine as described in 10.3 of
* RFC 2328. The only difference is that state %NEIGHBOR_ATTEMPT is not
* used. We discover neighbors on nonbroadcast networks in the
* same way as on broadcast networks. The only difference is in
* sending hello packets. These are sent to IPs listed in
* @ospf_iface->nbma_list .
*/
void
ospf_neigh_sm(struct ospf_neighbor *n, int event)
{
struct proto_ospf *po = n->ifa->oa->po;
struct proto *p = &po->proto;
DBG("Neighbor state machine for neighbor %I, event '%s'\n", n->ip,
ospf_inm[event]);
switch (event)
{
case INM_START:
neigh_chstate(n, NEIGHBOR_ATTEMPT);
/* NBMA are used different way */
break;
case INM_HELLOREC:
switch (n->state)
{
case NEIGHBOR_ATTEMPT:
case NEIGHBOR_DOWN:
neigh_chstate(n, NEIGHBOR_INIT);
default:
tm_start(n->inactim, n->ifa->deadint); /* Restart inactivity timer */
break;
}
break;
case INM_2WAYREC:
if (n->state < NEIGHBOR_2WAY)
neigh_chstate(n, NEIGHBOR_2WAY);
if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n))
neigh_chstate(n, NEIGHBOR_EXSTART);
break;
case INM_NEGDONE:
if (n->state == NEIGHBOR_EXSTART)
{
neigh_chstate(n, NEIGHBOR_EXCHANGE);
/* Reset DB summary list iterator */
s_get(&(n->dbsi));
s_init(&(n->dbsi), &po->lsal);
while (!EMPTY_LIST(n->ackl[ACKL_DELAY]))
{
struct lsah_n *no;
no = (struct lsah_n *) HEAD(n->ackl[ACKL_DELAY]);
rem_node(NODE no);
mb_free(no);
}
}
else
bug("NEGDONE and I'm not in EXSTART?");
break;
case INM_EXDONE:
neigh_chstate(n, NEIGHBOR_LOADING);
break;
case INM_LOADDONE:
neigh_chstate(n, NEIGHBOR_FULL);
break;
case INM_ADJOK:
switch (n->state)
{
case NEIGHBOR_2WAY:
/* Can In build adjacency? */
if (can_do_adj(n))
{
neigh_chstate(n, NEIGHBOR_EXSTART);
}
break;
default:
if (n->state >= NEIGHBOR_EXSTART)
if (!can_do_adj(n))
{
reset_lists(n);
neigh_chstate(n, NEIGHBOR_2WAY);
}
break;
}
break;
case INM_SEQMIS:
case INM_BADLSREQ:
if (n->state >= NEIGHBOR_EXCHANGE)
{
reset_lists(n);
neigh_chstate(n, NEIGHBOR_EXSTART);
}
break;
case INM_KILLNBR:
case INM_LLDOWN:
case INM_INACTTIM:
reset_lists(n);
neigh_chstate(n, NEIGHBOR_DOWN);
break;
case INM_1WAYREC:
reset_lists(n);
neigh_chstate(n, NEIGHBOR_INIT);
break;
default:
bug("%s: INM - Unknown event?", p->name);
break;
}
}
/**
* bdr_election - (Backup) Designed Router election
* ospf_dr_election - (Backup) Designed Router election
* @ifa: actual interface
*
* When the wait timer fires, it is time to elect (Backup) Designated Router.
* Structure describing me is added to this list so every electing router
* has the same list. Backup Designated Router is elected before Designated
* Router. This process is described in 9.4 of RFC 2328.
* Structure describing me is added to this list so every electing router has
* the same list. Backup Designated Router is elected before Designated
* Router. This process is described in 9.4 of RFC 2328. The function is
* supposed to be called only from ospf_iface_sm() as a part of the interface
* state machine.
*/
void
bdr_election(struct ospf_iface *ifa)
ospf_dr_election(struct ospf_iface *ifa)
{
struct proto_ospf *po = ifa->oa->po;
u32 myid = po->router_id;
struct ospf_proto *p = ifa->oa->po;
struct ospf_neighbor *neigh, *ndr, *nbdr, me;
int doadj;
u32 myid = p->router_id;
DBG("(B)DR election.\n");
@ -452,19 +473,14 @@ bdr_election(struct ospf_iface *ifa)
me.priority = ifa->priority;
me.ip = ifa->addr->ip;
#ifdef OSPFv2
me.dr = ipa_to_u32(ifa->drip);
me.bdr = ipa_to_u32(ifa->bdrip);
#else /* OSPFv3 */
me.dr = ifa->drid;
me.bdr = ifa->bdrid;
me.dr = ospf_is_v2(p) ? ipa_to_u32(ifa->drip) : ifa->drid;
me.bdr = ospf_is_v2(p) ? ipa_to_u32(ifa->bdrip) : ifa->bdrid;
me.iface_id = ifa->iface_id;
#endif
add_tail(&ifa->neigh_list, NODE & me);
nbdr = electbdr(ifa->neigh_list);
ndr = electdr(ifa->neigh_list);
nbdr = elect_bdr(p, ifa->neigh_list);
ndr = elect_dr(p, ifa->neigh_list);
if (ndr == NULL)
ndr = nbdr;
@ -475,56 +491,48 @@ bdr_election(struct ospf_iface *ifa)
|| ((ifa->bdrid == myid) && (nbdr != &me))
|| ((ifa->bdrid != myid) && (nbdr == &me)))
{
#ifdef OSPFv2
me.dr = ndr ? ipa_to_u32(ndr->ip) : 0;
me.bdr = nbdr ? ipa_to_u32(nbdr->ip) : 0;
#else /* OSPFv3 */
me.dr = ndr ? ndr->rid : 0;
me.bdr = nbdr ? nbdr->rid : 0;
#endif
me.dr = ndr ? neigh_get_id(p, ndr) : 0;
me.bdr = nbdr ? neigh_get_id(p, nbdr) : 0;
nbdr = electbdr(ifa->neigh_list);
ndr = electdr(ifa->neigh_list);
nbdr = elect_bdr(p, ifa->neigh_list);
ndr = elect_dr(p, ifa->neigh_list);
if (ndr == NULL)
ndr = nbdr;
}
u32 odrid = ifa->drid;
u32 obdrid = ifa->bdrid;
rem_node(NODE & me);
u32 old_drid = ifa->drid;
u32 old_bdrid = ifa->bdrid;
ifa->drid = ndr ? ndr->rid : 0;
ifa->drip = ndr ? ndr->ip : IPA_NONE;
ifa->dr_iface_id = ndr ? ndr->iface_id : 0;
ifa->bdrid = nbdr ? nbdr->rid : 0;
ifa->bdrip = nbdr ? nbdr->ip : IPA_NONE;
#ifdef OSPFv3
ifa->dr_iface_id = ndr ? ndr->iface_id : 0;
#endif
DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid);
doadj = ((ifa->drid != odrid) || (ifa->bdrid != obdrid));
if (myid == ifa->drid)
/* We are part of the interface state machine */
if (ifa->drid == myid)
ospf_iface_chstate(ifa, OSPF_IS_DR);
else
{
if (myid == ifa->bdrid)
else if (ifa->bdrid == myid)
ospf_iface_chstate(ifa, OSPF_IS_BACKUP);
else
ospf_iface_chstate(ifa, OSPF_IS_DROTHER);
}
rem_node(NODE & me);
if (doadj)
{
/* Review neighbor adjacencies if DR or BDR changed */
if ((ifa->drid != old_drid) || (ifa->bdrid != old_bdrid))
WALK_LIST(neigh, ifa->neigh_list)
{
if (neigh->state >= NEIGHBOR_2WAY)
ospf_neigh_sm(neigh, INM_ADJOK);
}
}
/* RFC 2328 12.4 Event 3 - DR change */
if (ifa->drid != old_drid)
ospf_notify_rt_lsa(ifa->oa);
}
struct ospf_neighbor *
@ -547,51 +555,28 @@ find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip)
return NULL;
}
/* Neighbor is inactive for a long time. Remove it. */
static void
neighbor_timer_hook(timer * timer)
inactivity_timer_hook(timer * timer)
{
struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
struct ospf_iface *ifa = n->ifa;
struct proto *p = &ifa->oa->po->proto;
struct ospf_proto *p = n->ifa->oa->po;
OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I.",
ifa->ifname, n->ip);
ospf_neigh_remove(n);
}
void
ospf_neigh_remove(struct ospf_neighbor *n)
{
struct ospf_iface *ifa = n->ifa;
struct proto *p = &ifa->oa->po->proto;
if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
{
struct nbma_node *nn = find_nbma_node(ifa, n->ip);
if (nn)
nn->found = 0;
}
s_get(&(n->dbsi));
neigh_chstate(n, NEIGHBOR_DOWN);
rem_node(NODE n);
rfree(n->pool);
OSPF_TRACE(D_EVENTS, "Deleting neigbor.");
OSPF_TRACE(D_EVENTS, "Inactivity timer expired for nbr %R on %s",
n->rid, n->ifa->ifname);
ospf_neigh_sm(n, INM_INACTTIM);
}
static void
ospf_neigh_bfd_hook(struct bfd_request *req)
{
struct ospf_neighbor *n = req->data;
struct proto *p = &n->ifa->oa->po->proto;
struct ospf_proto *p = n->ifa->oa->po;
if (req->down)
{
OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s",
n->ip, n->ifa->ifname);
ospf_neigh_remove(n);
OSPF_TRACE(D_EVENTS, "BFD session down for nbr %R on %s",
n->rid, n->ifa->ifname);
ospf_neigh_sm(n, INM_INACTTIM);
}
}
@ -610,11 +595,60 @@ ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd)
}
static void
dbdes_timer_hook(timer *t)
{
struct ospf_neighbor *n = t->data;
struct ospf_proto *p = n->ifa->oa->po;
// OSPF_TRACE(D_EVENTS, "DBDES timer expired for nbr %R on %s", n->rid, n->ifa->ifname);
if (n->state == NEIGHBOR_EXSTART)
ospf_send_dbdes(p, n);
if ((n->state == NEIGHBOR_EXCHANGE) && (n->myimms & DBDES_MS))
ospf_rxmt_dbdes(p, n);
}
static void
lsrq_timer_hook(timer *t)
{
struct ospf_neighbor *n = t->data;
struct ospf_proto *p = n->ifa->oa->po;
// OSPF_TRACE(D_EVENTS, "LSRQ timer expired for nbr %R on %s", n->rid, n->ifa->ifname);
if ((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrql))
ospf_send_lsreq(p, n);
}
static void
lsrt_timer_hook(timer *t)
{
struct ospf_neighbor *n = t->data;
struct ospf_proto *p = n->ifa->oa->po;
// OSPF_TRACE(D_EVENTS, "LSRT timer expired for nbr %R on %s", n->rid, n->ifa->ifname);
if ((n->state >= NEIGHBOR_EXCHANGE) && !EMPTY_SLIST(n->lsrtl))
ospf_rxmt_lsupd(p, n);
}
static void
ackd_timer_hook(timer *t)
{
struct ospf_neighbor *n = t->data;
struct ospf_proto *p = n->ifa->oa->po;
ospf_send_lsack(p, n, ACKL_DELAY);
}
void
ospf_sh_neigh_info(struct ospf_neighbor *n)
{
struct ospf_iface *ifa = n->ifa;
char *pos = "other";
char *pos = "PtP ";
char etime[6];
int exp, sec, min;
@ -630,74 +664,16 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
bsprintf(etime, "%02u:%02u", min, sec);
}
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
{
if (n->rid == ifa->drid)
pos = "dr ";
pos = "DR ";
else if (n->rid == ifa->bdrid)
pos = "bdr ";
else if ((n->ifa->type == OSPF_IT_PTP) || (n->ifa->type == OSPF_IT_PTMP) ||
(n->ifa->type == OSPF_IT_VLINK))
pos = "ptp ";
pos = "BDR ";
else
pos = "Other";
}
cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority,
ospf_ns[n->state], pos, etime, ifa->ifname, n->ip);
}
static void
rxmt_timer_hook(timer * timer)
{
struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
// struct proto *p = &n->ifa->oa->po->proto;
struct top_hash_entry *en;
DBG("%s: RXMT timer fired on interface %s for neigh: %I.\n",
p->name, n->ifa->ifname, n->ip);
if(n->state < NEIGHBOR_EXSTART) return;
if (n->state == NEIGHBOR_EXSTART)
{
ospf_dbdes_send(n, 1);
return;
}
if ((n->state == NEIGHBOR_EXCHANGE) && n->myimms.bit.ms) /* I'm master */
ospf_dbdes_send(n, 0);
if (n->state < NEIGHBOR_FULL)
ospf_lsreq_send(n); /* EXCHANGE or LOADING */
else
{
if (!EMPTY_SLIST(n->lsrtl)) /* FULL */
{
list uplist;
slab *upslab;
struct l_lsr_head *llsh;
init_list(&uplist);
upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
WALK_SLIST(en, n->lsrtl)
{
if ((SNODE en)->next == (SNODE en))
bug("RTList is cycled");
llsh = sl_alloc(upslab);
llsh->lsh.id = en->lsa.id;
llsh->lsh.rt = en->lsa.rt;
llsh->lsh.type = en->lsa.type;
DBG("Working on ID: %R, RT: %R, Type: %u\n",
en->lsa.id, en->lsa.rt, en->lsa.type);
add_tail(&uplist, NODE llsh);
}
ospf_lsupd_send_list(n, &uplist);
rfree(upslab);
}
}
}
static void
ackd_timer_hook(timer * t)
{
struct ospf_neighbor *n = t->data;
ospf_lsack_send(n, ACKL_DELAY);
ospf_ns_names[n->state], pos, etime, ifa->ifname, n->ip);
}

View File

@ -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_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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,57 +15,46 @@
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)
@ -75,13 +66,16 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
log(L_ERR "No suitable password found for authentication");
return;
}
password_cpy(pkt->u.password, passwd->password, sizeof(union ospf_auth));
strncpy(auth->password, passwd->password, sizeof(auth->password));
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);
{
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;
case OSPF_AUTH_CRYPT:
passwd = password_find(ifa->passwords, 0);
if (!passwd)
@ -105,141 +99,111 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
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);
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, ntohs(pkt->length));
password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE);
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))
{
OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", ntohs(pkt->autype));
return 0;
}
if (autype != ifa->autype)
DROP("authentication method mismatch", autype);
switch(ifa->autype)
switch (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));
DROP1("no password found");
if (!password_verify(pass, auth->password, sizeof(auth->password)))
DROP("wrong password", pass->id);
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)
if (auth->md5.len != OSPF_AUTH_CRYPT_SIZE)
DROP("invalid MD5 digest length", auth->md5.len);
if (plen + OSPF_AUTH_CRYPT_SIZE > len)
DROP("length mismatch", len);
u32 rcv_csn = ntohl(auth->md5.csn);
if (n && (rcv_csn < n->csn))
// DROP("lower sequence number", rcv_csn);
{
OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest");
/* 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;
}
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;
}
tail = ((void *)pkt) + ntohs(pkt->length);
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;
}
}
pass = password_find_by_id(ifa->passwords, auth->md5.keyid);
if (!pass)
{
OSPF_TRACE(D_PACKETS, "OSPF_auth: no suitable md5 password found");
return 0;
}
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)
{
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");
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
@ -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,15 +227,17 @@ 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
if (ospf_is_v2(p))
{
/* 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
@ -289,48 +252,40 @@ ospf_rx_hook(sock *sk, int size)
/* Ignore my own broadcast packets */
if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip))
return 1;
#else /* OSPFv3 */
}
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(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)
{
log(L_ERR "%s%I - bad IP header", mesg, sk->faddr);
return 1;
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,73 +294,54 @@ 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)
{
/* Matching area ID */
if (instance_id != ifa->instance_id)
return 1;
/* It is real iface, source should be local (in OSPFv2) */
#ifdef OSPFv2
if (!src_local)
return 1;
#endif
}
else if (dst_mcast || (areaid != 0))
{
/* Obvious mismatch */
if (ospf_is_v2(p) && !src_local)
DROP1("strange source address");
#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
return 1;
goto found;
}
else
else if ((areaid == 0) && !dst_mcast)
{
/* Some vlink? */
/* 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, po->iface_list)
WALK_LIST(iff, p->iface_list)
{
if ((iff->type == OSPF_IT_VLINK) &&
(iff->voa == ifa->oa) &&
#ifdef OSPFv3
(iff->instance_id == ps->instance_id) &&
#endif
(iff->instance_id == instance_id) &&
(iff->vid == rid))
{
/* Vlink should be UP */
@ -417,90 +353,90 @@ ospf_rx_hook(sock *sk, int size)
}
}
#ifdef OSPFv2
log(L_WARN "OSPF: Received packet for unknown vlink (ID %R, IP %I)", rid, sk->faddr);
#endif
/*
* 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
{
/* Non-matching area ID but cannot be vlink packet */
if (instance_id != ifa->instance_id)
return 1;
DROP("area mismatch", areaid);
}
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);
}

View File

@ -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_ */

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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_ */

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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"

View File

@ -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

View File

@ -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)
{

View File

@ -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);