#include "sockunion.h"
#include "stream.h"
#include "log.h"
-#include "md5-gnu.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "md5.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_network.h"
#include "ospfd/ospf_flood.h"
#include "ospfd/ospf_dump.h"
-static void ospf_ls_ack_send_list (struct ospf_interface *, list,
- struct in_addr);
-
/* Packet Type String. */
-char *ospf_packet_type_str[] =
+const char *ospf_packet_type_str[] =
{
"unknown",
"Hello",
"Link State Acknowledgment",
};
-extern int in_cksum (void *ptr, int nbytes);
-
/* OSPF authentication checking function */
-int
+static int
ospf_auth_type (struct ospf_interface *oi)
{
int auth_type;
}
-/* forward output pointer. */
-void
-ospf_output_forward (struct stream *s, int size)
-{
- s->putp += size;
-}
-
struct ospf_packet *
ospf_packet_new (size_t size)
{
void
ospf_packet_add (struct ospf_interface *oi, struct ospf_packet *op)
{
+ if (!oi->obuf)
+ {
+ zlog_err("ospf_packet_add(interface %s in state %d [%s], packet type %s, "
+ "destination %s) called with NULL obuf, ignoring "
+ "(please report this bug)!\n",
+ IF_NAME(oi), oi->state, LOOKUP (ospf_ism_state_msg, oi->state),
+ ospf_packet_type_str[stream_getc_from(op->s, 1)],
+ inet_ntoa (op->dst));
+ return;
+ }
+
/* Add packet to end of queue. */
ospf_fifo_push (oi->obuf, op);
ospf_packet_free (op);
}
-struct stream *
-ospf_stream_copy (struct stream *new, struct stream *s)
-{
- new->endp = s->endp;
- new->putp = s->putp;
- new->getp = s->getp;
-
- memcpy (new->data, s->data, stream_get_endp (s));
-
- return new;
-}
-
struct ospf_packet *
ospf_packet_dup (struct ospf_packet *op)
{
/* Reserve space for MD5 authentication that may be added later. */
new = ospf_packet_new (stream_get_endp(op->s) + OSPF_AUTH_MD5_SIZE);
- ospf_stream_copy (new->s, op->s);
+ stream_copy (new->s, op->s);
new->dst = op->dst;
new->length = op->length;
return new;
}
-int
+/* XXX inline */
+static inline unsigned int
+ospf_packet_authspace (struct ospf_interface *oi)
+{
+ int auth = 0;
+
+ if ( ospf_auth_type (oi) == OSPF_AUTH_CRYPTOGRAPHIC)
+ auth = OSPF_AUTH_MD5_SIZE;
+
+ return auth;
+}
+
+static unsigned int
ospf_packet_max (struct ospf_interface *oi)
{
int max;
- if ( ospf_auth_type (oi) == OSPF_AUTH_CRYPTOGRAPHIC)
- max = oi->ifp->mtu - OSPF_AUTH_MD5_SIZE - 88;
- else
- max = oi->ifp->mtu - 88;
+ max = oi->ifp->mtu - ospf_packet_authspace(oi);
+
+ max -= (OSPF_HEADER_SIZE + sizeof (struct ip));
return max;
}
\f
-int
+static int
ospf_check_md5_digest (struct ospf_interface *oi, struct stream *s,
u_int16_t length)
{
- void *ibuf;
- struct md5_ctx ctx;
+ unsigned char *ibuf;
+ MD5_CTX ctx;
unsigned char digest[OSPF_AUTH_MD5_SIZE];
unsigned char *pdigest;
struct crypt_key *ck;
}
/* Generate a digest for the ospf packet - their digest + our digest. */
- md5_init_ctx (&ctx);
- md5_process_bytes (ibuf, length, &ctx);
- md5_process_bytes (ck->auth_key, OSPF_AUTH_MD5_SIZE, &ctx);
- md5_finish_ctx (&ctx, digest);
+ memset(&ctx, 0, sizeof(ctx));
+ MD5Init(&ctx);
+ MD5Update(&ctx, ibuf, length);
+ MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE);
+ MD5Final(digest, &ctx);
/* compare the two */
if (memcmp (pdigest, digest, OSPF_AUTH_MD5_SIZE))
/* This function is called from ospf_write(), it will detect the
authentication scheme and if it is MD5, it will change the sequence
and update the MD5 digest. */
-int
+static int
ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op)
{
struct ospf_header *ospfh;
unsigned char digest[OSPF_AUTH_MD5_SIZE];
- struct md5_ctx ctx;
+ MD5_CTX ctx;
void *ibuf;
- unsigned long oldputp;
u_int32_t t;
struct crypt_key *ck;
- char *auth_key;
+ const u_int8_t *auth_key;
ibuf = STREAM_DATA (op->s);
ospfh = (struct ospf_header *) ibuf;
/* We do this here so when we dup a packet, we don't have to
waste CPU rewriting other headers. */
t = (time(NULL) & 0xFFFFFFFF);
- oi->crypt_seqnum = ( t > oi->crypt_seqnum ? t : oi->crypt_seqnum++);
+ if (t > oi->crypt_seqnum)
+ oi->crypt_seqnum = t;
+ else
+ oi->crypt_seqnum++;
+
ospfh->u.crypt.crypt_seqnum = htonl (oi->crypt_seqnum);
/* Get MD5 Authentication key from auth_key list. */
if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt)))
- auth_key = "";
+ auth_key = (const u_int8_t *) "";
else
{
- ck = getdata (OSPF_IF_PARAM (oi, auth_crypt)->tail);
+ ck = listgetdata (listtail(OSPF_IF_PARAM (oi, auth_crypt)));
auth_key = ck->auth_key;
}
/* Generate a digest for the entire packet + our secret key. */
- md5_init_ctx (&ctx);
- md5_process_bytes (ibuf, ntohs (ospfh->length), &ctx);
- md5_process_bytes (auth_key, OSPF_AUTH_MD5_SIZE, &ctx);
- md5_finish_ctx (&ctx, digest);
+ memset(&ctx, 0, sizeof(ctx));
+ MD5Init(&ctx);
+ MD5Update(&ctx, ibuf, ntohs (ospfh->length));
+ MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE);
+ MD5Final(digest, &ctx);
/* Append md5 digest to the end of the stream. */
- oldputp = stream_get_putp (op->s);
- stream_set_putp (op->s, ntohs (ospfh->length));
stream_put (op->s, digest, OSPF_AUTH_MD5_SIZE);
- stream_set_putp (op->s, oldputp);
/* We do *NOT* increment the OSPF header length. */
op->length = ntohs (ospfh->length) + OSPF_AUTH_MD5_SIZE;
}
\f
-int
+static int
ospf_ls_req_timer (struct thread *thread)
{
struct ospf_neighbor *nbr;
/* Send Link State Update. */
if (ospf_ls_retransmit_count (nbr) > 0)
{
- list update;
+ struct list *update;
struct ospf_lsdb *lsdb;
int i;
- struct timeval now;
int retransmit_interval;
- gettimeofday (&now, NULL);
retransmit_interval = OSPF_IF_PARAM (nbr->oi, retransmit_interval);
lsdb = &nbr->ls_rxmt;
fired. This is a small tweak to what is in the RFC,
but it will cut out out a lot of retransmit traffic
- MAG */
- if (tv_cmp (tv_sub (now, lsa->tv_recv),
+ if (tv_cmp (tv_sub (recent_time, lsa->tv_recv),
int2tv (retransmit_interval)) >= 0)
listnode_add (update, rn->info);
}
return 0;
}
-int
+#ifdef WANT_OSPF_WRITE_FRAGMENT
+static void
+ospf_write_frags (int fd, struct ospf_packet *op, struct ip *iph,
+ struct msghdr *msg, unsigned int maxdatasize,
+ unsigned int mtu, int flags, u_char type)
+{
+#define OSPF_WRITE_FRAG_SHIFT 3
+ u_int16_t offset;
+ struct iovec *iovp;
+ int ret;
+
+ assert ( op->length == stream_get_endp(op->s) );
+ assert (msg->msg_iovlen == 2);
+
+ /* we can but try.
+ *
+ * SunOS, BSD and BSD derived kernels likely will clear ip_id, as
+ * well as the IP_MF flag, making this all quite pointless.
+ *
+ * However, for a system on which IP_MF is left alone, and ip_id left
+ * alone or else which sets same ip_id for each fragment this might
+ * work, eg linux.
+ *
+ * XXX-TODO: It would be much nicer to have the kernel's use their
+ * existing fragmentation support to do this for us. Bugs/RFEs need to
+ * be raised against the various kernels.
+ */
+
+ /* set More Frag */
+ iph->ip_off |= IP_MF;
+
+ /* ip frag offset is expressed in units of 8byte words */
+ offset = maxdatasize >> OSPF_WRITE_FRAG_SHIFT;
+
+ iovp = &msg->msg_iov[1];
+
+ while ( (stream_get_endp(op->s) - stream_get_getp (op->s))
+ > maxdatasize )
+ {
+ /* data length of this frag is to next offset value */
+ iovp->iov_len = offset << OSPF_WRITE_FRAG_SHIFT;
+ iph->ip_len = iovp->iov_len + sizeof (struct ip);
+ assert (iph->ip_len <= mtu);
+
+ sockopt_iphdrincl_swab_htosys (iph);
+
+ ret = sendmsg (fd, msg, flags);
+
+ sockopt_iphdrincl_swab_systoh (iph);
+
+ if (ret < 0)
+ zlog_warn ("*** ospf_write_frags: sendmsg failed to %s,"
+ " id %d, off %d, len %d, mtu %u failed with %s",
+ inet_ntoa (iph->ip_dst),
+ iph->ip_id,
+ iph->ip_off,
+ iph->ip_len,
+ mtu,
+ safe_strerror (errno));
+
+ if (IS_DEBUG_OSPF_PACKET (type - 1, SEND))
+ {
+ zlog_debug ("ospf_write_frags: sent id %d, off %d, len %d to %s\n",
+ iph->ip_id, iph->ip_off, iph->ip_len,
+ inet_ntoa (iph->ip_dst));
+ if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
+ {
+ zlog_debug ("-----------------IP Header Dump----------------------");
+ ospf_ip_header_dump (iph);
+ zlog_debug ("-----------------------------------------------------");
+ }
+ }
+
+ iph->ip_off += offset;
+ stream_forward_getp (op->s, iovp->iov_len);
+ iovp->iov_base = STREAM_PNT (op->s);
+ }
+
+ /* setup for final fragment */
+ iovp->iov_len = stream_get_endp(op->s) - stream_get_getp (op->s);
+ iph->ip_len = iovp->iov_len + sizeof (struct ip);
+ iph->ip_off &= (~IP_MF);
+}
+#endif /* WANT_OSPF_WRITE_FRAGMENT */
+
+static int
ospf_write (struct thread *thread)
{
struct ospf *ospf = THREAD_ARG (thread);
u_char type;
int ret;
int flags = 0;
- listnode node;
+ struct listnode *node;
+#ifdef WANT_OSPF_WRITE_FRAGMENT
+ static u_int16_t ipid = 0;
+#endif /* WANT_OSPF_WRITE_FRAGMENT */
+ u_int16_t maxdatasize;
+#define OSPF_WRITE_IPHL_SHIFT 2
ospf->t_write = NULL;
node = listhead (ospf->oi_write_q);
assert (node);
- oi = getdata (node);
+ oi = listgetdata (node);
assert (oi);
+
+#ifdef WANT_OSPF_WRITE_FRAGMENT
+ /* seed ipid static with low order bits of time */
+ if (ipid == 0)
+ ipid = (time(NULL) & 0xffff);
+#endif /* WANT_OSPF_WRITE_FRAGMENT */
+
+ /* convenience - max OSPF data per packet */
+ maxdatasize = oi->ifp->mtu - sizeof (struct ip);
/* Get one packet from queue. */
op = ospf_fifo_head (oi->obuf);
if (op->dst.s_addr == htonl (OSPF_ALLSPFROUTERS)
|| op->dst.s_addr == htonl (OSPF_ALLDROUTERS))
- ospf_if_ipmulticast (ospf, oi->address, oi->ifp->ifindex);
-
+ ospf_if_ipmulticast (ospf, oi->address, oi->ifp->ifindex);
+
/* Rewrite the md5 signature & update the seq */
ospf_make_md5_digest (oi, op);
+ /* Retrieve OSPF packet type. */
+ stream_set_getp (op->s, 1);
+ type = stream_getc (op->s);
+
+ /* reset get pointer */
+ stream_set_getp (op->s, 0);
+
+ memset (&iph, 0, sizeof (struct ip));
memset (&sa_dst, 0, sizeof (sa_dst));
+
sa_dst.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
sa_dst.sin_len = sizeof(sa_dst);
if (!IN_MULTICAST (htonl (op->dst.s_addr)))
flags = MSG_DONTROUTE;
- iph.ip_hl = sizeof (struct ip) >> 2;
+ iph.ip_hl = sizeof (struct ip) >> OSPF_WRITE_IPHL_SHIFT;
+ /* it'd be very strange for header to not be 4byte-word aligned but.. */
+ if ( sizeof (struct ip)
+ > (unsigned int)(iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) )
+ iph.ip_hl++; /* we presume sizeof struct ip cant overflow ip_hl.. */
+
iph.ip_v = IPVERSION;
iph.ip_tos = IPTOS_PREC_INTERNETCONTROL;
-#if defined(__NetBSD__) || defined(__FreeBSD__)
- iph.ip_len = iph.ip_hl*4 + op->length;
-#else
- iph.ip_len = htons (iph.ip_hl*4 + op->length);
-#endif
- iph.ip_id = 0;
+ iph.ip_len = (iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) + op->length;
+
+#ifdef WANT_OSPF_WRITE_FRAGMENT
+ /* XXX-MT: not thread-safe at all..
+ * XXX: this presumes this is only programme sending OSPF packets
+ * otherwise, no guarantee ipid will be unique
+ */
+ iph.ip_id = ++ipid;
+#endif /* WANT_OSPF_WRITE_FRAGMENT */
+
iph.ip_off = 0;
if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
iph.ip_ttl = OSPF_VL_IP_TTL;
iph.ip_dst.s_addr = op->dst.s_addr;
memset (&msg, 0, sizeof (msg));
- msg.msg_name = &sa_dst;
+ msg.msg_name = (caddr_t) &sa_dst;
msg.msg_namelen = sizeof (sa_dst);
msg.msg_iov = iov;
msg.msg_iovlen = 2;
iov[0].iov_base = (char*)&iph;
- iov[0].iov_len = iph.ip_hl*4;
- iov[1].iov_base = STREAM_DATA (op->s);
+ iov[0].iov_len = iph.ip_hl << OSPF_WRITE_IPHL_SHIFT;
+ iov[1].iov_base = STREAM_PNT (op->s);
iov[1].iov_len = op->length;
-
+
+ /* Sadly we can not rely on kernels to fragment packets because of either
+ * IP_HDRINCL and/or multicast destination being set.
+ */
+#ifdef WANT_OSPF_WRITE_FRAGMENT
+ if ( op->length > maxdatasize )
+ ospf_write_frags (ospf->fd, op, &iph, &msg, maxdatasize,
+ oi->ifp->mtu, flags, type);
+#endif /* WANT_OSPF_WRITE_FRAGMENT */
+
+ /* send final fragment (could be first) */
+ sockopt_iphdrincl_swab_htosys (&iph);
ret = sendmsg (ospf->fd, &msg, flags);
+ sockopt_iphdrincl_swab_systoh (&iph);
if (ret < 0)
- zlog_warn ("*** sendmsg in ospf_write failed with %s", strerror (errno));
-
- /* Retrieve OSPF packet type. */
- stream_set_getp (op->s, 1);
- type = stream_getc (op->s);
+ zlog_warn ("*** sendmsg in ospf_write failed to %s, "
+ "id %d, off %d, len %d, interface %s, mtu %u: %s",
+ inet_ntoa (iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len,
+ oi->ifp->name, oi->ifp->mtu, safe_strerror (errno));
/* Show debug sending packet. */
if (IS_DEBUG_OSPF_PACKET (type - 1, SEND))
{
if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
{
- zlog_info ("-----------------------------------------------------");
+ zlog_debug ("-----------------------------------------------------");
+ ospf_ip_header_dump (&iph);
stream_set_getp (op->s, 0);
ospf_packet_dump (op->s);
}
- zlog_info ("%s sent to [%s] via [%s].",
+ zlog_debug ("%s sent to [%s] via [%s].",
ospf_packet_type_str[type], inet_ntoa (op->dst),
IF_NAME (oi));
if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
- zlog_info ("-----------------------------------------------------");
+ zlog_debug ("-----------------------------------------------------");
}
/* Now delete packet from queue. */
}
/* OSPF Hello message read -- RFC2328 Section 10.5. */
-void
+static void
ospf_hello (struct ip *iph, struct ospf_header *ospfh,
struct stream * s, struct ospf_interface *oi, int size)
{
struct ospf_hello *hello;
struct ospf_neighbor *nbr;
- struct route_node *rn;
- struct prefix p, key;
int old_state;
+ struct prefix p;
/* increment statistics. */
oi->hello_in++;
/* If Hello is myself, silently discard. */
if (IPV4_ADDR_SAME (&ospfh->router_id, &oi->ospf->router_id))
- return;
+ {
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+ {
+ zlog_debug ("ospf_header[%s/%s]: selforiginated, "
+ "dropping.",
+ ospf_packet_type_str[ospfh->type],
+ inet_ntoa (iph->ip_src));
+ }
+ return;
+ }
/* If incoming interface is passive one, ignore Hello. */
if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE) {
- zlog_info ("Packet %s [HELLO:RECV]: oi is passive",
- inet_ntoa (ospfh->router_id));
+ char buf[3][INET_ADDRSTRLEN];
+ zlog_debug ("ignoring HELLO from router %s sent to %s, "
+ "received on a passive interface, %s",
+ inet_ntop(AF_INET, &ospfh->router_id, buf[0], sizeof(buf[0])),
+ inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])),
+ inet_ntop(AF_INET, &oi->address->u.prefix4,
+ buf[2], sizeof(buf[2])));
+ if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS))
+ {
+ /* Try to fix multicast membership. */
+ SET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
+ ospf_if_set_multicast(oi);
+ }
return;
}
return;
}
- /* Compare Hello Interval. */
- if (OSPF_IF_PARAM (oi, v_hello) != ntohs (hello->hello_interval))
- {
- zlog_warn ("Packet %s [Hello:RECV]: HelloInterval mismatch.",
- inet_ntoa (ospfh->router_id));
- return;
- }
-
/* Compare Router Dead Interval. */
if (OSPF_IF_PARAM (oi, v_wait) != ntohl (hello->dead_interval))
{
return;
}
+ /* Compare Hello Interval - ignored if fast-hellos are set. */
+ if (OSPF_IF_PARAM (oi, fast_hello) == 0)
+ {
+ if (OSPF_IF_PARAM (oi, v_hello) != ntohs (hello->hello_interval))
+ {
+ zlog_warn ("Packet %s [Hello:RECV]: HelloInterval mismatch.",
+ inet_ntoa (ospfh->router_id));
+ return;
+ }
+ }
+
if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("Packet %s [Hello:RECV]: Options %s",
+ zlog_debug ("Packet %s [Hello:RECV]: Options %s",
inet_ntoa (ospfh->router_id),
ospf_options_dump (hello->options));
/* new for NSSA is to ensure that NP is on and E is off */
-#ifdef HAVE_NSSA
if (oi->area->external_routing == OSPF_AREA_NSSA)
{
if (! (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_NP)
return;
}
if (IS_DEBUG_OSPF_NSSA)
- zlog_info ("NSSA-Hello:RECV:Packet from %s:", inet_ntoa(ospfh->router_id));
+ zlog_debug ("NSSA-Hello:RECV:Packet from %s:", inet_ntoa(ospfh->router_id));
}
else
-#endif /* HAVE_NSSA */
/* The setting of the E-bit found in the Hello Packet's Options
field must match this area's ExternalRoutingCapability A
mismatch causes processing to stop and the packet to be
if (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_E) !=
CHECK_FLAG (hello->options, OSPF_OPTION_E))
{
- zlog_warn ("Packet[Hello:RECV]: my options: %x, his options %x",
- OPTIONS (oi), hello->options);
+ zlog_warn ("Packet %s [Hello:RECV]: my options: %x, his options %x",
+ inet_ntoa(ospfh->router_id), OPTIONS (oi), hello->options);
return;
}
-
-
- /* Get neighbor information from table. */
- key.family = AF_INET;
- key.prefixlen = IPV4_MAX_BITLEN;
- key.u.prefix4 = iph->ip_src;
-
- rn = route_node_get (oi->nbrs, &key);
- if (rn->info)
- {
- route_unlock_node (rn);
- nbr = rn->info;
-
- if (oi->type == OSPF_IFTYPE_NBMA && nbr->state == NSM_Attempt)
- {
- nbr->src = iph->ip_src;
- nbr->address = p;
- }
- }
- else
- {
- /* Create new OSPF Neighbor structure. */
- nbr = ospf_nbr_new (oi);
- nbr->state = NSM_Down;
- nbr->src = iph->ip_src;
- nbr->address = p;
-
- rn->info = nbr;
-
- nbr->nbr_nbma = NULL;
-
- if (oi->type == OSPF_IFTYPE_NBMA)
- {
- struct ospf_nbr_nbma *nbr_nbma;
- listnode node;
-
- for (node = listhead (oi->nbr_nbma); node; nextnode (node))
- {
- nbr_nbma = getdata (node);
- assert (nbr_nbma);
-
- if (IPV4_ADDR_SAME(&nbr_nbma->addr, &iph->ip_src))
- {
- nbr_nbma->nbr = nbr;
- nbr->nbr_nbma = nbr_nbma;
-
- if (nbr_nbma->t_poll)
- OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll);
-
- nbr->state_change = nbr_nbma->state_change + 1;
- }
- }
- }
-
- /* New nbr, save the crypto sequence number if necessary */
- if (ntohs (ospfh->auth_type) == OSPF_AUTH_CRYPTOGRAPHIC)
- nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;
-
- if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("NSM[%s:%s]: start", IF_NAME (nbr->oi),
- inet_ntoa (nbr->router_id));
- }
- nbr->router_id = ospfh->router_id;
+ /* get neighbour struct */
+ nbr = ospf_nbr_get (oi, ospfh, iph, &p);
+
+ /* neighbour must be valid, ospf_nbr_get creates if none existed */
+ assert (nbr);
old_state = nbr->state;
}
/* Save DD flags/options/Seqnum received. */
-void
+static void
ospf_db_desc_save_current (struct ospf_neighbor *nbr,
struct ospf_db_desc *dd)
{
struct ospf_lsa *new, *find;
struct lsa_header *lsah;
- stream_forward (s, OSPF_DB_DESC_MIN_SIZE);
+ stream_forward_getp (s, OSPF_DB_DESC_MIN_SIZE);
for (size -= OSPF_DB_DESC_MIN_SIZE;
size >= OSPF_LSA_HEADER_SIZE; size -= OSPF_LSA_HEADER_SIZE)
{
lsah = (struct lsa_header *) STREAM_PNT (s);
- stream_forward (s, OSPF_LSA_HEADER_SIZE);
+ stream_forward_getp (s, OSPF_LSA_HEADER_SIZE);
/* Unknown LS type. */
if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA)
{
- zlog_warn ("Pakcet [DD:RECV]: Unknown LS type %d.", lsah->type);
+ zlog_warn ("Packet [DD:RECV]: Unknown LS type %d.", lsah->type);
OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
return;
}
#ifdef HAVE_OPAQUE_LSA
case OSPF_OPAQUE_AS_LSA:
#endif /* HAVE_OPAQUE_LSA */
-#ifdef HAVE_NSSA
/* Check for stub area. Reject if AS-External from stub but
allow if from NSSA. */
if (oi->area->external_routing == OSPF_AREA_STUB)
-#else /* ! HAVE_NSSA */
- if (oi->area->external_routing != OSPF_AREA_DEFAULT)
-#endif /* HAVE_NSSA */
{
zlog_warn ("Packet [DD:RECV]: LSA[Type%d:%s] from %s area.",
lsah->type, inet_ntoa (lsah->id),
{
/* Received LSA is not recent. */
if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("Packet [DD:RECV]: LSA received Type %d, "
+ zlog_debug ("Packet [DD:RECV]: LSA received Type %d, "
"ID %s is not recent.", lsah->type, inet_ntoa (lsah->id));
ospf_lsa_discard (new);
continue;
OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone);
}
- /* Send DD pakcet in reply. */
+ /* Send DD packet in reply. */
ospf_db_desc_send (nbr);
}
ospf_db_desc_save_current (nbr, dd);
}
-int
+static int
ospf_db_desc_is_dup (struct ospf_db_desc *dd, struct ospf_neighbor *nbr)
{
/* Is DD duplicated? */
}
/* OSPF Database Description message read -- RFC2328 Section 10.6. */
-void
+static void
ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
struct stream *s, struct ospf_interface *oi, u_int16_t size)
{
oi->db_desc_in++;
dd = (struct ospf_db_desc *) STREAM_PNT (s);
-#ifdef HAVE_NSSA
- /*
- * XXX HACK by Hasso Tepper. Setting P bit in NSSA area DD packets is not
- * required. In fact at least JunOS sends DD packets with P bit clear.
- * Until proper solution is developped, this hack should help.
- */
- if (oi->area->external_routing == OSPF_AREA_NSSA)
- {
- dd->options = (dd->options | ((short)(8)));
- }
-#endif /* HAVE_NSSA */
- nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src);
+
+ nbr = ospf_nbr_lookup (oi, iph, ospfh);
if (nbr == NULL)
{
zlog_warn ("Packet[DD]: Unknown Neighbor %s",
}
/* Check MTU. */
- if (ntohs (dd->mtu) > oi->ifp->mtu)
+ if ((OSPF_IF_PARAM (oi, mtu_ignore) == 0) &&
+ (ntohs (dd->mtu) > oi->ifp->mtu))
{
- zlog_warn ("Packet[DD]: MTU is larger than [%s]'s MTU", IF_NAME (oi));
+ zlog_warn ("Packet[DD]: Neighbor %s MTU %u is larger than [%s]'s MTU %u",
+ inet_ntoa (nbr->router_id), ntohs (dd->mtu),
+ IF_NAME (oi), oi->ifp->mtu);
return;
}
+ /*
+ * XXX HACK by Hasso Tepper. Setting N/P bit in NSSA area DD packets is not
+ * required. In fact at least JunOS sends DD packets with P bit clear.
+ * Until proper solution is developped, this hack should help.
+ *
+ * Update: According to the RFCs, N bit is specified /only/ for Hello
+ * options, unfortunately its use in DD options is not specified. Hence some
+ * implementations follow E-bit semantics and set it in DD options, and some
+ * treat it as unspecified and hence follow the directive "default for
+ * options is clear", ie unset.
+ *
+ * Reset the flag, as ospfd follows E-bit semantics.
+ */
+ if ( (oi->area->external_routing == OSPF_AREA_NSSA)
+ && (CHECK_FLAG (nbr->options, OSPF_OPTION_NP))
+ && (!CHECK_FLAG (dd->options, OSPF_OPTION_NP)) )
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug ("Packet[DD]: Neighbour %s: Has NSSA capability, sends with N bit clear in DD options",
+ inet_ntoa (nbr->router_id) );
+ SET_FLAG (dd->options, OSPF_OPTION_NP);
+ }
+
#ifdef REJECT_IF_TBIT_ON
if (CHECK_FLAG (dd->options, OSPF_OPTION_T))
{
case NSM_Down:
case NSM_Attempt:
case NSM_TwoWay:
- zlog_warn ("Packet[DD]: Neighbor state is %s, packet discarded.",
+ zlog_warn ("Packet[DD]: Neighbor %s state is %s, packet discarded.",
+ inet_ntoa(nbr->router_id),
LOOKUP (ospf_nsm_state_msg, nbr->state));
break;
case NSM_Init:
if (IPV4_ADDR_CMP (&nbr->router_id, &oi->ospf->router_id) > 0)
{
/* We're Slave---obey */
- zlog_warn ("Packet[DD]: Negotiation done (Slave).");
+ zlog_info ("Packet[DD]: Neighbor %s Negotiation done (Slave).",
+ inet_ntoa(nbr->router_id));
nbr->dd_seqnum = ntohl (dd->dd_seqnum);
nbr->dd_flags &= ~(OSPF_DD_FLAG_MS|OSPF_DD_FLAG_I); /* Reset I/MS */
}
else
{
/* We're Master, ignore the initial DBD from Slave */
- zlog_warn ("Packet[DD]: Initial DBD from Slave, ignoring.");
+ zlog_info ("Packet[DD]: Neighbor %s: Initial DBD from Slave, "
+ "ignoring.", inet_ntoa(nbr->router_id));
break;
}
}
ntohl (dd->dd_seqnum) == nbr->dd_seqnum &&
IPV4_ADDR_CMP (&nbr->router_id, &oi->ospf->router_id) < 0)
{
- zlog_warn ("Packet[DD]: Negotiation done (Master).");
+ zlog_info ("Packet[DD]: Neighbor %s Negotiation done (Master).",
+ inet_ntoa(nbr->router_id));
nbr->dd_flags &= ~OSPF_DD_FLAG_I;
}
else
{
- zlog_warn ("Packet[DD]: Negotiation fails.");
+ zlog_warn ("Packet[DD]: Neighbor %s Negotiation fails.",
+ inet_ntoa(nbr->router_id));
break;
}
if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE))
{
if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("Neighbor[%s] is %sOpaque-capable.",
+ zlog_debug ("Neighbor[%s] is %sOpaque-capable.",
inet_ntoa (nbr->router_id),
CHECK_FLAG (nbr->options, OSPF_OPTION_O) ? "" : "NOT ");
if (! CHECK_FLAG (nbr->options, OSPF_OPTION_O)
&& IPV4_ADDR_SAME (&DR (oi), &nbr->address.u.prefix4))
{
- zlog_warn ("DR-neighbor[%s] is NOT opaque-capable; Opaque-LSAs cannot be reliably advertised in this network.", inet_ntoa (nbr->router_id));
+ zlog_warn ("DR-neighbor[%s] is NOT opaque-capable; "
+ "Opaque-LSAs cannot be reliably advertised "
+ "in this network.",
+ inet_ntoa (nbr->router_id));
/* This situation is undesirable, but not a real error. */
}
}
{
if (IS_SET_DD_MS (nbr->dd_flags))
/* Master: discard duplicated DD packet. */
- zlog_warn ("Packet[DD] (Master): packet duplicated.");
+ zlog_info ("Packet[DD] (Master): Neighbor %s packet duplicated.",
+ inet_ntoa (nbr->router_id));
else
/* Slave: cause to retransmit the last Database Description. */
{
- zlog_warn ("Packet[DD] [Slave]: packet duplicated.");
+ zlog_info ("Packet[DD] [Slave]: Neighbor %s packet duplicated.",
+ inet_ntoa (nbr->router_id));
ospf_db_desc_resend (nbr);
}
break;
/* Check Master/Slave bit mismatch */
if (IS_SET_DD_MS (dd->flags) != IS_SET_DD_MS (nbr->last_recv.flags))
{
- zlog_warn ("Packet[DD]: MS-bit mismatch.");
+ zlog_warn ("Packet[DD]: Neighbor %s MS-bit mismatch.",
+ inet_ntoa(nbr->router_id));
OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("Packet[DD]: dd->flags=%d, nbr->dd_flags=%d",
- dd->flags, nbr->dd_flags);
+ zlog_debug ("Packet[DD]: dd->flags=%d, nbr->dd_flags=%d",
+ dd->flags, nbr->dd_flags);
break;
}
/* Check initialize bit is set. */
if (IS_SET_DD_I (dd->flags))
{
- zlog_warn ("Packet[DD]: I-bit set.");
+ zlog_info ("Packet[DD]: Neighbor %s I-bit set.",
+ inet_ntoa(nbr->router_id));
OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
break;
}
/* Save the new options for debugging */
nbr->options = dd->options;
#endif /* ORIGINAL_CODING */
- zlog_warn ("Packet[DD]: options mismatch.");
+ zlog_warn ("Packet[DD]: Neighbor %s options mismatch.",
+ inet_ntoa(nbr->router_id));
OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
break;
}
(!IS_SET_DD_MS (nbr->dd_flags) &&
ntohl (dd->dd_seqnum) != nbr->dd_seqnum + 1))
{
- zlog_warn ("Pakcet[DD]: sequence number mismatch.");
+ zlog_warn ("Packet[DD]: Neighbor %s sequence number mismatch.",
+ inet_ntoa(nbr->router_id));
OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
break;
}
if (IS_SET_DD_MS (nbr->dd_flags))
{
/* Master should discard duplicate DD packet. */
- zlog_warn ("Pakcet[DD]: duplicated, packet discarded.");
+ zlog_info ("Packet[DD]: Neighbor %s duplicated, "
+ "packet discarded.",
+ inet_ntoa(nbr->router_id));
break;
}
else
OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
break;
default:
- zlog_warn ("Packet[DD]: NSM illegal status.");
+ zlog_warn ("Packet[DD]: Neighbor %s NSM illegal status %u.",
+ inet_ntoa(nbr->router_id), nbr->state);
break;
}
}
#define OSPF_LSA_KEY_SIZE 12 /* type(4) + id(4) + ar(4) */
/* OSPF Link State Request Read -- RFC2328 Section 10.7. */
-void
+static void
ospf_ls_req (struct ip *iph, struct ospf_header *ospfh,
struct stream *s, struct ospf_interface *oi, u_int16_t size)
{
struct in_addr ls_id;
struct in_addr adv_router;
struct ospf_lsa *find;
- list ls_upd;
- int length;
+ struct list *ls_upd;
+ unsigned int length;
/* Increment statistics. */
oi->ls_req_in++;
- nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src);
+ nbr = ospf_nbr_lookup (oi, iph, ospfh);
if (nbr == NULL)
{
zlog_warn ("Link State Request: Unknown Neighbor %s.",
nbr->state != NSM_Loading &&
nbr->state != NSM_Full)
{
- zlog_warn ("Link State Request: Neighbor state is %s, packet discarded.",
+ zlog_warn ("Link State Request received from %s: "
+ "Neighbor state is %s, packet discarded.",
+ inet_ntoa (ospfh->router_id),
LOOKUP (ospf_nsm_state_msg, nbr->state));
return;
}
return;
}
- /* Packet overflows MTU size, send immediatly. */
- if (length + ntohs (find->data->length) > OSPF_PACKET_MAX (oi))
+ /* Packet overflows MTU size, send immediately. */
+ if (length + ntohs (find->data->length) > ospf_packet_max (oi))
{
if (oi->type == OSPF_IFTYPE_NBMA)
ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_DIRECT);
/* Get the list of LSAs from Link State Update packet.
And process some validation -- RFC2328 Section 13. (1)-(2). */
-static list
+static struct list *
ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s,
struct ospf_interface *oi, size_t size)
{
u_int32_t length;
struct lsa_header *lsah;
struct ospf_lsa *lsa;
- list lsas;
+ struct list *lsas;
lsas = list_new ();
size -= OSPF_LS_UPD_MIN_SIZE; /* # LSAs */
for (; size >= OSPF_LSA_HEADER_SIZE && count > 0;
- size -= length, stream_forward (s, length), count--)
+ size -= length, stream_forward_getp (s, length), count--)
{
lsah = (struct lsa_header *) STREAM_PNT (s);
length = ntohs (lsah->length);
&& nbr->oi->area->external_routing != OSPF_AREA_DEFAULT)
{
if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("LSA[Type%d:%s]: We are a stub, don't take this LSA.", lsah->type, inet_ntoa (lsah->id));
+ zlog_debug ("LSA[Type%d:%s]: We are a stub, don't take this LSA.", lsah->type, inet_ntoa (lsah->id));
continue;
}
}
memcpy (lsa->data, lsah, length);
if (IS_DEBUG_OSPF_EVENT)
- zlog_info("LSA[Type%d:%s]: %p new LSA created with Link State Update",
+ zlog_debug("LSA[Type%d:%s]: %p new LSA created with Link State Update",
lsa->data->type, inet_ntoa (lsa->data->id), lsa);
listnode_add (lsas, lsa);
}
}
/* Cleanup Update list. */
-void
-ospf_upd_list_clean (list lsas)
+static void
+ospf_upd_list_clean (struct list *lsas)
{
- listnode node;
+ struct listnode *node, *nnode;
struct ospf_lsa *lsa;
- for (node = listhead (lsas); node; nextnode (node))
- if ((lsa = getdata (node)) != NULL)
- ospf_lsa_discard (lsa);
+ for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa))
+ ospf_lsa_discard (lsa);
list_delete (lsas);
}
/* OSPF Link State Update message read -- RFC2328 Section 13. */
-void
+static void
ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
struct stream *s, struct ospf_interface *oi, u_int16_t size)
{
struct ospf_neighbor *nbr;
- list lsas;
-#ifdef HAVE_OPAQUE_LSA
- list mylsa_acks, mylsa_upds;
-#endif /* HAVE_OPAQUE_LSA */
- listnode node, next;
+ struct list *lsas;
+ struct listnode *node, *nnode;
struct ospf_lsa *lsa = NULL;
/* unsigned long ls_req_found = 0; */
oi->ls_upd_in++;
/* Check neighbor. */
- nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src);
+ nbr = ospf_nbr_lookup (oi, iph, ospfh);
if (nbr == NULL)
{
zlog_warn ("Link State Update: Unknown Neighbor %s on int: %s",
/* Check neighbor state. */
if (nbr->state < NSM_Exchange)
{
- zlog_warn ("Link State Update: Neighbor[%s] state is less than Exchange",
- inet_ntoa (ospfh->router_id));
+ zlog_warn ("Link State Update: "
+ "Neighbor[%s] state %s is less than Exchange",
+ inet_ntoa (ospfh->router_id),
+ LOOKUP(ospf_nsm_state_msg, nbr->state));
return;
}
lsas = ospf_ls_upd_list_lsa (nbr, s, oi, size);
#ifdef HAVE_OPAQUE_LSA
- /*
- * Prepare two kinds of lists to clean up unwanted self-originated
- * Opaque-LSAs from the routing domain as soon as possible.
- */
- mylsa_acks = list_new (); /* Let the sender cease retransmission. */
- mylsa_upds = list_new (); /* Flush target LSAs if necessary. */
-
/*
* If self-originated Opaque-LSAs that have flooded before restart
* are contained in the received LSUpd message, corresponding LSReq
* updating for the same LSA would take place alternately, this trick
* must be done before entering to the loop below.
*/
+ /* XXX: Why is this Opaque specific? Either our core code is deficient
+ * and this should be fixed generally, or Opaque is inventing strawman
+ * problems */
ospf_opaque_adjust_lsreq (nbr, lsas);
#endif /* HAVE_OPAQUE_LSA */
#define DISCARD_LSA(L,N) {\
if (IS_DEBUG_OSPF_EVENT) \
- zlog_info ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p Type-%d", N, lsa, (int) lsa->data->type); \
+ zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p Type-%d", N, lsa, (int) lsa->data->type); \
ospf_lsa_discard (L); \
continue; }
/* Process each LSA received in the one packet. */
- for (node = listhead (lsas); node; node = next)
+ for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa))
{
struct ospf_lsa *ls_ret, *current;
int ret = 1;
- next = node->next;
-
- lsa = getdata (node);
-
-#ifdef HAVE_NSSA
if (IS_DEBUG_OSPF_NSSA)
{
char buf1[INET_ADDRSTRLEN];
char buf2[INET_ADDRSTRLEN];
char buf3[INET_ADDRSTRLEN];
- zlog_info("LSA Type-%d from %s, ID: %s, ADV: %s",
+ zlog_debug("LSA Type-%d from %s, ID: %s, ADV: %s",
lsa->data->type,
inet_ntop (AF_INET, &ospfh->router_id,
buf1, INET_ADDRSTRLEN),
inet_ntop (AF_INET, &lsa->data->adv_router,
buf3, INET_ADDRSTRLEN));
}
-#endif /* HAVE_NSSA */
listnode_delete (lsas, lsa); /* We don't need it in list anymore */
if (nbr->oi->area->external_routing != OSPF_AREA_DEFAULT)
{
DISCARD_LSA (lsa, 1);
-#ifdef HAVE_NSSA
if (IS_DEBUG_OSPF_NSSA)
- zlog_info("Incoming External LSA Discarded: We are NSSA/STUB Area");
-#endif /* HAVE_NSSA */
+ zlog_debug("Incoming External LSA Discarded: We are NSSA/STUB Area");
}
-#ifdef HAVE_NSSA
if (lsa->data->type == OSPF_AS_NSSA_LSA)
if (nbr->oi->area->external_routing != OSPF_AREA_NSSA)
{
DISCARD_LSA (lsa,2);
if (IS_DEBUG_OSPF_NSSA)
- zlog_info("Incoming NSSA LSA Discarded: Not NSSA Area");
+ zlog_debug("Incoming NSSA LSA Discarded: Not NSSA Area");
}
-#endif /* HAVE_NSSA */
/* Find the LSA in the current database. */
ospf_ls_ack_send (nbr, lsa);
/* Discard LSA. */
- zlog_warn ("Link State Update: LS age is equal to MaxAge.");
+ zlog_info ("Link State Update[%s]: LS age is equal to MaxAge.",
+ dump_lsa_key(lsa));
DISCARD_LSA (lsa, 3);
}
* Otherwise, the LSA instance remains in the routing domain
* until its age reaches to MaxAge.
*/
+ /* XXX: We should deal with this for *ALL* LSAs, not just opaque */
if (current == NULL)
{
if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("LSA[%s]: Previously originated Opaque-LSA, not found in the LSDB.", dump_lsa_key (lsa));
+ zlog_debug ("LSA[%s]: Previously originated Opaque-LSA,"
+ "not found in the LSDB.", dump_lsa_key (lsa));
SET_FLAG (lsa->flags, OSPF_LSA_SELF);
- listnode_add (mylsa_upds, ospf_lsa_dup (lsa));
- listnode_add (mylsa_acks, ospf_lsa_lock (lsa));
+
+ ospf_opaque_self_originated_lsa_received (nbr, lsa);
+ ospf_ls_ack_send (nbr, lsa);
+
continue;
}
}
#endif /* HAVE_OPAQUE_LSA */
+ /* It might be happen that received LSA is self-originated network LSA, but
+ * router ID is cahnged. So, we should check if LSA is a network-LSA whose
+ * Link State ID is one of the router's own IP interface addresses but whose
+ * Advertising Router is not equal to the router's own Router ID
+ * According to RFC 2328 12.4.2 and 13.4 this LSA should be flushed.
+ */
+
+ if(lsa->data->type == OSPF_NETWORK_LSA)
+ {
+ struct listnode *oinode, *oinnode;
+ struct ospf_interface *out_if;
+ int Flag = 0;
+
+ for (ALL_LIST_ELEMENTS (oi->ospf->oiflist, oinode, oinnode, out_if))
+ {
+ if(out_if == NULL)
+ break;
+
+ if((IPV4_ADDR_SAME(&out_if->address->u.prefix4, &lsa->data->id)) &&
+ (!(IPV4_ADDR_SAME(&oi->ospf->router_id, &lsa->data->adv_router))))
+ {
+ if(out_if->network_lsa_self)
+ {
+ ospf_lsa_flush_area(lsa,out_if->area);
+ if(IS_DEBUG_OSPF_EVENT)
+ zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point 9: lsa %p Type-%d",
+ lsa, (int) lsa->data->type);
+ ospf_lsa_discard (lsa);
+ Flag = 1;
+ }
+ break;
+ }
+ }
+ if(Flag)
+ continue;
+ }
+
/* (5) Find the instance of this LSA that is currently contained
in the router's link state database. If there is no
database copy, or the received LSA is more recent than
if (ospf_ls_request_lookup (nbr, lsa))
{
OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq);
- zlog_warn ("LSA instance exists on Link state request list");
+ zlog_warn("LSA[%s] instance exists on Link state request list",
+ dump_lsa_key(lsa));
/* Clean list of LSAs. */
ospf_upd_list_clean (lsas);
/* this lsa is not on lsas list already. */
ospf_lsa_discard (lsa);
-#ifdef HAVE_OPAQUE_LSA
- list_delete (mylsa_acks);
- list_delete (mylsa_upds);
-#endif /* HAVE_OPAQUE_LSA */
return;
}
}
}
-#ifdef HAVE_OPAQUE_LSA
- /*
- * Now that previously originated Opaque-LSAs those which not yet
- * installed into LSDB are captured, take several steps to clear
- * them completely from the routing domain, before proceeding to
- * origination for the current target Opaque-LSAs.
- */
- while (listcount (mylsa_acks) > 0)
- ospf_ls_ack_send_list (oi, mylsa_acks, nbr->address.u.prefix4);
-
- if (listcount (mylsa_upds) > 0)
- ospf_opaque_self_originated_lsa_received (nbr, mylsa_upds);
-
- list_delete (mylsa_upds);
- list_delete (mylsa_acks);
-#endif /* HAVE_OPAQUE_LSA */
-
assert (listcount (lsas) == 0);
list_delete (lsas);
}
/* OSPF Link State Acknowledgment message read -- RFC2328 Section 13.7. */
-void
+static void
ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh,
struct stream *s, struct ospf_interface *oi, u_int16_t size)
{
struct ospf_neighbor *nbr;
-#ifdef HAVE_OPAQUE_LSA
- list opaque_acks;
-#endif /* HAVE_OPAQUE_LSA */
-
+
/* increment statistics. */
oi->ls_ack_in++;
- nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src);
+ nbr = ospf_nbr_lookup (oi, iph, ospfh);
if (nbr == NULL)
{
zlog_warn ("Link State Acknowledgment: Unknown Neighbor %s.",
if (nbr->state < NSM_Exchange)
{
- zlog_warn ("Link State Acknowledgment: State is less than Exchange.");
+ zlog_warn ("Link State Acknowledgment: "
+ "Neighbor[%s] state %s is less than Exchange",
+ inet_ntoa (ospfh->router_id),
+ LOOKUP(ospf_nsm_state_msg, nbr->state));
return;
}
-
-#ifdef HAVE_OPAQUE_LSA
- opaque_acks = list_new ();
-#endif /* HAVE_OPAQUE_LSA */
-
+
while (size >= OSPF_LSA_HEADER_SIZE)
{
struct ospf_lsa *lsa, *lsr;
/* lsah = (struct lsa_header *) STREAM_PNT (s); */
size -= OSPF_LSA_HEADER_SIZE;
- stream_forward (s, OSPF_LSA_HEADER_SIZE);
+ stream_forward_getp (s, OSPF_LSA_HEADER_SIZE);
if (lsa->data->type < OSPF_MIN_LSA || lsa->data->type >= OSPF_MAX_LSA)
{
if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum)
{
#ifdef HAVE_OPAQUE_LSA
- /* Keep this LSA entry for later reference. */
if (IS_OPAQUE_LSA (lsr->data->type))
- listnode_add (opaque_acks, ospf_lsa_dup (lsr));
+ ospf_opaque_ls_ack_received (nbr, lsr);
#endif /* HAVE_OPAQUE_LSA */
ospf_ls_retransmit_delete (nbr, lsr);
ospf_lsa_discard (lsa);
}
-#ifdef HAVE_OPAQUE_LSA
- if (listcount (opaque_acks) > 0)
- ospf_opaque_ls_ack_received (nbr, opaque_acks);
-
- list_delete (opaque_acks);
return;
-#endif /* HAVE_OPAQUE_LSA */
}
\f
-struct stream *
-ospf_recv_packet (int fd, struct interface **ifp)
+static struct stream *
+ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf)
{
int ret;
- struct ip iph;
+ struct ip *iph;
u_int16_t ip_len;
- struct stream *ibuf;
unsigned int ifindex = 0;
struct iovec iov;
- struct cmsghdr *cmsg;
-#if defined (IP_PKTINFO)
- struct in_pktinfo *pktinfo;
-#elif defined (IP_RECVIF)
- struct sockaddr_dl *pktinfo;
-#else
- char *pktinfo; /* dummy */
-#endif
- char buff [sizeof (*cmsg) + sizeof (*pktinfo)];
- struct msghdr msgh = {NULL, 0, &iov, 1, buff,
- sizeof (*cmsg) + sizeof (*pktinfo), 0};
-
- ret = recvfrom (fd, (void *)&iph, sizeof (iph), MSG_PEEK, NULL, 0);
+ /* Header and data both require alignment. */
+ char buff [CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())];
+ struct msghdr msgh;
+
+ memset (&msgh, 0, sizeof (struct msghdr));
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_control = (caddr_t) buff;
+ msgh.msg_controllen = sizeof (buff);
- if (ret != sizeof (iph))
+ ret = stream_recvmsg (ibuf, fd, &msgh, 0, OSPF_MAX_PACKET_SIZE+1);
+ if (ret < 0)
{
- zlog_warn ("ospf_recv_packet packet smaller than ip header");
+ zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno));
return NULL;
}
-
-#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
- ip_len = iph.ip_len;
-#else
- ip_len = ntohs (iph.ip_len);
-#endif
-
-#if !defined(GNU_LINUX)
+ if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */
+ {
+ zlog_warn("ospf_recv_packet: discarding runt packet of length %d "
+ "(ip header size is %u)",
+ ret, (u_int)sizeof(iph));
+ return NULL;
+ }
+
+ /* Note that there should not be alignment problems with this assignment
+ because this is at the beginning of the stream data buffer. */
+ iph = (struct ip *) STREAM_DATA(ibuf);
+ sockopt_iphdrincl_swab_systoh (iph);
+
+ ip_len = iph->ip_len;
+
+#if !defined(GNU_LINUX) && (OpenBSD < 200311)
/*
* Kernel network code touches incoming IP header parameters,
* before protocol specific processing.
*
* For more details, see <netinet/ip_input.c>.
*/
- ip_len = ip_len + (iph.ip_hl << 2);
+ ip_len = ip_len + (iph->ip_hl << 2);
#endif
- ibuf = stream_new (ip_len);
- iov.iov_base = STREAM_DATA (ibuf);
- iov.iov_len = ip_len;
- ret = recvmsg (fd, &msgh, 0);
-
- cmsg = CMSG_FIRSTHDR (&msgh);
-
- if (cmsg != NULL && //cmsg->cmsg_len == sizeof (*pktinfo) &&
- cmsg->cmsg_level == IPPROTO_IP &&
-#if defined (IP_PKTINFO)
- cmsg->cmsg_type == IP_PKTINFO
-#elif defined (IP_RECVIF)
- cmsg->cmsg_type == IP_RECVIF
-#else
- 0
-#endif
- )
- {
-#if defined (IP_PKTINFO)
- pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
- ifindex = pktinfo->ipi_ifindex;
-#elif defined (IP_RECVIF)
- pktinfo = (struct sockaddr_dl *)CMSG_DATA(cmsg);
- ifindex = pktinfo->sdl_index;
-#else
- ifindex = 0;
-#endif
- }
+ ifindex = getsockopt_ifindex (AF_INET, &msgh);
*ifp = if_lookup_by_index (ifindex);
if (ret != ip_len)
{
- zlog_warn ("ospf_recv_packet short read. "
- "ip_len %d bytes read %d", ip_len, ret);
- stream_free (ibuf);
+ zlog_warn ("ospf_recv_packet read length mismatch: ip_len is %d, "
+ "but recvmsg returned %d", ip_len, ret);
return NULL;
}
return ibuf;
}
-struct ospf_interface *
-ospf_associate_packet_vl (struct ospf *ospf,
- struct interface *ifp, struct ospf_interface *oi,
+static struct ospf_interface *
+ospf_associate_packet_vl (struct ospf *ospf, struct interface *ifp,
struct ip *iph, struct ospf_header *ospfh)
{
struct ospf_interface *rcv_oi;
struct ospf_vl_data *vl_data;
struct ospf_area *vl_area;
- listnode node;
+ struct listnode *node;
if (IN_MULTICAST (ntohl (iph->ip_dst.s_addr)) ||
!OSPF_IS_AREA_BACKBONE (ospfh))
- return oi;
+ return NULL;
- if ((rcv_oi = oi) == NULL)
- {
- if ((rcv_oi = ospf_if_lookup_by_local_addr (ospf, ifp,
- iph->ip_dst)) == NULL)
- return NULL;
- }
+ /* look for local OSPF interface matching the destination
+ * to determine Area ID. We presume therefore the destination address
+ * is unique, or at least (for "unnumbered" links), not used in other
+ * areas
+ */
+ if ((rcv_oi = ospf_if_lookup_by_local_addr (ospf, NULL,
+ iph->ip_dst)) == NULL)
+ return NULL;
- for (node = listhead (ospf->vlinks); node; nextnode (node))
+ for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data))
{
- if ((vl_data = getdata (node)) == NULL)
- continue;
-
vl_area = ospf_area_lookup_by_area_id (ospf, vl_data->vl_area_id);
if (!vl_area)
continue;
IPV4_ADDR_SAME (&vl_data->vl_peer, &ospfh->router_id))
{
if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("associating packet with %s",
+ zlog_debug ("associating packet with %s",
IF_NAME (vl_data->vl_oi));
if (! CHECK_FLAG (vl_data->vl_oi->ifp->flags, IFF_UP))
{
if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("This VL is not up yet, sorry");
+ zlog_debug ("This VL is not up yet, sorry");
return NULL;
}
}
if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("couldn't find any VL to associate the packet with");
+ zlog_debug ("couldn't find any VL to associate the packet with");
- return oi;
+ return NULL;
}
-int
+static inline int
ospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh)
{
/* Check match the Area ID of the receiving interface. */
/* Unbound socket will accept any Raw IP packets if proto is matched.
To prevent it, compare src IP address and i/f address with masking
i/f network mask. */
-int
+static int
ospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src)
{
struct in_addr mask, me, him;
return 0;
}
-int
+static int
ospf_check_auth (struct ospf_interface *oi, struct stream *ibuf,
struct ospf_header *ospfh)
{
ret = 0;
break;
case OSPF_AUTH_CRYPTOGRAPHIC:
- if ((ck = getdata (OSPF_IF_PARAM (oi,auth_crypt)->tail)) == NULL)
+ if ((ck = listgetdata (listtail(OSPF_IF_PARAM (oi,auth_crypt)))) == NULL)
{
ret = 0;
break;
return ret;
}
-int
+static int
ospf_check_sum (struct ospf_header *ospfh)
{
u_int32_t ret;
u_int16_t sum;
- int in_cksum (void *ptr, int nbytes);
/* clear auth_data for checksum. */
memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
}
/* OSPF Header verification. */
-int
+static int
ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi,
struct ip *iph, struct ospf_header *ospfh)
{
/* Check authentication. */
if (ospf_auth_type (oi) != ntohs (ospfh->auth_type))
{
- zlog_warn ("interface %s: ospf_read authentication type mismatch.",
- IF_NAME (oi));
+ zlog_warn ("interface %s: auth-type mismatch, local %d, rcvd %d",
+ IF_NAME (oi), ospf_auth_type (oi), ntohs (ospfh->auth_type));
return -1;
}
/* first of all get interface pointer. */
ospf = THREAD_ARG (thread);
- ospf->t_read = NULL;
+
+ /* prepare for next packet. */
+ ospf->t_read = thread_add_read (master, ospf_read, ospf, ospf->fd);
/* read OSPF packet. */
- ibuf = ospf_recv_packet (ospf->fd, &ifp);
- if (ibuf == NULL)
+ stream_reset(ospf->ibuf);
+ if (!(ibuf = ospf_recv_packet (ospf->fd, &ifp, ospf->ibuf)))
return -1;
+ /* Note that there should not be alignment problems with this assignment
+ because this is at the beginning of the stream data buffer. */
iph = (struct ip *) STREAM_DATA (ibuf);
+ /* Note that sockopt_iphdrincl_swab_systoh was called in ospf_recv_packet. */
- /* prepare for next packet. */
- ospf->t_read = thread_add_read (master, ospf_read, ospf, ospf->fd);
+ if (ifp == NULL)
+ /* Handle cases where the platform does not support retrieving the ifindex,
+ and also platforms (such as Solaris 8) that claim to support ifindex
+ retrieval but do not. */
+ ifp = if_lookup_address (iph->ip_src);
+
+ if (ifp == NULL)
+ return 0;
/* IP Header dump. */
if (IS_DEBUG_OSPF_PACKET(0, RECV))
- ospf_ip_header_dump (ibuf);
+ ospf_ip_header_dump (iph);
/* Self-originated packet should be discarded silently. */
if (ospf_if_lookup_by_local_addr (ospf, NULL, iph->ip_src))
{
- stream_free (ibuf);
+ if (IS_DEBUG_OSPF_PACKET (0, RECV))
+ {
+ zlog_debug ("ospf_read[%s]: Dropping self-originated packet",
+ inet_ntoa (iph->ip_src));
+ }
return 0;
}
/* Adjust size to message length. */
- stream_forward (ibuf, iph->ip_hl * 4);
+ stream_forward_getp (ibuf, iph->ip_hl * 4);
/* Get ospf packet header. */
ospfh = (struct ospf_header *) STREAM_PNT (ibuf);
/* associate packet with ospf interface */
oi = ospf_if_lookup_recv_if (ospf, iph->ip_src);
- if (ifp && oi && oi->ifp != ifp)
+
+ /* if no local ospf_interface,
+ * or header area is backbone but ospf_interface is not
+ * check for VLINK interface
+ */
+ if ( (oi == NULL) ||
+ (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id)
+ && !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id))
+ )
+ {
+ if ((oi = ospf_associate_packet_vl (ospf, ifp, iph, ospfh)) == NULL)
+ {
+ zlog_debug ("Packet from [%s] received on link %s"
+ " but no ospf_interface",
+ inet_ntoa (iph->ip_src), ifp->name);
+ return 0;
+ }
+ }
+
+ /* else it must be a local ospf interface, check it was received on
+ * correct link
+ */
+ else if (oi->ifp != ifp)
{
zlog_warn ("Packet from [%s] received on wrong link %s",
- inet_ntoa (iph->ip_src), ifp->name);
- stream_free (ibuf);
+ inet_ntoa (iph->ip_src), ifp->name);
return 0;
}
-
- if ((oi = ospf_associate_packet_vl (ospf, ifp, oi, iph, ospfh)) == NULL)
- {
- stream_free (ibuf);
+ else if (oi->state == ISM_Down)
+ {
+ char buf[2][INET_ADDRSTRLEN];
+ zlog_warn ("Ignoring packet from %s to %s received on interface that is "
+ "down [%s]; interface flags are %s",
+ inet_ntop(AF_INET, &iph->ip_src, buf[0], sizeof(buf[0])),
+ inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])),
+ ifp->name, if_flag_dump(ifp->flags));
+ /* Fix multicast memberships? */
+ if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS))
+ SET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
+ else if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS))
+ SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
+ if (oi->multicast_memberships)
+ ospf_if_set_multicast(oi);
return 0;
}
if (iph->ip_dst.s_addr == htonl (OSPF_ALLDROUTERS)
&& (oi->state != ISM_DR && oi->state != ISM_Backup))
{
- zlog_info ("Packet for AllDRouters from [%s] via [%s] (ISM: %s)",
+ zlog_warn ("Dropping packet for AllDRouters from [%s] via [%s] (ISM: %s)",
inet_ntoa (iph->ip_src), IF_NAME (oi),
LOOKUP (ospf_ism_state_msg, oi->state));
- stream_free (ibuf);
+ /* Try to fix multicast membership. */
+ SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
+ ospf_if_set_multicast(oi);
return 0;
}
{
if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL))
{
- zlog_info ("-----------------------------------------------------");
+ zlog_debug ("-----------------------------------------------------");
ospf_packet_dump (ibuf);
}
- zlog_info ("%s received from [%s] via [%s]",
+ zlog_debug ("%s received from [%s] via [%s]",
ospf_packet_type_str[ospfh->type],
inet_ntoa (ospfh->router_id), IF_NAME (oi));
- zlog_info (" src [%s],", inet_ntoa (iph->ip_src));
- zlog_info (" dst [%s]", inet_ntoa (iph->ip_dst));
+ zlog_debug (" src [%s],", inet_ntoa (iph->ip_src));
+ zlog_debug (" dst [%s]", inet_ntoa (iph->ip_dst));
if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL))
- zlog_info ("-----------------------------------------------------");
+ zlog_debug ("-----------------------------------------------------");
}
/* Some header verification. */
ret = ospf_verify_header (ibuf, oi, iph, ospfh);
if (ret < 0)
{
- stream_free (ibuf);
+ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+ {
+ zlog_debug ("ospf_read[%s/%s]: Header check failed, "
+ "dropping.",
+ ospf_packet_type_str[ospfh->type],
+ inet_ntoa (iph->ip_src));
+ }
return ret;
}
- stream_forward (ibuf, OSPF_HEADER_SIZE);
+ stream_forward_getp (ibuf, OSPF_HEADER_SIZE);
/* Adjust size to message length. */
length = ntohs (ospfh->length) - OSPF_HEADER_SIZE;
break;
}
- stream_free (ibuf);
return 0;
}
/* Make OSPF header. */
-void
+static void
ospf_make_header (int type, struct ospf_interface *oi, struct stream *s)
{
struct ospf_header *ospfh;
memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
- ospf_output_forward (s, OSPF_HEADER_SIZE);
+ stream_forward_endp (s, OSPF_HEADER_SIZE);
}
/* Make Authentication Data. */
-int
+static int
ospf_make_auth (struct ospf_interface *oi, struct ospf_header *ospfh)
{
struct crypt_key *ck;
}
else
{
- ck = getdata (OSPF_IF_PARAM (oi, auth_crypt)->tail);
+ ck = listgetdata (listtail(OSPF_IF_PARAM (oi, auth_crypt)));
ospfh->u.crypt.zero = 0;
ospfh->u.crypt.key_id = ck->key_id;
ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
}
/* Fill rest of OSPF header. */
-void
+static void
ospf_fill_header (struct ospf_interface *oi,
struct stream *s, u_int16_t length)
{
ospf_make_auth (oi, ospfh);
}
-int
+static int
ospf_make_hello (struct ospf_interface *oi, struct stream *s)
{
struct ospf_neighbor *nbr;
stream_put_ipv4 (s, mask.s_addr);
/* Set Hello Interval. */
- stream_putw (s, OSPF_IF_PARAM (oi, v_hello));
+ if (OSPF_IF_PARAM (oi, fast_hello) == 0)
+ stream_putw (s, OSPF_IF_PARAM (oi, v_hello));
+ else
+ stream_putw (s, 0); /* hello-interval of 0 for fast-hellos */
if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("make_hello: options: %x, int: %s",
+ zlog_debug ("make_hello: options: %x, int: %s",
OPTIONS(oi), IF_NAME (oi));
/* Set Options. */
/* Set Designated Router. */
stream_put_ipv4 (s, DR (oi).s_addr);
- p = s->putp;
+ p = stream_get_endp (s);
/* Set Backup Designated Router. */
stream_put_ipv4 (s, BDR (oi).s_addr);
/* Let neighbor generate BackupSeen. */
if (flag == 1)
- {
- stream_set_putp (s, p);
- stream_put_ipv4 (s, 0);
- }
+ stream_putl_at (s, p, 0); /* ipv4 address, normally */
return length;
}
-int
+static int
ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr,
struct stream *s)
{
stream_putc (s, options);
/* Keep pointer to flags. */
- pp = stream_get_putp (s);
+ pp = stream_get_endp (s);
stream_putc (s, nbr->dd_flags);
/* Set DD Sequence Number. */
{
nbr->dd_flags &= ~OSPF_DD_FLAG_M;
/* Set DD flags again */
- stream_set_putp (s, pp);
- stream_putc (s, nbr->dd_flags);
+ stream_putc_at (s, pp, nbr->dd_flags);
}
return length;
}
u_int16_t ls_age;
/* DD packet overflows interface MTU. */
- if (length + OSPF_LSA_HEADER_SIZE > OSPF_PACKET_MAX (oi))
+ if (length + OSPF_LSA_HEADER_SIZE > ospf_packet_max (oi))
break;
/* Keep pointer to LS age. */
lsah = (struct lsa_header *) (STREAM_DATA (s) +
- stream_get_putp (s));
+ stream_get_endp (s));
/* Proceed stream pointer. */
stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE);
return length;
}
-int
+static int
ospf_make_ls_req_func (struct stream *s, u_int16_t *length,
unsigned long delta, struct ospf_neighbor *nbr,
struct ospf_lsa *lsa)
oi = nbr->oi;
/* LS Request packet overflows interface MTU. */
- if (*length + delta > OSPF_PACKET_MAX(oi))
+ if (*length + delta > ospf_packet_max(oi))
return 0;
stream_putl (s, lsa->data->type);
return 1;
}
-int
+static int
ospf_make_ls_req (struct ospf_neighbor *nbr, struct stream *s)
{
struct ospf_lsa *lsa;
u_int16_t length = OSPF_LS_REQ_MIN_SIZE;
- unsigned long delta = stream_get_putp(s)+12;
+ unsigned long delta = stream_get_endp(s)+12;
struct route_table *table;
struct route_node *rn;
int i;
return length;
}
-int
+static int
ls_age_increment (struct ospf_lsa *lsa, int delay)
{
int age;
return (age > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : age);
}
-int
-ospf_make_ls_upd (struct ospf_interface *oi, list update, struct stream *s)
+static int
+ospf_make_ls_upd (struct ospf_interface *oi, struct list *update, struct stream *s)
{
struct ospf_lsa *lsa;
- listnode node;
+ struct listnode *node;
u_int16_t length = OSPF_LS_UPD_MIN_SIZE;
- unsigned long delta = stream_get_putp (s);
+ unsigned int size_noauth;
+ unsigned long delta = stream_get_endp (s);
unsigned long pp;
int count = 0;
if (IS_DEBUG_OSPF_EVENT)
- zlog_info("ospf_make_ls_upd: Start");
-
- pp = stream_get_putp (s);
- ospf_output_forward (s, 4);
+ zlog_debug ("ospf_make_ls_upd: Start");
+
+ pp = stream_get_endp (s);
+ stream_forward_endp (s, OSPF_LS_UPD_MIN_SIZE);
+
+ /* Calculate amount of packet usable for data. */
+ size_noauth = stream_get_size(s) - ospf_packet_authspace(oi);
while ((node = listhead (update)) != NULL)
{
u_int16_t ls_age;
if (IS_DEBUG_OSPF_EVENT)
- zlog_info("ospf_make_ls_upd: List Iteration");
+ zlog_debug ("ospf_make_ls_upd: List Iteration");
+
+ lsa = listgetdata (node);
- lsa = getdata (node);
- assert (lsa);
assert (lsa->data);
- /* Check packet size. */
- if (length + delta + ntohs (lsa->data->length) > OSPF_PACKET_MAX (oi))
- break;
-
+ /* Will it fit? */
+ if (length + delta + ntohs (lsa->data->length) > size_noauth)
+ break;
+
/* Keep pointer to LS age. */
- lsah = (struct lsa_header *) (STREAM_DATA (s) + stream_get_putp (s));
+ lsah = (struct lsa_header *) (STREAM_DATA (s) + stream_get_endp (s));
/* Put LSA to Link State Request. */
stream_put (s, lsa->data, ntohs (lsa->data->length));
}
/* Now set #LSAs. */
- stream_set_putp (s, pp);
- stream_putl (s, count);
-
- stream_set_putp (s, s->endp);
+ stream_putl_at (s, pp, count);
if (IS_DEBUG_OSPF_EVENT)
- zlog_info("ospf_make_ls_upd: Stop");
+ zlog_debug ("ospf_make_ls_upd: Stop");
return length;
}
-int
-ospf_make_ls_ack (struct ospf_interface *oi, list ack, struct stream *s)
+static int
+ospf_make_ls_ack (struct ospf_interface *oi, struct list *ack, struct stream *s)
{
- list rm_list;
- listnode node;
+ struct list *rm_list;
+ struct listnode *node;
u_int16_t length = OSPF_LS_ACK_MIN_SIZE;
- unsigned long delta = stream_get_putp(s) + 24;
+ unsigned long delta = stream_get_endp(s) + 24;
struct ospf_lsa *lsa;
rm_list = list_new ();
- for (node = listhead (ack); node; nextnode (node))
+ for (ALL_LIST_ELEMENTS_RO (ack, node, lsa))
{
- lsa = getdata (node);
+ lsa = listgetdata (node);
assert (lsa);
- if (length + delta > OSPF_PACKET_MAX (oi))
+ if (length + delta > ospf_packet_max (oi))
break;
stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE);
}
/* Remove LSA from LS-Ack list. */
- for (node = listhead (rm_list); node; nextnode (node))
+ /* XXX: this loop should be removed and the list move done in previous
+ * loop
+ */
+ for (ALL_LIST_ELEMENTS_RO (rm_list, node, lsa))
{
- lsa = (struct ospf_lsa *) getdata (node);
-
listnode_delete (ack, lsa);
ospf_lsa_unlock (lsa);
}
OSPF_ISM_WRITE_ON (oi->ospf);
}
-void
+static void
ospf_poll_send (struct ospf_nbr_nbma *nbr_nbma)
{
struct ospf_interface *oi;
nbr_nbma->t_poll = NULL;
if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
- zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (Poll timer expire)",
+ zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (Poll timer expire)",
IF_NAME (nbr_nbma->oi), inet_ntoa (nbr_nbma->addr));
ospf_poll_send (nbr_nbma);
assert (nbr->oi);
if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
- zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (hello-reply timer expire)",
+ zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (hello-reply timer expire)",
IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
ospf_hello_send_sub (nbr->oi, &nbr->address.u.prefix4);
ospf_ls_upd_send_lsa (struct ospf_neighbor *nbr, struct ospf_lsa *lsa,
int flag)
{
- list update;
+ struct list *update;
update = list_new ();
list_delete (update);
}
+/* Determine size for packet. Must be at least big enough to accomodate next
+ * LSA on list, which may be bigger than MTU size.
+ *
+ * Return pointer to new ospf_packet
+ * NULL if we can not allocate, eg because LSA is bigger than imposed limit
+ * on packet sizes (in which case offending LSA is deleted from update list)
+ */
+static struct ospf_packet *
+ospf_ls_upd_packet_new (struct list *update, struct ospf_interface *oi)
+{
+ struct ospf_lsa *lsa;
+ struct listnode *ln;
+ size_t size;
+ static char warned = 0;
+
+ lsa = listgetdata((ln = listhead (update)));
+ assert (lsa->data);
+
+ if ((OSPF_LS_UPD_MIN_SIZE + ntohs (lsa->data->length))
+ > ospf_packet_max (oi))
+ {
+ if (!warned)
+ {
+ zlog_warn ("ospf_ls_upd_packet_new: oversized LSA encountered!"
+ "will need to fragment. Not optimal. Try divide up"
+ " your network with areas. Use 'debug ospf packet send'"
+ " to see details, or look at 'show ip ospf database ..'");
+ warned = 1;
+ }
+
+ if (IS_DEBUG_OSPF_PACKET (0, SEND))
+ zlog_debug ("ospf_ls_upd_packet_new: oversized LSA id:%s,"
+ " %d bytes originated by %s, will be fragmented!",
+ inet_ntoa (lsa->data->id),
+ ntohs (lsa->data->length),
+ inet_ntoa (lsa->data->adv_router));
+
+ /*
+ * Allocate just enough to fit this LSA only, to avoid including other
+ * LSAs in fragmented LSA Updates.
+ */
+ size = ntohs (lsa->data->length) + (oi->ifp->mtu - ospf_packet_max (oi))
+ + OSPF_LS_UPD_MIN_SIZE;
+ }
+ else
+ size = oi->ifp->mtu;
+
+ /* XXX Should this be - sizeof(struct ip)?? -gdt */
+ if (size > OSPF_MAX_PACKET_SIZE)
+ {
+ zlog_warn ("ospf_ls_upd_packet_new: oversized LSA id:%s too big,"
+ " %d bytes, packet size %ld, dropping it completely."
+ " OSPF routing is broken!",
+ inet_ntoa (lsa->data->id), ntohs (lsa->data->length),
+ (long int) size);
+ list_delete_node (update, ln);
+ return NULL;
+ }
+
+ return ospf_packet_new (size);
+}
+
static void
-ospf_ls_upd_queue_send (struct ospf_interface *oi, list update,
+ospf_ls_upd_queue_send (struct ospf_interface *oi, struct list *update,
struct in_addr addr)
{
struct ospf_packet *op;
u_int16_t length = OSPF_HEADER_SIZE;
if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("listcount = %d, dst %s", listcount (update), inet_ntoa(addr));
-
- op = ospf_packet_new (oi->ifp->mtu);
+ zlog_debug ("listcount = %d, dst %s", listcount (update), inet_ntoa(addr));
+
+ op = ospf_ls_upd_packet_new (update, oi);
/* Prepare OSPF common header. */
ospf_make_header (OSPF_MSG_LS_UPD, oi, op->s);
- /* Prepare OSPF Link State Update body. */
- /* Includes Type-7 translation. */
+ /* Prepare OSPF Link State Update body.
+ * Includes Type-7 translation.
+ */
length += ospf_make_ls_upd (oi, update, op->s);
/* Fill OSPF header. */
{
struct ospf_interface *oi = THREAD_ARG(thread);
struct route_node *rn;
+ struct route_node *rnext;
+ struct list *update;
+ char again = 0;
oi->t_ls_upd_event = NULL;
if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("ospf_ls_upd_send_queue start");
+ zlog_debug ("ospf_ls_upd_send_queue start");
- for (rn = route_top (oi->ls_upd_queue); rn; rn = route_next (rn))
+ for (rn = route_top (oi->ls_upd_queue); rn; rn = rnext)
{
+ rnext = route_next (rn);
+
if (rn->info == NULL)
- continue;
-
- while (!list_isempty ((list)rn->info))
- ospf_ls_upd_queue_send (oi, rn->info, rn->p.u.prefix4);
+ continue;
+
+ update = (struct list *)rn->info;
- list_delete (rn->info);
- rn->info = NULL;
+ ospf_ls_upd_queue_send (oi, update, rn->p.u.prefix4);
- route_unlock_node (rn);
+ /* list might not be empty. */
+ if (listcount(update) == 0)
+ {
+ list_delete (rn->info);
+ rn->info = NULL;
+ route_unlock_node (rn);
+ }
+ else
+ again = 1;
+ }
+
+ if (again != 0)
+ {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug ("ospf_ls_upd_send_queue: update lists not cleared,"
+ " %d nodes to try again, raising new event", again);
+ oi->t_ls_upd_event =
+ thread_add_event (master, ospf_ls_upd_send_queue_event, oi, 0);
}
if (IS_DEBUG_OSPF_EVENT)
- zlog_info ("ospf_ls_upd_send_queue stop");
+ zlog_debug ("ospf_ls_upd_send_queue stop");
+
return 0;
}
void
-ospf_ls_upd_send (struct ospf_neighbor *nbr, list update, int flag)
+ospf_ls_upd_send (struct ospf_neighbor *nbr, struct list *update, int flag)
{
struct ospf_interface *oi;
+ struct ospf_lsa *lsa;
struct prefix_ipv4 p;
struct route_node *rn;
- listnode n;
+ struct listnode *node;
oi = nbr->oi;
if (rn->info == NULL)
rn->info = list_new ();
- for (n = listhead (update); n; nextnode (n))
- listnode_add (rn->info, ospf_lsa_lock (getdata (n)));
+ for (ALL_LIST_ELEMENTS_RO (update, node, lsa))
+ {
+ ospf_lsa_lock (lsa);
+ listnode_add (rn->info, lsa);
+ }
if (oi->t_ls_upd_event == NULL)
oi->t_ls_upd_event =
}
static void
-ospf_ls_ack_send_list (struct ospf_interface *oi, list ack, struct in_addr dst)
+ospf_ls_ack_send_list (struct ospf_interface *oi, struct list *ack,
+ struct in_addr dst)
{
struct ospf_packet *op;
u_int16_t length = OSPF_HEADER_SIZE;
dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
+ else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
+ dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
else
dst.s_addr = htonl (OSPF_ALLDROUTERS);