/*
 * 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/McIPv6.cc,v 1.19 2002/12/02 12:31:29 akisada Exp $
 */
#include "McIPv6.h"
#include "ItPosition.h"
#include "WObject.h"
#include "RObject.h"
#include "PControl.h"
#include "PvObject.h"
#include "PvOctets.h"
#include <stdio.h>

#define DEF_ALIGNMENT_IPv6	8

//////////////////////////////////////////////////////////////////////////////
#define SUPER	McPacket
McPacket_IPv6* McPacket_IPv6::instance_=0;
McTopHdr_IPv6* McPacket_IPv6::tophdr_=0;
McPacket_IPv6::McPacket_IPv6(CSTR s):SUPER(s) {instance_=this;}
McPacket_IPv6::~McPacket_IPv6() {if(instance_==this)instance_=0;}

// COMPOSE/REVERSE
uint32_t McPacket_IPv6::length_for_reverse(
		RControl& c,ItPosition& at,OCTBUF& buf) const{
	uint32_t length = tophdr_->Layerlength_for_reverse(c,at,buf);
	return length;}

RObject* McPacket_IPv6::reverseRc(RControl& c,
		RObject* r_parent,const ItPosition& at,PvObject* pv)const{
	RcPacket_IP* rc = new RcPacket_IP(r_parent,this,at,pv);
	c.set_IPinfo(rc->IPinfo());
	return rc;}

WObject* McPacket_IPv6::composeWc(WControl& c,
		WObject* w_parent,const PObject* pc) const {
	WcPacket_IP* wc = new WcPacket_IP(w_parent,this,pc);
	c.set_IPinfo(wc->IPinfo());
	return wc;}

RObject* McPacket_IPv6::reverse(RControl& c,
		RObject* r_parent,ItPosition& at,OCTBUF& buf)const{
	Con_IPinfo* keep = c.IPinfo();
	RcPacket_IP* rc = (RcPacket_IP*)SUPER::reverse(c,r_parent,at,buf);
	if(!c.error()){
		Con_IPinfo* info = rc->IPinfo();
		info->reverse_postAHICV(c,rc);}
	c.set_IPinfo(keep);
	return rc;}

WObject* McPacket_IPv6::compose(WControl& c,
		WObject* w_parent,const PObject* pc) const{
	Con_IPinfo* keep = c.IPinfo();
	WObject* rtn = SUPER::compose(c,w_parent,pc);
	c.set_IPinfo(keep);
	return rtn;}

bool McPacket_IPv6::generate(WControl& c,WObject* w_self,OCTBUF& buf) const {
	Con_IPinfo* keep = c.IPinfo();
	WcPacket_IP* wc = (WcPacket_IP*)w_self;
	c.set_IPinfo(wc->IPinfo());
	bool rtn = SUPER::generate(c,w_self,buf);
	if(!c.error()){
		Con_IPinfo* info = wc->IPinfo();
		info->generate_postAHICV(c,buf,wc);}
	c.set_IPinfo(keep);
	return rtn;}

bool McPacket_IPv6::overwrite_ICV(ICVControl&,
		const ItPosition&,OCTBUF&,const TObject*)const{
	return true;}//useless overwrite tunnelPacket

#undef SUPER

//----------------------------------------------------------------------------
#define SUPER	McHeader

McTopHdr_IPv6::McTopHdr_IPv6(CSTR key):SUPER(key),Layerlength_(0){}
McTopHdr_IPv6::~McTopHdr_IPv6(){}
uint32_t McTopHdr_IPv6::alignment_requirement() const{
	McHeader::provisional_AH_alignment_v4_v6_=DEF_ALIGNMENT_IPv6;
	return DEF_ALIGNMENT_IPv6;}

// COMPOSE/REVERSE
uint32_t McTopHdr_IPv6::Layerlength_for_reverse(
			RControl& c,ItPosition& at,OCTBUF& buf) const {
	if(!Layerlength_)return SUPER::Layerlength_for_reverse(c,at,buf);
	uint32_t remainlen	= buf.remainLength(at.bytes()); 
	uint32_t Payloadlen	= Layerlength_->value(at,buf);
	uint32_t hdrlen		= length_for_reverse(c,at,buf);
//TAHI_SPEC if (Payloadlen==0 JumboPayload) then use remainlen
	uint32_t Layerlength	= Payloadlen ? (Payloadlen+hdrlen) : remainlen;
	return Layerlength;}

bool McTopHdr_IPv6::HCGENE(PayloadLength)(
		WControl& cntr,WObject* wmem,OCTBUF& buf) const{
	WObject* wc		= wmem->parent();	//TopHdr_IPv6
	uint32_t hdrlen		= wc->size().bytes();
	WObject* packet		= wc->parent();		//Packet_IPv6
	uint32_t pktlen		= packet->size().bytes();
	uint32_t valulen	= pktlen - hdrlen;
	PvNumber def(valulen);
	return def.generate(cntr,wmem,buf);}

bool McTopHdr_IPv6::HCGENE(NextHeader)(WControl& cntr,WObject* wmem,OCTBUF& buf) const{
	int32_t val		= get_next_headerType(wmem);
	if(val==-1)return false;
	PvNumber def(val);
	return def.generate(cntr,wmem,buf);}
PObject* McTopHdr_IPv6::HCEVAL(NextHeader)(WObject* wmem) const{
	int32_t val		= get_next_headerType(wmem);
	return new PvNumber(val);}

void McTopHdr_IPv6::HC_ForIPinfo(SourceAddress)(
		Con_IPinfo& info,TObject* tmem) const {
	const PvObject* pv = tmem->pvalue();
	info.SrcAddr(pv);}
void McTopHdr_IPv6::HC_ForIPinfo(DestinationAddress)(
		Con_IPinfo& info,TObject* tmem) const {
	const PvObject* pv = tmem->pvalue();
	info.DstAddr(pv);}

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

bool McTopHdr_IPv6::HC_OWICV(SourceAddress)(ICVControl& c,	// MIP6AH
		const ItPosition& at,OCTBUF& buf,const TObject* t)const{
	const OCTBUF* home = (const OCTBUF*)c.HomeAddr();
	if(home)buf.encode(at, *home);
	const PvObject* coa = t->pvalue();
	c.CareOfAddr(coa);
	return true;}

bool McTopHdr_IPv6::HC_OWICV(DestinationAddress)(ICVControl& c,
		const ItPosition& at,OCTBUF& buf,const TObject* t)const{
	const OCTBUF* last = (const OCTBUF*)c.LastDstAddr();
	if(last)buf.encode(at,*last);
	const PvObject* shift = t->pvalue();
	c.ShiftRoutAddr(shift);
	return true;}

#undef SUPER

//////////////////////////////////////////////////////////////////////////////
#define DEF_LENGTH_ELEM_Ext	8
#define DEF_LENGTH_OFFSET_Ext	8

#define SUPER	McHeader
McHdr_Ext::McHdr_Ext(CSTR key):SUPER(key),length_(0){}
McHdr_Ext::~McHdr_Ext(){}
uint32_t McHdr_Ext::alignment_requirement() const{
	return DEF_ALIGNMENT_IPv6;}//exclude ESP

// COMPOSE/REVERSE
uint32_t McHdr_Ext::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_Ext)+DEF_LENGTH_OFFSET_Ext;
	return length;}

bool McHdr_Ext::HCGENE(NextHeader)(WControl& cntr,WObject* wmem,OCTBUF& buf) const{
	int32_t val	= get_next_headerType(wmem);
	if(val==-1)return false;
	PvNumber def(val);
	return def.generate(cntr,wmem,buf);}
PObject* McHdr_Ext::HCEVAL(NextHeader)(WObject* wmem) const{
	int32_t val	= get_next_headerType(wmem);
	return new PvNumber(val);}

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

bool McHdr_Ext::overwrite_ICV(ICVControl& c,
		const ItPosition& at,OCTBUF& buf,const TObject* t)const{
	return t->overwrite_ICV_child(c,at,buf);}
#undef SUPER

#define SUPER	McHdr_Ext
//----------------------------------------------------------------------------
McHdr_Ext_HopByHop::McHdr_Ext_HopByHop(CSTR key):SUPER(key){}
McHdr_Ext_HopByHop::~McHdr_Ext_HopByHop(){}

//----------------------------------------------------------------------------
McHdr_Ext_Destination::McHdr_Ext_Destination(CSTR key):SUPER(key){}
McHdr_Ext_Destination::~McHdr_Ext_Destination(){}

//----------------------------------------------------------------------------
McHdr_Ext_Routing::McHdr_Ext_Routing(CSTR key):SUPER(key){}
McHdr_Ext_Routing::~McHdr_Ext_Routing(){}

uint32_t McHdr_Ext_Routing::HC_MLC(Address)(
		const ItPosition& at,OCTBUF& buf)const{
	uint32_t length=length_->value(at,buf);
	return length/2;}

void McHdr_Ext_Routing::HC_ForIPinfo(SegmentsLeft)(
		Con_IPinfo& info,TObject* tmem) const {
	const PvNumber* pv = (const PvNumber*)tmem->pvalue();
	uint32_t segmentsleft = pv->value();
	bool isLeft = segmentsleft>0;
	info.Route_isLeft(isLeft);}
void McHdr_Ext_Routing::HC_ForIPinfo(Address)(
		Con_IPinfo& info,TObject* tmem) const {
	const PvObject* pv = tmem->pvalue();
	if(info.Route_isLeft()){
		info.LastDstAddr(pv);}
	}

bool McHdr_Ext_Routing::overwrite_ICV(ICVControl& c,
		const ItPosition& at,OCTBUF& buf,const TObject* t)const{
	uint32_t count = HC_MLC(Address)(at,buf);
	c.RoutAddrmax(count);
	c.RoutAddrindex(0);
	c.SegmentsLeft(0);
	return SUPER::overwrite_ICV(c,at,buf,t);}

bool McHdr_Ext_Routing::HC_OWICV(SegmentsLeft)(ICVControl& c,
		const ItPosition& at,OCTBUF& buf,const TObject* t)const{
	uint32_t lastnodevalue=0;
	const MmUint* m = (const MmUint*)t->meta();
	m->encode(lastnodevalue,at,buf);
	//
	const PvNumber* pv = (const PvNumber*)t->pvalue();
	uint32_t value = pv->value();
	c.SegmentsLeft(value);
	return true;}

bool McHdr_Ext_Routing::HC_OWICV(Address)(ICVControl& c,
		const ItPosition& at,OCTBUF& buf,const TObject* t)const{
	bool isShift = c.isShift_RoutAddr();
	if(isShift){
		const OCTBUF* shift = (const OCTBUF*)c.ShiftRoutAddr();
		if(shift)buf.encode(at,*shift);
		const PvObject* next = t->pvalue();
		c.ShiftRoutAddr(next);} //next ShiftRoutAddr
	c.inc_RoutAddrindex();
	return true;}

//----------------------------------------------------------------------------
McHdr_Ext_Fragment::McHdr_Ext_Fragment(CSTR key):SUPER(key){}
McHdr_Ext_Fragment::~McHdr_Ext_Fragment(){}

// COMPOSE/REVERSE
RObject* McHdr_Ext_Fragment::reverse(RControl& c,
		RObject* r_parent,ItPosition& at,OCTBUF& buf)const{
	RObject* r_self = SUPER::reverse(c,r_parent,at,buf);
	c.DictType().other_Set(); // nextType must overewrite other(McPayload)
	return r_self;}

bool McHdr_Ext_Fragment::overwrite_ICV(ICVControl&,
		const ItPosition&,OCTBUF&,const TObject*)const{
	fprintf(stderr,"err:unable calculate ICV with %s\n",string());
	return false;}

#undef SUPER

//////////////////////////////////////////////////////////////////////////////
#define DEF_LENGTH_OFFSET_OptExt	2

#define SUPER	McOption
McOpt_Ext::McOpt_Ext(CSTR key):SUPER(key),type_(0),length_(0){}
McOpt_Ext::~McOpt_Ext(){}

// COMPOSE/REVERSE
uint32_t McOpt_Ext::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_OFFSET_OptExt;
	return length;}

bool McOpt_Ext::HCGENE(OptDataLength)(WControl& cntr,WObject* wmem,OCTBUF& buf) const{
	WObject* wc = wmem->parent();
	uint32_t reallen	= wc->size().bytes();
	uint32_t valulen	= reallen-DEF_LENGTH_OFFSET_OptExt;
	PvNumber def(valulen);
	return def.generate(cntr,wmem,buf);}

bool McOpt_Ext::overwrite_DictType(
		RControl& c,ItPosition& at,OCTBUF& buf)const{
	uint32_t limit = buf.remainLength(at.bytes());
	if(limit==0)return false;		//End of Ext Header
	//
	ItPosition tmpat=at;
	RObject* rtype = type_->reverse(c,0,tmpat,buf);
	if(!rtype)return false;			//Type field decode error
	//
	const PvNumber* pv = (const PvNumber*)rtype->pvalue();
	uint32_t typevalue = pv->value();
	c.DictType().type_Set(typevalue);       //self Type set
	delete rtype;
	return true;}

bool McOpt_Ext::overwrite_ICV(ICVControl& c,
		const ItPosition& at,OCTBUF& buf,const TObject* t)const{
	uint32_t typeval = type_ ? type_->value(at,buf) : 0;
	bool isZero = !!(typeval&0x00000020);
	c.isZero_ExtOptData(isZero);
	bool rtn = t->overwrite_ICV_child(c,at,buf);
	c.isZero_ExtOptData(false);
	return rtn;}

bool McOpt_Ext::HC_OWICV(OptExtData)(ICVControl& c,
		const ItPosition& at,OCTBUF& buf,const TObject* t)const{
	bool isZero = c.isZero_ExtOptData();
	ICV_Zero owzero;
	return isZero ? owzero.overwrite(c,at,buf,t) : true;}

#undef SUPER

#define SUPER	McOpt_Ext
//----------------------------------------------------------------------------
McOpt_Ext_ANY::McOpt_Ext_ANY(CSTR key):SUPER(key){}
McOpt_Ext_ANY::~McOpt_Ext_ANY(){}

//----------------------------------------------------------------------------
McOpt_Ext_Pad1::McOpt_Ext_Pad1(CSTR key):SUPER(key){}
McOpt_Ext_Pad1::~McOpt_Ext_Pad1(){}

//----------------------------------------------------------------------------
McOpt_Ext_PadN::McOpt_Ext_PadN(CSTR key):SUPER(key){}
McOpt_Ext_PadN::~McOpt_Ext_PadN(){}

//----------------------------------------------------------------------------
#define DEF_ALIGNMENT_OptExt_JumboPayload	4
McOpt_Ext_JumboPayload::McOpt_Ext_JumboPayload(CSTR key):SUPER(key){}
McOpt_Ext_JumboPayload::~McOpt_Ext_JumboPayload(){}
uint32_t McOpt_Ext_JumboPayload::alignment_requirement() const{
	//now return fixvalue ("JumboPayloadLength" 4byte)
	return DEF_ALIGNMENT_OptExt_JumboPayload;}

bool McOpt_Ext_JumboPayload::HCGENE(JumboPayloadLength)(
		WControl& cntr,WObject* wmem,OCTBUF& buf) const{
	WObject* opt	= wmem->parent();		//Opt_Ext_JumboPayload
	WObject* hdr	= opt->parent();		//Hdr_Ext_HopByHop
	uint32_t offset	= hdr->distance();
	WObject* packet	= hdr->parent();		//Packet_IPv6
	uint32_t pktlen	= packet->size().bytes();
	uint32_t valulen= pktlen-offset;
	PvNumber def(valulen);
	return def.generate(cntr,wmem,buf);}

//----------------------------------------------------------------------------
#define DEF_ALIGNMENT_OptExt_RouterAlert	2
McOpt_Ext_RouterAlert::McOpt_Ext_RouterAlert(CSTR key):SUPER(key){}
McOpt_Ext_RouterAlert::~McOpt_Ext_RouterAlert(){}
uint32_t McOpt_Ext_RouterAlert::alignment_requirement() const{
	//now return fixvalue ("Value" 2byte)
	return DEF_ALIGNMENT_OptExt_RouterAlert;}

//----------------------------------------------------------------------------
#define DEF_ALIGNMENT_OptExt_TunnelEncap	2
McOpt_Ext_TunnelEncap::McOpt_Ext_TunnelEncap(CSTR key):SUPER(key){}
McOpt_Ext_TunnelEncap::~McOpt_Ext_TunnelEncap(){}
uint32_t McOpt_Ext_TunnelEncap::alignment_requirement() const{
	//now return fixvalue ("Value" 2byte)
	return DEF_ALIGNMENT_OptExt_TunnelEncap;}

//----------------------------------------------------------------------------
#if 0
#define DEF_ALIGNMENT_Opt_Ext_HomeAddress 8
#endif
McOpt_Ext_HomeAddress::McOpt_Ext_HomeAddress(CSTR key):SUPER(key) {}
McOpt_Ext_HomeAddress::~McOpt_Ext_HomeAddress() {}
#if 0
uint32_t McOpt_Ext_HomeAddress::alignment_requirement() const {
	return(DEF_ALIGNMENT_Opt_Ext_HomeAddress);
}
#endif
void McOpt_Ext_HomeAddress::HC_ForIPinfo(HomeAddress)(Con_IPinfo& info, TObject* tmem) const {
	const PvObject* pv = tmem->pvalue();
	info.SrcAddr(pv);
}

bool McOpt_Ext_HomeAddress::overwrite_ICV(ICVControl &c, const ItPosition &at, OCTBUF &buf, const TObject *t) const {
	return(SUPER::overwrite_ICV(c, at, buf, t));
}	// MIP6AH

bool McOpt_Ext_HomeAddress::HC_OWICV(HomeAddress)(ICVControl &c, const ItPosition &at, OCTBUF &buf, const TObject *t) const {
	const OCTBUF *coa = (const OCTBUF *)c.CareOfAddr();

	if(coa) {
		buf.encode(at, *coa);
	}

	const PvObject *home = t->pvalue();
	c.HomeAddr(home);

	return true;
}	// MIP6AH

#undef SUPER

///////////////////////////////////////////////////////////////////////////////
MmOption_onExt::MmOption_onExt(CSTR key):MmReference_More0(key,true) {}
MmOption_onExt::~MmOption_onExt() {}

void MmOption_onExt::add(McOpt_Ext* mc){
	dict_.add(mc->optionType(),mc);}
void MmOption_onExt::add_other(McOpt_Ext* mc){dict_.add_other(mc);}
TypevsMcDict MmOption_onExt::dict_;

// REVERSE
bool MmOption_onExt::overwrite_DictType(
		RControl& c,ItPosition& at,OCTBUF& buf)const{
	McOpt_Ext* any = (McOpt_Ext*)dict_.find_other();
	return any->overwrite_DictType(c,at,buf);}

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


syntax highlighted by Code2HTML, v. 0.9.1