mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-03 23:47:16 +00:00 
			
		
		
		
	Previous fix was incomplete, as calling ospf6_lsa_unlock() frees 'req' but it does not put it to zero, so it was called ospf6_lsdb_remove() afterwards even being 'req' already freed. Signed-off-by: F. Aragon <paco@voltanet.io>
		
			
				
	
	
		
			1082 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1082 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (C) 2003 Yasuhiro Ohara
 | 
						|
 *
 | 
						|
 * This file is part of GNU Zebra.
 | 
						|
 *
 | 
						|
 * GNU Zebra is free software; you can redistribute it and/or modify it
 | 
						|
 * under the terms of the GNU General Public License as published by the
 | 
						|
 * Free Software Foundation; either version 2, or (at your option) any
 | 
						|
 * later version.
 | 
						|
 *
 | 
						|
 * GNU Zebra is distributed in the hope that it will be useful, but
 | 
						|
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
 * General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License along
 | 
						|
 * with this program; see the file COPYING; if not, write to the Free Software
 | 
						|
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 | 
						|
 */
 | 
						|
 | 
						|
#include <zebra.h>
 | 
						|
 | 
						|
#include "log.h"
 | 
						|
#include "thread.h"
 | 
						|
#include "linklist.h"
 | 
						|
#include "vty.h"
 | 
						|
#include "command.h"
 | 
						|
 | 
						|
#include "ospf6d.h"
 | 
						|
#include "ospf6_proto.h"
 | 
						|
#include "ospf6_lsa.h"
 | 
						|
#include "ospf6_lsdb.h"
 | 
						|
#include "ospf6_message.h"
 | 
						|
#include "ospf6_route.h"
 | 
						|
#include "ospf6_spf.h"
 | 
						|
 | 
						|
#include "ospf6_top.h"
 | 
						|
#include "ospf6_area.h"
 | 
						|
#include "ospf6_interface.h"
 | 
						|
#include "ospf6_neighbor.h"
 | 
						|
 | 
						|
#include "ospf6_flood.h"
 | 
						|
 | 
						|
unsigned char conf_debug_ospf6_flooding;
 | 
						|
 | 
						|
struct ospf6_lsdb *ospf6_get_scoped_lsdb(struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	struct ospf6_lsdb *lsdb = NULL;
 | 
						|
	switch (OSPF6_LSA_SCOPE(lsa->header->type)) {
 | 
						|
	case OSPF6_SCOPE_LINKLOCAL:
 | 
						|
		lsdb = OSPF6_INTERFACE(lsa->lsdb->data)->lsdb;
 | 
						|
		break;
 | 
						|
	case OSPF6_SCOPE_AREA:
 | 
						|
		lsdb = OSPF6_AREA(lsa->lsdb->data)->lsdb;
 | 
						|
		break;
 | 
						|
	case OSPF6_SCOPE_AS:
 | 
						|
		lsdb = OSPF6_PROCESS(lsa->lsdb->data)->lsdb;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		assert(0);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	return lsdb;
 | 
						|
}
 | 
						|
 | 
						|
struct ospf6_lsdb *ospf6_get_scoped_lsdb_self(struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	struct ospf6_lsdb *lsdb_self = NULL;
 | 
						|
	switch (OSPF6_LSA_SCOPE(lsa->header->type)) {
 | 
						|
	case OSPF6_SCOPE_LINKLOCAL:
 | 
						|
		lsdb_self = OSPF6_INTERFACE(lsa->lsdb->data)->lsdb_self;
 | 
						|
		break;
 | 
						|
	case OSPF6_SCOPE_AREA:
 | 
						|
		lsdb_self = OSPF6_AREA(lsa->lsdb->data)->lsdb_self;
 | 
						|
		break;
 | 
						|
	case OSPF6_SCOPE_AS:
 | 
						|
		lsdb_self = OSPF6_PROCESS(lsa->lsdb->data)->lsdb_self;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		assert(0);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	return lsdb_self;
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_lsa_originate(struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	struct ospf6_lsa *old;
 | 
						|
	struct ospf6_lsdb *lsdb_self;
 | 
						|
 | 
						|
	/* find previous LSA */
 | 
						|
	old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
 | 
						|
				lsa->header->adv_router, lsa->lsdb);
 | 
						|
 | 
						|
	/* if the new LSA does not differ from previous,
 | 
						|
	   suppress this update of the LSA */
 | 
						|
	if (old && !OSPF6_LSA_IS_DIFFER(lsa, old)) {
 | 
						|
		if (IS_OSPF6_DEBUG_ORIGINATE_TYPE(lsa->header->type))
 | 
						|
			zlog_debug("Suppress updating LSA: %s", lsa->name);
 | 
						|
		ospf6_lsa_delete(lsa);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* store it in the LSDB for self-originated LSAs */
 | 
						|
	lsdb_self = ospf6_get_scoped_lsdb_self(lsa);
 | 
						|
	ospf6_lsdb_add(ospf6_lsa_copy(lsa), lsdb_self);
 | 
						|
 | 
						|
	lsa->refresh = NULL;
 | 
						|
	thread_add_timer(master, ospf6_lsa_refresh, lsa, OSPF_LS_REFRESH_TIME,
 | 
						|
			 &lsa->refresh);
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)
 | 
						|
	    || IS_OSPF6_DEBUG_ORIGINATE_TYPE(lsa->header->type)) {
 | 
						|
		zlog_debug("LSA Originate:");
 | 
						|
		ospf6_lsa_header_print(lsa);
 | 
						|
	}
 | 
						|
 | 
						|
	ospf6_install_lsa(lsa);
 | 
						|
	ospf6_flood(NULL, lsa);
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_lsa_originate_process(struct ospf6_lsa *lsa, struct ospf6 *process)
 | 
						|
{
 | 
						|
	lsa->lsdb = process->lsdb;
 | 
						|
	ospf6_lsa_originate(lsa);
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_lsa_originate_area(struct ospf6_lsa *lsa, struct ospf6_area *oa)
 | 
						|
{
 | 
						|
	lsa->lsdb = oa->lsdb;
 | 
						|
	ospf6_lsa_originate(lsa);
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa,
 | 
						|
				   struct ospf6_interface *oi)
 | 
						|
{
 | 
						|
	lsa->lsdb = oi->lsdb;
 | 
						|
	ospf6_lsa_originate(lsa);
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_lsa_purge(struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	struct ospf6_lsa *self;
 | 
						|
	struct ospf6_lsdb *lsdb_self;
 | 
						|
 | 
						|
	/* remove it from the LSDB for self-originated LSAs */
 | 
						|
	lsdb_self = ospf6_get_scoped_lsdb_self(lsa);
 | 
						|
	self = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
 | 
						|
				 lsa->header->adv_router, lsdb_self);
 | 
						|
	if (self) {
 | 
						|
		THREAD_OFF(self->expire);
 | 
						|
		THREAD_OFF(self->refresh);
 | 
						|
		ospf6_lsdb_remove(self, lsdb_self);
 | 
						|
	}
 | 
						|
 | 
						|
	ospf6_lsa_premature_aging(lsa);
 | 
						|
}
 | 
						|
 | 
						|
/* Puring Multi Link-State IDs LSAs:
 | 
						|
 * Same Advertising Router with Multiple Link-State IDs
 | 
						|
 * LSAs, purging require to traverse all Link-State IDs
 | 
						|
 */
 | 
						|
void ospf6_lsa_purge_multi_ls_id(struct ospf6_area *oa, struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	int ls_id = 0;
 | 
						|
	struct ospf6_lsa *lsa_next;
 | 
						|
	uint16_t type;
 | 
						|
 | 
						|
	type = lsa->header->type;
 | 
						|
 | 
						|
	ospf6_lsa_purge(lsa);
 | 
						|
 | 
						|
	lsa_next = ospf6_lsdb_lookup(type, htonl(++ls_id),
 | 
						|
				     oa->ospf6->router_id, oa->lsdb);
 | 
						|
	while (lsa_next) {
 | 
						|
		ospf6_lsa_purge(lsa_next);
 | 
						|
		lsa_next = ospf6_lsdb_lookup(type, htonl(++ls_id),
 | 
						|
					     oa->ospf6->router_id, oa->lsdb);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_increment_retrans_count(struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	/* The LSA must be the original one (see the description
 | 
						|
	   in ospf6_decrement_retrans_count () below) */
 | 
						|
	lsa->retrans_count++;
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_decrement_retrans_count(struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	struct ospf6_lsdb *lsdb;
 | 
						|
	struct ospf6_lsa *orig;
 | 
						|
 | 
						|
	/* The LSA must be on the retrans-list of a neighbor. It means
 | 
						|
	   the "lsa" is a copied one, and we have to decrement the
 | 
						|
	   retransmission count of the original one (instead of this "lsa"'s).
 | 
						|
	   In order to find the original LSA, first we have to find
 | 
						|
	   appropriate LSDB that have the original LSA. */
 | 
						|
	lsdb = ospf6_get_scoped_lsdb(lsa);
 | 
						|
 | 
						|
	/* Find the original LSA of which the retrans_count should be
 | 
						|
	 * decremented */
 | 
						|
	orig = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
 | 
						|
				 lsa->header->adv_router, lsdb);
 | 
						|
	if (orig) {
 | 
						|
		orig->retrans_count--;
 | 
						|
		assert(orig->retrans_count >= 0);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* RFC2328 section 13.2 Installing LSAs in the database */
 | 
						|
void ospf6_install_lsa(struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	struct timeval now;
 | 
						|
	struct ospf6_lsa *old;
 | 
						|
 | 
						|
	/* Remove the old instance from all neighbors' Link state
 | 
						|
	   retransmission list (RFC2328 13.2 last paragraph) */
 | 
						|
	old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
 | 
						|
				lsa->header->adv_router, lsa->lsdb);
 | 
						|
	if (old) {
 | 
						|
		THREAD_OFF(old->expire);
 | 
						|
		THREAD_OFF(old->refresh);
 | 
						|
		ospf6_flood_clear(old);
 | 
						|
	}
 | 
						|
 | 
						|
	monotime(&now);
 | 
						|
	if (!OSPF6_LSA_IS_MAXAGE(lsa)) {
 | 
						|
		lsa->expire = NULL;
 | 
						|
		thread_add_timer(master, ospf6_lsa_expire, lsa,
 | 
						|
				 OSPF_LSA_MAXAGE + lsa->birth.tv_sec
 | 
						|
					 - now.tv_sec,
 | 
						|
				 &lsa->expire);
 | 
						|
	} else
 | 
						|
		lsa->expire = NULL;
 | 
						|
 | 
						|
	if (OSPF6_LSA_IS_SEQWRAP(lsa)
 | 
						|
	    && !(CHECK_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED)
 | 
						|
		 && lsa->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER))) {
 | 
						|
		if (IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type))
 | 
						|
			zlog_debug("lsa install wrapping: sequence 0x%x",
 | 
						|
				   ntohl(lsa->header->seqnum));
 | 
						|
		SET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED);
 | 
						|
		/* in lieu of premature_aging, since we do not want to recreate
 | 
						|
		 * this lsa
 | 
						|
		 * and/or mess with timers etc, we just want to wrap the
 | 
						|
		 * sequence number
 | 
						|
		 * and reflood the lsa before continuing.
 | 
						|
		 * NOTE: Flood needs to be called right after this function
 | 
						|
		 * call, by the
 | 
						|
		 * caller
 | 
						|
		 */
 | 
						|
		lsa->header->seqnum = htonl(OSPF_MAX_SEQUENCE_NUMBER);
 | 
						|
		lsa->header->age = htons(OSPF_LSA_MAXAGE);
 | 
						|
		ospf6_lsa_checksum(lsa->header);
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)
 | 
						|
	    || IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type))
 | 
						|
		zlog_debug("%s Install LSA: %s age %d seqnum %x in LSDB.",
 | 
						|
			   __PRETTY_FUNCTION__, lsa->name,
 | 
						|
			   ntohs(lsa->header->age), ntohl(lsa->header->seqnum));
 | 
						|
 | 
						|
	/* actually install */
 | 
						|
	lsa->installed = now;
 | 
						|
	ospf6_lsdb_add(lsa, lsa->lsdb);
 | 
						|
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
/* RFC2740 section 3.5.2. Sending Link State Update packets */
 | 
						|
/* RFC2328 section 13.3 Next step in the flooding procedure */
 | 
						|
void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
 | 
						|
			   struct ospf6_interface *oi)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_neighbor *on;
 | 
						|
	struct ospf6_lsa *req;
 | 
						|
	int retrans_added = 0;
 | 
						|
	int is_debug = 0;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_FLOODING
 | 
						|
	    || IS_OSPF6_DEBUG_FLOOD_TYPE(lsa->header->type)) {
 | 
						|
		is_debug++;
 | 
						|
		zlog_debug("Flooding on %s: %s", oi->interface->name,
 | 
						|
			   lsa->name);
 | 
						|
	}
 | 
						|
 | 
						|
	/* (1) For each neighbor */
 | 
						|
	for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug("To neighbor %s", on->name);
 | 
						|
 | 
						|
		/* (a) if neighbor state < Exchange, examin next */
 | 
						|
		if (on->state < OSPF6_NEIGHBOR_EXCHANGE) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"Neighbor state less than ExChange, next neighbor");
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		/* (b) if neighbor not yet Full, check request-list */
 | 
						|
		if (on->state != OSPF6_NEIGHBOR_FULL) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug("Neighbor not yet Full");
 | 
						|
 | 
						|
			req = ospf6_lsdb_lookup(
 | 
						|
				lsa->header->type, lsa->header->id,
 | 
						|
				lsa->header->adv_router, on->request_list);
 | 
						|
			if (req == NULL) {
 | 
						|
				if (is_debug)
 | 
						|
					zlog_debug(
 | 
						|
						"Not on request-list for this neighbor");
 | 
						|
				/* fall through */
 | 
						|
			} else {
 | 
						|
				/* If new LSA less recent, examin next neighbor
 | 
						|
				 */
 | 
						|
				if (ospf6_lsa_compare(lsa, req) > 0) {
 | 
						|
					if (is_debug)
 | 
						|
						zlog_debug(
 | 
						|
							"Requesting is older, next neighbor");
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
 | 
						|
				/* If the same instance, delete from
 | 
						|
				   request-list and
 | 
						|
				   examin next neighbor */
 | 
						|
				if (ospf6_lsa_compare(lsa, req) == 0) {
 | 
						|
					if (is_debug)
 | 
						|
						zlog_debug(
 | 
						|
							"Requesting the same, remove it, next neighbor");
 | 
						|
					if (req == on->last_ls_req) {
 | 
						|
						ospf6_lsa_unlock(req);
 | 
						|
						on->last_ls_req = NULL;
 | 
						|
					}
 | 
						|
					ospf6_lsdb_remove(req,
 | 
						|
							  on->request_list);
 | 
						|
					ospf6_check_nbr_loading(on);
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
 | 
						|
				/* If the new LSA is more recent, delete from
 | 
						|
				 * request-list */
 | 
						|
				if (ospf6_lsa_compare(lsa, req) < 0) {
 | 
						|
					if (is_debug)
 | 
						|
						zlog_debug(
 | 
						|
							"Received is newer, remove requesting");
 | 
						|
					if (req == on->last_ls_req) {
 | 
						|
						ospf6_lsa_unlock(req);
 | 
						|
						req = NULL;
 | 
						|
						on->last_ls_req = NULL;
 | 
						|
					}
 | 
						|
					if (req)
 | 
						|
						ospf6_lsdb_remove(req,
 | 
						|
							on->request_list);
 | 
						|
					ospf6_check_nbr_loading(on);
 | 
						|
					/* fall through */
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/* (c) If the new LSA was received from this neighbor,
 | 
						|
		   examin next neighbor */
 | 
						|
		if (from == on) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"Received is from the neighbor, next neighbor");
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if (ospf6->inst_shutdown) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"%s: Send LSA %s (age %d) update now",
 | 
						|
					__PRETTY_FUNCTION__, lsa->name,
 | 
						|
					ntohs(lsa->header->age));
 | 
						|
			ospf6_lsupdate_send_neighbor_now(on, lsa);
 | 
						|
			continue;
 | 
						|
		} else {
 | 
						|
			/* (d) add retrans-list, schedule retransmission */
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug("Add retrans-list of this neighbor");
 | 
						|
			ospf6_increment_retrans_count(lsa);
 | 
						|
			ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list);
 | 
						|
			thread_add_timer(master, ospf6_lsupdate_send_neighbor,
 | 
						|
					 on, on->ospf6_if->rxmt_interval,
 | 
						|
					 &on->thread_send_lsupdate);
 | 
						|
			retrans_added++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* (2) examin next interface if not added to retrans-list */
 | 
						|
	if (retrans_added == 0) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"No retransmission scheduled, next interface");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* (3) If the new LSA was received on this interface,
 | 
						|
	   and it was from DR or BDR, examin next interface */
 | 
						|
	if (from && from->ospf6_if == oi
 | 
						|
	    && (from->router_id == oi->drouter
 | 
						|
		|| from->router_id == oi->bdrouter)) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"Received is from the I/F's DR or BDR, next interface");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* (4) If the new LSA was received on this interface,
 | 
						|
	   and the interface state is BDR, examin next interface */
 | 
						|
	if (from && from->ospf6_if == oi) {
 | 
						|
		if (oi->state == OSPF6_INTERFACE_BDR) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"Received is from the I/F, itself BDR, next interface");
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		SET_FLAG(lsa->flag, OSPF6_LSA_FLOODBACK);
 | 
						|
	}
 | 
						|
 | 
						|
	/* (5) flood the LSA out the interface. */
 | 
						|
	if (is_debug)
 | 
						|
		zlog_debug("Schedule flooding for the interface");
 | 
						|
	if ((oi->type == OSPF_IFTYPE_BROADCAST)
 | 
						|
	    || (oi->type == OSPF_IFTYPE_POINTOPOINT)) {
 | 
						|
		ospf6_lsdb_add(ospf6_lsa_copy(lsa), oi->lsupdate_list);
 | 
						|
		thread_add_event(master, ospf6_lsupdate_send_interface, oi, 0,
 | 
						|
				 &oi->thread_send_lsupdate);
 | 
						|
	} else {
 | 
						|
		/* reschedule retransmissions to all neighbors */
 | 
						|
		for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
 | 
						|
			THREAD_OFF(on->thread_send_lsupdate);
 | 
						|
			on->thread_send_lsupdate = NULL;
 | 
						|
			thread_add_event(master, ospf6_lsupdate_send_neighbor,
 | 
						|
					 on, 0, &on->thread_send_lsupdate);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_flood_area(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
 | 
						|
		      struct ospf6_area *oa)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_interface *oi;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) {
 | 
						|
		if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_LINKLOCAL
 | 
						|
		    && oi != OSPF6_INTERFACE(lsa->lsdb->data))
 | 
						|
			continue;
 | 
						|
 | 
						|
#if 0
 | 
						|
      if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AS &&
 | 
						|
          ospf6_is_interface_virtual_link (oi))
 | 
						|
        continue;
 | 
						|
#endif /*0*/
 | 
						|
 | 
						|
		ospf6_flood_interface(from, lsa, oi);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_flood_process(struct ospf6_neighbor *from,
 | 
						|
				struct ospf6_lsa *lsa, struct ospf6 *process)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_area *oa;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(process->area_list, node, nnode, oa)) {
 | 
						|
		if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_AREA
 | 
						|
		    && oa != OSPF6_AREA(lsa->lsdb->data))
 | 
						|
			continue;
 | 
						|
		if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_LINKLOCAL
 | 
						|
		    && oa != OSPF6_INTERFACE(lsa->lsdb->data)->area)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL
 | 
						|
		    && IS_AREA_STUB(oa))
 | 
						|
			continue;
 | 
						|
 | 
						|
		ospf6_flood_area(from, lsa, oa);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_flood(struct ospf6_neighbor *from, struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	ospf6_flood_process(from, lsa, ospf6);
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_flood_clear_interface(struct ospf6_lsa *lsa,
 | 
						|
					struct ospf6_interface *oi)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_neighbor *on;
 | 
						|
	struct ospf6_lsa *rem;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
 | 
						|
		rem = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
 | 
						|
					lsa->header->adv_router,
 | 
						|
					on->retrans_list);
 | 
						|
		if (rem && !ospf6_lsa_compare(rem, lsa)) {
 | 
						|
			if (IS_OSPF6_DEBUG_FLOODING
 | 
						|
			    || IS_OSPF6_DEBUG_FLOOD_TYPE(lsa->header->type))
 | 
						|
				zlog_debug("Remove %s from retrans_list of %s",
 | 
						|
					   rem->name, on->name);
 | 
						|
			ospf6_decrement_retrans_count(rem);
 | 
						|
			ospf6_lsdb_remove(rem, on->retrans_list);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_flood_clear_area(struct ospf6_lsa *lsa, struct ospf6_area *oa)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_interface *oi;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) {
 | 
						|
		if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_LINKLOCAL
 | 
						|
		    && oi != OSPF6_INTERFACE(lsa->lsdb->data))
 | 
						|
			continue;
 | 
						|
 | 
						|
#if 0
 | 
						|
      if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AS &&
 | 
						|
          ospf6_is_interface_virtual_link (oi))
 | 
						|
        continue;
 | 
						|
#endif /*0*/
 | 
						|
 | 
						|
		ospf6_flood_clear_interface(lsa, oi);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_flood_clear_process(struct ospf6_lsa *lsa,
 | 
						|
				      struct ospf6 *process)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_area *oa;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(process->area_list, node, nnode, oa)) {
 | 
						|
		if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_AREA
 | 
						|
		    && oa != OSPF6_AREA(lsa->lsdb->data))
 | 
						|
			continue;
 | 
						|
		if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_LINKLOCAL
 | 
						|
		    && oa != OSPF6_INTERFACE(lsa->lsdb->data)->area)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL
 | 
						|
		    && IS_AREA_STUB(oa))
 | 
						|
			continue;
 | 
						|
 | 
						|
		ospf6_flood_clear_area(lsa, oa);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_flood_clear(struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	ospf6_flood_clear_process(lsa, ospf6);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* RFC2328 13.5 (Table 19): Sending link state acknowledgements. */
 | 
						|
static void ospf6_acknowledge_lsa_bdrouter(struct ospf6_lsa *lsa,
 | 
						|
					   int ismore_recent,
 | 
						|
					   struct ospf6_neighbor *from)
 | 
						|
{
 | 
						|
	struct ospf6_interface *oi;
 | 
						|
	int is_debug = 0;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_FLOODING
 | 
						|
	    || IS_OSPF6_DEBUG_FLOOD_TYPE(lsa->header->type))
 | 
						|
		is_debug++;
 | 
						|
 | 
						|
	assert(from && from->ospf6_if);
 | 
						|
	oi = from->ospf6_if;
 | 
						|
 | 
						|
	/* LSA is more recent than database copy, but was not flooded
 | 
						|
	   back out receiving interface. Delayed acknowledgement sent
 | 
						|
	   if advertisement received from Designated Router,
 | 
						|
	   otherwide do nothing. */
 | 
						|
	if (ismore_recent < 0) {
 | 
						|
		if (oi->drouter == from->router_id) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"Delayed acknowledgement (BDR & MoreRecent & from DR)");
 | 
						|
			/* Delayed acknowledgement */
 | 
						|
			ospf6_lsdb_add(ospf6_lsa_copy(lsa), oi->lsack_list);
 | 
						|
			thread_add_timer(master, ospf6_lsack_send_interface, oi,
 | 
						|
					 3, &oi->thread_send_lsack);
 | 
						|
		} else {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"No acknowledgement (BDR & MoreRecent & ! from DR)");
 | 
						|
		}
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* LSA is a duplicate, and was treated as an implied acknowledgement.
 | 
						|
	   Delayed acknowledgement sent if advertisement received from
 | 
						|
	   Designated Router, otherwise do nothing */
 | 
						|
	if (CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE)
 | 
						|
	    && CHECK_FLAG(lsa->flag, OSPF6_LSA_IMPLIEDACK)) {
 | 
						|
		if (oi->drouter == from->router_id) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"Delayed acknowledgement (BDR & Duplicate & ImpliedAck & from DR)");
 | 
						|
			/* Delayed acknowledgement */
 | 
						|
			ospf6_lsdb_add(ospf6_lsa_copy(lsa), oi->lsack_list);
 | 
						|
			thread_add_timer(master, ospf6_lsack_send_interface, oi,
 | 
						|
					 3, &oi->thread_send_lsack);
 | 
						|
		} else {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"No acknowledgement (BDR & Duplicate & ImpliedAck & ! from DR)");
 | 
						|
		}
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* LSA is a duplicate, and was not treated as an implied
 | 
						|
	   acknowledgement.
 | 
						|
	   Direct acknowledgement sent */
 | 
						|
	if (CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE)
 | 
						|
	    && !CHECK_FLAG(lsa->flag, OSPF6_LSA_IMPLIEDACK)) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug("Direct acknowledgement (BDR & Duplicate)");
 | 
						|
		ospf6_lsdb_add(ospf6_lsa_copy(lsa), from->lsack_list);
 | 
						|
		thread_add_event(master, ospf6_lsack_send_neighbor, from, 0,
 | 
						|
				 &from->thread_send_lsack);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* LSA's LS age is equal to Maxage, and there is no current instance
 | 
						|
	   of the LSA in the link state database, and none of router's
 | 
						|
	   neighbors are in states Exchange or Loading */
 | 
						|
	/* Direct acknowledgement sent, but this case is handled in
 | 
						|
	   early of ospf6_receive_lsa () */
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_acknowledge_lsa_allother(struct ospf6_lsa *lsa,
 | 
						|
					   int ismore_recent,
 | 
						|
					   struct ospf6_neighbor *from)
 | 
						|
{
 | 
						|
	struct ospf6_interface *oi;
 | 
						|
	int is_debug = 0;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_FLOODING
 | 
						|
	    || IS_OSPF6_DEBUG_FLOOD_TYPE(lsa->header->type))
 | 
						|
		is_debug++;
 | 
						|
 | 
						|
	assert(from && from->ospf6_if);
 | 
						|
	oi = from->ospf6_if;
 | 
						|
 | 
						|
	/* LSA has been flood back out receiving interface.
 | 
						|
	   No acknowledgement sent. */
 | 
						|
	if (CHECK_FLAG(lsa->flag, OSPF6_LSA_FLOODBACK)) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug("No acknowledgement (AllOther & FloodBack)");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* LSA is more recent than database copy, but was not flooded
 | 
						|
	   back out receiving interface. Delayed acknowledgement sent. */
 | 
						|
	if (ismore_recent < 0) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"Delayed acknowledgement (AllOther & MoreRecent)");
 | 
						|
		/* Delayed acknowledgement */
 | 
						|
		ospf6_lsdb_add(ospf6_lsa_copy(lsa), oi->lsack_list);
 | 
						|
		thread_add_timer(master, ospf6_lsack_send_interface, oi, 3,
 | 
						|
				 &oi->thread_send_lsack);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* LSA is a duplicate, and was treated as an implied acknowledgement.
 | 
						|
	   No acknowledgement sent. */
 | 
						|
	if (CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE)
 | 
						|
	    && CHECK_FLAG(lsa->flag, OSPF6_LSA_IMPLIEDACK)) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"No acknowledgement (AllOther & Duplicate & ImpliedAck)");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* LSA is a duplicate, and was not treated as an implied
 | 
						|
	   acknowledgement.
 | 
						|
	   Direct acknowledgement sent */
 | 
						|
	if (CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE)
 | 
						|
	    && !CHECK_FLAG(lsa->flag, OSPF6_LSA_IMPLIEDACK)) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"Direct acknowledgement (AllOther & Duplicate)");
 | 
						|
		ospf6_lsdb_add(ospf6_lsa_copy(lsa), from->lsack_list);
 | 
						|
		thread_add_event(master, ospf6_lsack_send_neighbor, from, 0,
 | 
						|
				 &from->thread_send_lsack);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* LSA's LS age is equal to Maxage, and there is no current instance
 | 
						|
	   of the LSA in the link state database, and none of router's
 | 
						|
	   neighbors are in states Exchange or Loading */
 | 
						|
	/* Direct acknowledgement sent, but this case is handled in
 | 
						|
	   early of ospf6_receive_lsa () */
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_acknowledge_lsa(struct ospf6_lsa *lsa, int ismore_recent,
 | 
						|
				  struct ospf6_neighbor *from)
 | 
						|
{
 | 
						|
	struct ospf6_interface *oi;
 | 
						|
 | 
						|
	assert(from && from->ospf6_if);
 | 
						|
	oi = from->ospf6_if;
 | 
						|
 | 
						|
	if (oi->state == OSPF6_INTERFACE_BDR)
 | 
						|
		ospf6_acknowledge_lsa_bdrouter(lsa, ismore_recent, from);
 | 
						|
	else
 | 
						|
		ospf6_acknowledge_lsa_allother(lsa, ismore_recent, from);
 | 
						|
}
 | 
						|
 | 
						|
/* RFC2328 section 13 (4):
 | 
						|
   if MaxAge LSA and if we have no instance, and no neighbor
 | 
						|
   is in states Exchange or Loading
 | 
						|
   returns 1 if match this case, else returns 0 */
 | 
						|
static int ospf6_is_maxage_lsa_drop(struct ospf6_lsa *lsa,
 | 
						|
				    struct ospf6_neighbor *from)
 | 
						|
{
 | 
						|
	struct ospf6_neighbor *on;
 | 
						|
	struct ospf6_interface *oi;
 | 
						|
	struct ospf6_area *oa;
 | 
						|
	struct ospf6 *process = NULL;
 | 
						|
	struct listnode *i, *j, *k;
 | 
						|
	int count = 0;
 | 
						|
 | 
						|
	if (!OSPF6_LSA_IS_MAXAGE(lsa))
 | 
						|
		return 0;
 | 
						|
 | 
						|
	if (ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
 | 
						|
			      lsa->header->adv_router, lsa->lsdb))
 | 
						|
		return 0;
 | 
						|
 | 
						|
	process = from->ospf6_if->area->ospf6;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(process->area_list, i, oa))
 | 
						|
		for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi))
 | 
						|
			for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on))
 | 
						|
				if (on->state == OSPF6_NEIGHBOR_EXCHANGE
 | 
						|
				    || on->state == OSPF6_NEIGHBOR_LOADING)
 | 
						|
					count++;
 | 
						|
 | 
						|
	if (count == 0)
 | 
						|
		return 1;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* RFC2328 section 13 The Flooding Procedure */
 | 
						|
void ospf6_receive_lsa(struct ospf6_neighbor *from,
 | 
						|
		       struct ospf6_lsa_header *lsa_header)
 | 
						|
{
 | 
						|
	struct ospf6_lsa *new = NULL, *old = NULL, *rem = NULL;
 | 
						|
	int ismore_recent;
 | 
						|
	int is_debug = 0;
 | 
						|
	unsigned int time_delta_ms;
 | 
						|
 | 
						|
	ismore_recent = 1;
 | 
						|
	assert(from);
 | 
						|
 | 
						|
	/* make lsa structure for received lsa */
 | 
						|
	new = ospf6_lsa_create(lsa_header);
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_FLOODING
 | 
						|
	    || IS_OSPF6_DEBUG_FLOOD_TYPE(new->header->type)) {
 | 
						|
		is_debug++;
 | 
						|
		zlog_debug("LSA Receive from %s", from->name);
 | 
						|
		ospf6_lsa_header_print(new);
 | 
						|
	}
 | 
						|
 | 
						|
	/* (1) LSA Checksum */
 | 
						|
	if (!ospf6_lsa_checksum_valid(new->header)) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug("Wrong LSA Checksum, discard");
 | 
						|
		ospf6_lsa_delete(new);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* (2) Examine the LSA's LS type.
 | 
						|
	   RFC2470 3.5.1. Receiving Link State Update packets  */
 | 
						|
	if (IS_AREA_STUB(from->ospf6_if->area)
 | 
						|
	    && OSPF6_LSA_SCOPE(new->header->type) == OSPF6_SCOPE_AS) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"AS-External-LSA (or AS-scope LSA) in stub area, discard");
 | 
						|
		ospf6_lsa_delete(new);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* (3) LSA which have reserved scope is discarded
 | 
						|
	   RFC2470 3.5.1. Receiving Link State Update packets  */
 | 
						|
	/* Flooding scope check. LSAs with unknown scope are discarded here.
 | 
						|
	   Set appropriate LSDB for the LSA */
 | 
						|
	switch (OSPF6_LSA_SCOPE(new->header->type)) {
 | 
						|
	case OSPF6_SCOPE_LINKLOCAL:
 | 
						|
		new->lsdb = from->ospf6_if->lsdb;
 | 
						|
		break;
 | 
						|
	case OSPF6_SCOPE_AREA:
 | 
						|
		new->lsdb = from->ospf6_if->area->lsdb;
 | 
						|
		break;
 | 
						|
	case OSPF6_SCOPE_AS:
 | 
						|
		new->lsdb = from->ospf6_if->area->ospf6->lsdb;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug("LSA has reserved scope, discard");
 | 
						|
		ospf6_lsa_delete(new);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* (4) if MaxAge LSA and if we have no instance, and no neighbor
 | 
						|
	       is in states Exchange or Loading */
 | 
						|
	if (ospf6_is_maxage_lsa_drop(new, from)) {
 | 
						|
		/* log */
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"Drop MaxAge LSA with direct acknowledgement.");
 | 
						|
 | 
						|
		/* a) Acknowledge back to neighbor (Direct acknowledgement,
 | 
						|
		 * 13.5) */
 | 
						|
		ospf6_lsdb_add(ospf6_lsa_copy(new), from->lsack_list);
 | 
						|
		thread_add_event(master, ospf6_lsack_send_neighbor, from, 0,
 | 
						|
				 &from->thread_send_lsack);
 | 
						|
 | 
						|
		/* b) Discard */
 | 
						|
		ospf6_lsa_delete(new);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* (5) */
 | 
						|
	/* lookup the same database copy in lsdb */
 | 
						|
	old = ospf6_lsdb_lookup(new->header->type, new->header->id,
 | 
						|
				new->header->adv_router, new->lsdb);
 | 
						|
	if (old) {
 | 
						|
		ismore_recent = ospf6_lsa_compare(new, old);
 | 
						|
		if (ntohl(new->header->seqnum) == ntohl(old->header->seqnum)) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug("Received is duplicated LSA");
 | 
						|
			SET_FLAG(new->flag, OSPF6_LSA_DUPLICATE);
 | 
						|
		}
 | 
						|
		if (old->header->adv_router
 | 
						|
			    == from->ospf6_if->area->ospf6->router_id
 | 
						|
		    && OSPF6_LSA_IS_MAXAGE(new)) {
 | 
						|
			ospf6_acknowledge_lsa(new, ismore_recent, from);
 | 
						|
			ospf6_lsa_delete(new);
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"%s: Received is self orig MAXAGE LSA %s, discard (ismore_recent %d)",
 | 
						|
					__PRETTY_FUNCTION__, old->name,
 | 
						|
					ismore_recent);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* if no database copy or received is more recent */
 | 
						|
	if (old == NULL || ismore_recent < 0) {
 | 
						|
		/* in case we have no database copy */
 | 
						|
		ismore_recent = -1;
 | 
						|
 | 
						|
		/* (a) MinLSArrival check */
 | 
						|
		if (old) {
 | 
						|
			struct timeval now, res;
 | 
						|
			monotime(&now);
 | 
						|
			timersub(&now, &old->installed, &res);
 | 
						|
			time_delta_ms =
 | 
						|
				(res.tv_sec * 1000) + (int)(res.tv_usec / 1000);
 | 
						|
			if (time_delta_ms
 | 
						|
			    < from->ospf6_if->area->ospf6->lsa_minarrival) {
 | 
						|
				if (is_debug)
 | 
						|
					zlog_debug(
 | 
						|
						"LSA can't be updated within MinLSArrival, %dms < %dms, discard",
 | 
						|
						time_delta_ms,
 | 
						|
						from->ospf6_if->area->ospf6
 | 
						|
							->lsa_minarrival);
 | 
						|
				ospf6_lsa_delete(new);
 | 
						|
				return; /* examin next lsa */
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		monotime(&new->received);
 | 
						|
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"Install, Flood, Possibly acknowledge the received LSA");
 | 
						|
 | 
						|
		/* Remove older copies of this LSA from retx lists */
 | 
						|
		if (old)
 | 
						|
			ospf6_flood_clear(old);
 | 
						|
 | 
						|
		/* (b) immediately flood and (c) remove from all retrans-list */
 | 
						|
		/* Prevent self-originated LSA to be flooded. this is to make
 | 
						|
		reoriginated instance of the LSA not to be rejected by other
 | 
						|
		routers
 | 
						|
		due to MinLSArrival. */
 | 
						|
		if (new->header->adv_router
 | 
						|
		    != from->ospf6_if->area->ospf6->router_id)
 | 
						|
			ospf6_flood(from, new);
 | 
						|
 | 
						|
		/* (d), installing lsdb, which may cause routing
 | 
						|
			table calculation (replacing database copy) */
 | 
						|
		ospf6_install_lsa(new);
 | 
						|
 | 
						|
		if (OSPF6_LSA_IS_MAXAGE(new))
 | 
						|
			ospf6_maxage_remove(from->ospf6_if->area->ospf6);
 | 
						|
 | 
						|
		/* (e) possibly acknowledge */
 | 
						|
		ospf6_acknowledge_lsa(new, ismore_recent, from);
 | 
						|
 | 
						|
		/* (f) Self Originated LSA, section 13.4 */
 | 
						|
		if (new->header->adv_router
 | 
						|
		    == from->ospf6_if->area->ospf6->router_id) {
 | 
						|
			/* Self-originated LSA (newer than ours) is received
 | 
						|
			   from
 | 
						|
			   another router. We have to make a new instance of the
 | 
						|
			   LSA
 | 
						|
			   or have to flush this LSA. */
 | 
						|
			if (is_debug) {
 | 
						|
				zlog_debug(
 | 
						|
					"Newer instance of the self-originated LSA");
 | 
						|
				zlog_debug("Schedule reorigination");
 | 
						|
			}
 | 
						|
			new->refresh = NULL;
 | 
						|
			thread_add_event(master, ospf6_lsa_refresh, new, 0,
 | 
						|
					 &new->refresh);
 | 
						|
		}
 | 
						|
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* (6) if there is instance on sending neighbor's request list */
 | 
						|
	if (ospf6_lsdb_lookup(new->header->type, new->header->id,
 | 
						|
			      new->header->adv_router, from->request_list)) {
 | 
						|
		/* if no database copy, should go above state (5) */
 | 
						|
		assert(old);
 | 
						|
 | 
						|
		if (is_debug) {
 | 
						|
			zlog_debug(
 | 
						|
				"Received is not newer, on the neighbor's request-list");
 | 
						|
			zlog_debug("BadLSReq, discard the received LSA");
 | 
						|
		}
 | 
						|
 | 
						|
		/* BadLSReq */
 | 
						|
		thread_add_event(master, bad_lsreq, from, 0, NULL);
 | 
						|
 | 
						|
		ospf6_lsa_delete(new);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* (7) if neither one is more recent */
 | 
						|
	if (ismore_recent == 0) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"The same instance as database copy (neither recent)");
 | 
						|
 | 
						|
		/* (a) if on retrans-list, Treat this LSA as an Ack: Implied Ack
 | 
						|
		 */
 | 
						|
		rem = ospf6_lsdb_lookup(new->header->type, new->header->id,
 | 
						|
					new->header->adv_router,
 | 
						|
					from->retrans_list);
 | 
						|
		if (rem) {
 | 
						|
			if (is_debug) {
 | 
						|
				zlog_debug(
 | 
						|
					"It is on the neighbor's retrans-list.");
 | 
						|
				zlog_debug(
 | 
						|
					"Treat as an Implied acknowledgement");
 | 
						|
			}
 | 
						|
			SET_FLAG(new->flag, OSPF6_LSA_IMPLIEDACK);
 | 
						|
			ospf6_decrement_retrans_count(rem);
 | 
						|
			ospf6_lsdb_remove(rem, from->retrans_list);
 | 
						|
		}
 | 
						|
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug("Possibly acknowledge and then discard");
 | 
						|
 | 
						|
		/* (b) possibly acknowledge */
 | 
						|
		ospf6_acknowledge_lsa(new, ismore_recent, from);
 | 
						|
 | 
						|
		ospf6_lsa_delete(new);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* (8) previous database copy is more recent */
 | 
						|
	{
 | 
						|
		assert(old);
 | 
						|
 | 
						|
		/* If database copy is in 'Seqnumber Wrapping',
 | 
						|
		   simply discard the received LSA */
 | 
						|
		if (OSPF6_LSA_IS_MAXAGE(old)
 | 
						|
		    && old->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER)) {
 | 
						|
			if (is_debug) {
 | 
						|
				zlog_debug("The LSA is in Seqnumber Wrapping");
 | 
						|
				zlog_debug("MaxAge & MaxSeqNum, discard");
 | 
						|
			}
 | 
						|
			ospf6_lsa_delete(new);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		/* Otherwise, Send database copy of this LSA to this neighbor */
 | 
						|
		{
 | 
						|
			if (is_debug) {
 | 
						|
				zlog_debug("Database copy is more recent.");
 | 
						|
				zlog_debug(
 | 
						|
					"Send back directly and then discard");
 | 
						|
			}
 | 
						|
 | 
						|
			/* Neighbor router sent recent age for LSA,
 | 
						|
			 * Router could be restarted while current copy is
 | 
						|
			 * MAXAGEd and not removed.*/
 | 
						|
			if (OSPF6_LSA_IS_MAXAGE(old)
 | 
						|
			    && !OSPF6_LSA_IS_MAXAGE(new)) {
 | 
						|
 | 
						|
				if (is_debug)
 | 
						|
					zlog_debug(
 | 
						|
						"%s: Current copy of LSA %s is MAXAGE, but new has recent Age.",
 | 
						|
						old->name, __PRETTY_FUNCTION__);
 | 
						|
 | 
						|
				ospf6_lsa_purge(old);
 | 
						|
				if (new->header->adv_router
 | 
						|
				    != from->ospf6_if->area->ospf6->router_id)
 | 
						|
					ospf6_flood(from, new);
 | 
						|
 | 
						|
				ospf6_install_lsa(new);
 | 
						|
				return;
 | 
						|
			}
 | 
						|
 | 
						|
			/* XXX, MinLSArrival check !? RFC 2328 13 (8) */
 | 
						|
 | 
						|
			ospf6_lsdb_add(ospf6_lsa_copy(old),
 | 
						|
				       from->lsupdate_list);
 | 
						|
			thread_add_event(master, ospf6_lsupdate_send_neighbor,
 | 
						|
					 from, 0, &from->thread_send_lsupdate);
 | 
						|
 | 
						|
			ospf6_lsa_delete(new);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		return;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
DEFUN (debug_ospf6_flooding,
 | 
						|
       debug_ospf6_flooding_cmd,
 | 
						|
       "debug ospf6 flooding",
 | 
						|
       DEBUG_STR
 | 
						|
       OSPF6_STR
 | 
						|
       "Debug OSPFv3 flooding function\n"
 | 
						|
      )
 | 
						|
{
 | 
						|
	OSPF6_DEBUG_FLOODING_ON();
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
DEFUN (no_debug_ospf6_flooding,
 | 
						|
       no_debug_ospf6_flooding_cmd,
 | 
						|
       "no debug ospf6 flooding",
 | 
						|
       NO_STR
 | 
						|
       DEBUG_STR
 | 
						|
       OSPF6_STR
 | 
						|
       "Debug OSPFv3 flooding function\n"
 | 
						|
      )
 | 
						|
{
 | 
						|
	OSPF6_DEBUG_FLOODING_OFF();
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int config_write_ospf6_debug_flood(struct vty *vty)
 | 
						|
{
 | 
						|
	if (IS_OSPF6_DEBUG_FLOODING)
 | 
						|
		vty_out(vty, "debug ospf6 flooding\n");
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
void install_element_ospf6_debug_flood(void)
 | 
						|
{
 | 
						|
	install_element(ENABLE_NODE, &debug_ospf6_flooding_cmd);
 | 
						|
	install_element(ENABLE_NODE, &no_debug_ospf6_flooding_cmd);
 | 
						|
	install_element(CONFIG_NODE, &debug_ospf6_flooding_cmd);
 | 
						|
	install_element(CONFIG_NODE, &no_debug_ospf6_flooding_cmd);
 | 
						|
}
 |