/*
 * Copyright (C) 2002, 2003, 2004, 2005 Yokogawa Electric Corporation, 
 * INTAP(Interoperability Technology Association for Information 
 * Processing, Japan), IPA (Information-technology Promotion Agency, Japan).
 * All rights reserved.
 * 
 * Redistribution and use of this software in source and binary forms, with 
 * or without modification, are permitted provided that the following 
 * conditions and disclaimer are agreed and accepted by the user:
 * 
 * 1. Redistributions of source code must retain the above copyright 
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the following disclaimer in the 
 * documentation and/or other materials provided with the distribution.
 * 
 * 3. Neither the names of the copyrighters, the name of the project which 
 * is related to this software (hereinafter referred to as "project") nor 
 * the names of the contributors may be used to endorse or promote products 
 * derived from this software without specific prior written permission.
 * 
 * 4. No merchantable use may be permitted without prior written 
 * notification to the copyrighters. However, using this software for the 
 * purpose of testing or evaluating any products including merchantable 
 * products may be permitted without any notification to the copyrighters.
 * 
 * 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHTERS, THE PROJECT AND 
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING 
 * BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.  IN NO EVENT SHALL THE 
 * COPYRIGHTERS, THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT,STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $TAHI: v6eval/lib/Pz/McAH.cc,v 1.15 2003/10/23 04:37:30 akisada Exp $
 */
#include "McAH.h"
#include "MmData.h"
#include "ItPosition.h"
#include "WObject.h"
#include "RObject.h"
#include "PControl.h"
#include "PvObject.h"
#include "PvOctets.h"
#include "PvAutoItem.h"
#include "PvAction.h"
#include "McAlgorithm.h"
#include "PAlgorithm.h"
#include "CmMain.h"
#include <stdio.h>


//////////////////////////////////////////////////////////////////////////////
#define DEF_LENGTH_ELEM_AH	4
#define DEF_LENGTH_OFFSET_AH	8

#define SUPER	McHdr_Ext

McHdr_Ext_AH::McHdr_Ext_AH(CSTR key):SUPER(key){}
McHdr_Ext_AH::~McHdr_Ext_AH(){}

uint32_t McHdr_Ext_AH::alignment_requirement() const{
	if(provisional_AH_alignment_v4_v6_)return provisional_AH_alignment_v4_v6_;
	return SUPER::alignment_requirement();}//only IPv6 alignment(8)

// COMPOSE/REVERSE
uint32_t McHdr_Ext_AH::length_for_reverse(
		RControl& c,ItPosition& at,OCTBUF& buf)const{
	if(!length_)return SUPER::length_for_reverse(c,at,buf);
	uint32_t valulen= length_->value(at,buf);
	uint32_t length = (valulen*DEF_LENGTH_ELEM_AH)+DEF_LENGTH_OFFSET_AH;
	return length;}

RObject* McHdr_Ext_AH::reverse(RControl& c,
		RObject* r_parent,ItPosition& at,OCTBUF& buf)const{
	const PaObject* keepSA = c.poping_SA(); c.poping_SA(0);
	RObject* r_self = SUPER::reverse(c,r_parent,at,buf);
	c.poping_SA(keepSA);
	return r_self;}
WObject* McHdr_Ext_AH::compose(WControl& c,
		WObject* w_parent,const PObject* pc) const {
	const PaObject* keepSA = c.pushing_SA(); c.pushing_SA(0);
	WObject* w_self = SUPER::compose(c,w_parent,pc);
	c.pushing_SA(keepSA);
	return w_self;}

bool McHdr_Ext_AH::HCGENE(HeaderExtLength)(
			WControl& cntr,WObject* wmem,OCTBUF& buf) const{
	WObject* wc	= wmem->parent();       //Hdr_Ext_AH
	uint32_t reallen= wc->size().bytes();
	uint32_t valulen= (reallen-DEF_LENGTH_OFFSET_AH)/DEF_LENGTH_ELEM_AH;
	PvNumber def(valulen);
	return def.generate(cntr,wmem,buf);}

bool McHdr_Ext_AH::overwrite_ICV(ICVControl& c,
		const ItPosition& at,OCTBUF& buf,const TObject* t)const{
	return t->overwrite_ICV_child(c,at,buf);}//forward to member

#define	UN(n) PvNumber::unique(n)
#define	MUST()PvMUSTDEF::must()
#define EVALANY()	new PvANY()
#define GENEHC(mc,cls,mem)	new PvHCgene(mc,(HCgenefunc)&cls::HCGENE(mem))
#define EVALHC(mc,cls,mem)	new PvHCeval(mc,(HCevalfunc)&cls::HCEVAL(mem))
#define ICVCONST()	0
#define ICVZERO()	new ICV_Zero()
#define DEF_EVALSKIP	true

McHdr_Ext_AH* McHdr_Ext_AH::create(CSTR key){
	McHdr_Ext_AH* mc = new McHdr_Ext_AH(key);
	mc->nextType_member(
		    new MmUint( "NextHeader",	8,
			GENEHC(mc,McHdr_Ext_AH,NextHeader),
			EVALHC(mc,McHdr_Ext_AH,NextHeader),	ICVCONST() ) );
	mc->length_member(
		    new MmUint( "PayloadLength",8,
			GENEHC(mc,McHdr_Ext_AH,HeaderExtLength),
			EVALANY(),		ICVCONST() ) );
	mc->member( new MmUint(	"Reserved",	16,
			UN(0),	UN(0),		ICVCONST() ) );
	mc->member( new MmSPI(	"SPI",		32,
			UN(0),	UN(0),		ICVCONST() ) );
	mc->member( new MmUint( "SequenceNumber",32,
			UN(0),	UN(0),		ICVCONST() ) );
	mc->member( new MmAlgorithm_onAH("algorithm")); //reference
	mc->member( new MmAH_ICV("ICV",		ICVZERO() ));
	mc->member( new MmData( "Padding",DEF_EVALSKIP, ICVCONST() ) );
	// dict
	MmExtent_onIP::add(mc);			//Packet_IP::exthdr=
	return mc;}
#undef SUPER

//////////////////////////////////////////////////////////////////////////////
class RcAH:public RcObject {
private:
	const PaObject* algorithm_;
public:
	RcAH(RObject*,const MObject*,const ItPosition& o,PvObject* =0);
virtual	~RcAH();
virtual	void algorithm(const PaObject* sa){algorithm_=sa;}
virtual	void printChild(uint32_t) const;
};

RObject* McHdr_Ext_AH::reverseRc(RControl&,
		RObject* r_parent,const ItPosition& at,PvObject* pv) const {
	return new RcAH(r_parent,this,at,pv);}

RcAH::RcAH(RObject* r,const MObject* m,const ItPosition& o,PvObject* p):
	RcObject(r,m,o,p),algorithm_(0) {}
RcAH::~RcAH() {}
void RcAH::printChild(uint32_t t) const {
	if(DBGFLAGS('S')){
		if(algorithm_){printf("== AH SA ==\n"); algorithm_->print();}}
	RcObject::printChild(t);}


//////////////////////////////////////////////////////////////////////////////
class WcAH:public WcObject {
private:
	const PaObject* algorithm_;
public:
	WcAH(WObject*,const MObject*,const PObject* =0);
virtual	~WcAH();
virtual	void algorithm(const PaObject* sa){algorithm_=sa;}
virtual	void printChild(uint32_t) const;
};

WObject* McHdr_Ext_AH::composeWc(WControl&,
		WObject* w_parent,const PObject* pc) const {
	return new WcAH(w_parent,this,pc);}

WcAH::WcAH(WObject* w,const MObject* m,const PObject* p):WcObject(w,m,p),
	algorithm_(0) {}
WcAH::~WcAH() {}
void WcAH::printChild(uint32_t t) const {
	if(DBGFLAGS('S')){
		if(algorithm_){printf("== AH SA ==\n"); algorithm_->print();}}
	WcObject::printChild(t);}


//////////////////////////////////////////////////////////////////////////////
#define SUPER	MmReference_Must1
#include "PvName.h"
MmAlgorithm_onAH::MmAlgorithm_onAH(CSTR key):SUPER(key) {}
MmAlgorithm_onAH::~MmAlgorithm_onAH() {}
RObject* MmAlgorithm_onAH::reverse(
		RControl& c,RObject* r_parent,ItPosition& at,OCTBUF&)const{
	RObject* r_self=0;
	c.set_pop_SA(eAH_);//select&set SA
	const PaObject* sa = c.poping_SA();
	if(sa){ RcAH* rcah = (RcAH*)r_parent;
		if(rcah)rcah->algorithm(sa);
		PvObject* pv = sa->nameObject()->shallowCopy();
		ItPosition size(0);
		r_self = new RmObject(r_parent,this,at,size,pv); }
	return r_self;}// not reverse

bool MmAlgorithm_onAH::disused() const{return true;}
#undef SUPER


//////////////////////////////////////////////////////////////////////////////
#define SUPER	MmVarOctets

MmAH_ICV::MmAH_ICV(CSTR str,const ICVoverwriter* ow):SUPER(str,0,0,ow){}
MmAH_ICV::~MmAH_ICV(){}

ItPosition MmAH_ICV::length_for_reverse(
		RControl& c,ItPosition& at,OCTBUF& buf) const {
	const PaObject* sa = c.poping_SA();
	uint32_t length =0;
if(DBGFLAGS('V')){
	//Request Spec (for v6eval)
	//if ICV can not find SA , ICV Length = remainLength onAH
	length = buf.remainLength(at.bytes());
}
/*SA*/	if(sa){	length= sa->ICV_Length();}
	return ItPosition(length);}

//post add
RObject* MmAH_ICV::reverse(RControl& c,
		RObject* r_parent,ItPosition& at,OCTBUF& buf)const{
	RObject* r_self = SUPER::reverse(c,r_parent,at,buf);
	if(!c.error()){
		Con_IPinfo* info = c.IPinfo();
		if(info)info->postAHICV(r_self);}//post reverse calcICV
	return r_self;}

bool MmAH_ICV::geneAuto(WControl& c,WObject* w_self,OCTBUF&) const{
	if(!c.error()){
		Con_IPinfo* info = c.IPinfo();
		if(info)info->postAHICV(w_self);}//post generate calcICV
	return c;}
#undef SUPER


///////////////////////////////////////////////////////////////////////////////
class RmAH_ICV : public RmObject{
	const PaObject*	sa_;
	PvObject*	calc_pvalue_;
public:
	RmAH_ICV(RObject* r_parent,const MObject* m,
		const ItPosition& offset,const ItPosition& size,PvObject* pv,
		const PaObject* sa);
virtual ~RmAH_ICV();
	void set_calc_pvalue(PvObject* icvbuf);
	PvObject* calc_pvalue()const{return calc_pvalue_;}
virtual void post_reverse(Con_IPinfo& info,RControl&,RObject* pkt);
virtual void printName(uint32_t,CSTR =0) const;
virtual void logSelf(uint32_t,CSTR =0) const;
};

RObject* MmAH_ICV::reverseRm(RControl& c,RObject* r_parent,
		const ItPosition& at,const ItPosition& size,PvObject* pv)const{
	const PaObject* sa = c.poping_SA();
	RmAH_ICV* r_self = new RmAH_ICV(r_parent,this,at,size,pv,sa);
	return r_self;}


#define SUPER	RmObject
RmAH_ICV::RmAH_ICV(RObject* r_parent,const MObject* m,
		const ItPosition& offset,const ItPosition& size,PvObject* pv,
		const PaObject* sa):SUPER(r_parent,m,offset,size,pv),
		sa_(sa),calc_pvalue_(new OCTBUF()){}
RmAH_ICV::~RmAH_ICV(){
	if(calc_pvalue_){delete calc_pvalue_; calc_pvalue_=0;}
	}
void RmAH_ICV::set_calc_pvalue(PvObject* calc){
	if(calc_pvalue_){delete calc_pvalue_;}
	calc_pvalue_=calc;}

void RmAH_ICV::post_reverse(Con_IPinfo& info,RControl& c,RObject* pkt){
	OCTBUF* pktbuf = (OCTBUF*)pkt->pvalue();
	OCTBUF ahbuf(pktbuf->length(),(OCTSTR)pktbuf->string(),true);
	ICVControl icvc;
	icvc.LastDstAddr(info.LastDstAddr());
	icvc.HomeAddr(info.SrcAddr());	// MIP6AH

	ItPosition at;
	pkt->overwrite_ICV_child(icvc,at,ahbuf);
	//
	OCTBUF* calc = 0;
/*SA*/	if(sa_)calc = sa_->ICV_Calculate(ahbuf);
	if(!calc)calc=new OCTBUF();
	set_calc_pvalue(calc);
	//
	const PvObject* rcv=pvalue();
	if(calc->compareObject(*rcv)!=0){
		c.unmatchMessage(meta()->string(),rcv,calc);
		c.set_warning(0);}
	if(DBGFLAGS('C')) {
		info.print(); printf("\n");
		printf("== AHICV overwrite buffer ==\n");
		ahbuf.print(); printf("\n");
		printf("== AHICV calculate ==\n");
		calc->print(); printf("\n");}
	}

void RmAH_ICV::printName(uint32_t t,CSTR cls) const {
	SUPER::printName(t,cls);
	printf(" calc("); if(calc_pvalue_)calc_pvalue_->print(); printf(")");}
void RmAH_ICV::logSelf(uint32_t t,CSTR cls) const {
	SUPER::logSelf(t,cls);
	printf(" calc("); if(calc_pvalue_)calc_pvalue_->print(); printf(")");}
#undef SUPER


///////////////////////////////////////////////////////////////////////////////
class WmAH_ICV : public WmObject{
	const PaObject*	sa_;
public:
	WmAH_ICV(WObject* p,const MObject* m,const PaObject* sa);
virtual ~WmAH_ICV();
// GENERATE/EVALUATE INTERFACE ------------------------------------------------
virtual void internalGeneratePrologue(ItPosition& it);
virtual void post_generate(Con_IPinfo& info,WControl& c,OCTBUF& buf,
				WObject* pkt);
virtual bool doEvaluate(WControl& c,RObject& r);
};

WObject* MmAH_ICV::composeWm(WControl& c,
		WObject* w_parent,const PObject*)const{
	const PaObject* sa = c.pushing_SA();
	WmAH_ICV* w_self = new WmAH_ICV(w_parent,this,sa);
	return w_self;}


#define SUPER	WmObject
WmAH_ICV::WmAH_ICV(WObject* p,const MObject* m,const PaObject* sa):
		SUPER(p,m,0),sa_(sa){}
WmAH_ICV::~WmAH_ICV(){}

void WmAH_ICV::internalGeneratePrologue(ItPosition& it){
	if(!sa_)return;
/*SA*/	uint32_t icvlen	= sa_->ICV_Length();
	it.addBytes(icvlen);
	}
void WmAH_ICV::post_generate(Con_IPinfo& info,WControl& c,OCTBUF& buf,
		WObject* pkt){
	OCTBUF* pktbuf = (OCTBUF*)pkt->pvalue();
	OCTBUF ahbuf(pktbuf->length(),(OCTSTR)pktbuf->string(),true);
	ICVControl icvc;
	icvc.LastDstAddr(info.LastDstAddr());
	icvc.HomeAddr(info.SrcAddr());	// MIP6AH

	ItPosition at;
	pkt->overwrite_ICV_child(icvc,at,ahbuf);
	//
	OCTBUF* calc = 0;
/*SA*/	if(sa_)calc = sa_->ICV_Calculate(ahbuf);
	if(!calc)calc=new OCTBUF();
	set_rgenerate(calc); //generater self life management
	SUPER::generate(c,buf);
	//
	if(DBGFLAGS('C')) {
		info.print(); printf("\n");
		printf("== AHICV overwrite buffer ==\n");
		ahbuf.print(); printf("\n");
		printf("== AHICV calculate ==\n");
		calc->print(); printf("\n");}
	}

bool WmAH_ICV::doEvaluate(WControl& c,RObject& r) {
	//typecheck be finished by metaEvaluate()
	RmAH_ICV& rm = (RmAH_ICV&)r;
	const PvObject* ro	= rm.pvalue();
	const PvObject* eo	= revaluate();
	if(!eo)eo		= rm.calc_pvalue(); //auto
	return valueEvaluate(c,ro,eo);}
#undef SUPER


//////////////////////////////////////////////////////////////////////////////



syntax highlighted by Code2HTML, v. 0.9.1