LibIpv6_Interface_Functions.ttcn 46.1 KB
Newer Older
/*
 *	@author 	STF 276
 *  @version 	$Id$
 *	@desc		This module specifies functions definitions
 *              based on the IPv6 meta message type.  
 *  
 */
 module LibIpv6_Interface_Functions {

	//LibCommon
	import from LibCommon_BasicTypesAndValues all;
	import from LibCommon_DataStrings all;
	import from LibCommon_VerdictControl { type FncRetCode };
	//LibIpv6
	import from LibIpv6_Interface_TypesAndValues all;
	import from LibIpv6_Interface_Templates all;
	import from LibIpv6_ModuleParameters all;
	import from LibIpv6_ExternalFunctions all;
	import from LibIpv6_CommonRfcs_Functions all;
	import from LibIpv6_CommonRfcs_TypesAndValues all;
mullers's avatar
mullers committed
	import from LibIpv6_Rfc4306Ikev2_TypesAndValues all;
group rfc2460Root_Functions {
	
	group ipv6Packets {	

	/*
	 * @desc 	This sends a General IPv6 packet
	 *			from an IPv6 node to any NUT.
	 *			A General IPv6 packet is used in the case where only Extension headers
	 *			need to be sent.
	 * @remark  Time limit is defined by module parameter PX_TAC (see comp type)
	 * @param 	p_msg MIPHeader to be sent	
	 * @return 	execution status
	*/
	function f_sendGeneralIpv6(template Ipv6Packet p_msg)
	runs on LibIpv6Node
	return FncRetCode {
		//Variables
		var Ipv6Packet v_ipPkt;
		v_ipPkt := valueof(p_msg);
		//calc payloadLen
		v_ipPkt.ipv6Hdr.payloadLength := fx_payloadLength (v_ipPkt);
		
		//set extensionHeaders
		if(f_setExtensionHeaders( v_ipPkt ) != e_success) {
			log(" **** f_sendGeneralIpv6: Error when calculating length of extension headers ****");
			return e_error;
		}

		//send
		ipPort.send(v_ipPkt);

		return e_success;
	}//end f_sendGeneralIpv6

	group extHdrFns {

	/*
	 * @desc 	This goes through the extension header list and calculates length, checksum
	 *			and other specific functions of the different extension headers
	 * @param 	p_ipv6Packet	IPv6 packet to be processed
	 * @return 	execution status 
	*/
	function f_setExtensionHeaders(	inout Ipv6Packet p_ipv6Packet)
	runs on LibIpv6Node
	return FncRetCode {
		var FncRetCode v_ret := e_success; 
		var UInt8 i, j;
		var UInt8 v_authHdrIndex := 0;
		var UInt8 v_spi := 0;
berge's avatar
berge committed
		var Ipv6Address v_pseudoSrcAddr := c_16ZeroBytes;
		var Ipv6Address v_pseudoDstAddr := c_16ZeroBytes;
		var boolean v_loop := true;
		var Ipv6Packet v_innerIpv6Packet;
		var Ipv6Packet v_tempIpv6Packet;
		var Ipv6Packet v_activeIpv6Packet := p_ipv6Packet;
		v_pseudoDstAddr := v_activeIpv6Packet.ipv6Hdr.destinationAddress;
		v_pseudoSrcAddr := v_activeIpv6Packet.ipv6Hdr.sourceAddress;
mullers's avatar
mullers committed
		//calc payloadLen of IPv6packet
		if (v_activeIpv6Packet.ipv6Hdr.payloadLength == c_uInt16Zero ) {
			v_activeIpv6Packet.ipv6Hdr.payloadLength := fx_payloadLength (v_activeIpv6Packet);
		}
		
		// Browse the differents extension headers and search for specific fields to be computed
		if (ispresent(v_activeIpv6Packet.extHdrList)) {
			for (i:=0; v_loop and i<sizeof(v_activeIpv6Packet.extHdrList) ;i:=i+1) {

				// Authentication Header has to be processed only when all the other fields are correct
				// Only the first auth header will be processed
				if (ischosen(v_activeIpv6Packet.extHdrList[i].authHeader) and v_authHdrIndex == 0) {
					// Remember to process this auth header later
					v_authHdrIndex := i;
				}				
				// Process Home Address Destination Option, non-recursive
				// Change the pseudo-source address
				if (ischosen(v_activeIpv6Packet.extHdrList[i].destinationOptionHeader)) {
					for (j:=0; j<sizeof(v_activeIpv6Packet.extHdrList[i].destinationOptionHeader.destOptionList);j:=j+1) {
						if (ischosen(v_activeIpv6Packet.extHdrList[i].destinationOptionHeader.destOptionList[j].homeAddressOption)) {
							v_pseudoSrcAddr := v_activeIpv6Packet.extHdrList[i].destinationOptionHeader.destOptionList[j].homeAddressOption.homeAddress;
						}
					}
				
				// Proccess Routing Header Type 2, non-recursive
				// Change the pseudo-destination address		
				else if (ischosen(v_activeIpv6Packet.extHdrList[i].routingHeader) and (v_activeIpv6Packet.extHdrList[i].routingHeader.routingType == c_routeHdrType2)) {
					if (ischosen(v_activeIpv6Packet.extHdrList[i].routingHeader.routingHeaderData.rtHdrDataHomeAddress)) {
						v_pseudoDstAddr := v_activeIpv6Packet.extHdrList[i].routingHeader.routingHeaderData.rtHdrDataHomeAddress;
					}
				
				// Process Mobile Header, non-recursive		 	
				// Compute Mip header length and checksum, and some other mip specific fields
				// Update global packet's payload length
				else if (ischosen(v_activeIpv6Packet.extHdrList[i].mobileHeader)) {
					v_ret := f_setMobileHeader(	v_activeIpv6Packet.ipv6Hdr.sourceAddress,
												v_activeIpv6Packet.ipv6Hdr.destinationAddress,
												v_pseudoSrcAddr,					
												v_pseudoDstAddr,
												v_activeIpv6Packet.extHdrList[i].mobileHeader);
					
					//	update packet payloadLen
					v_activeIpv6Packet.ipv6Hdr.payloadLength := fx_payloadLength (v_activeIpv6Packet);
				// Process Tunneled Header, recursive
				// Recursively process the tunneled packet. 
				// Outter packet has to be updated once the recursion call returns
				else if (ischosen(v_activeIpv6Packet.extHdrList[i].tunneledIpv6)) {
							
					// extract inner packet
					v_innerIpv6Packet.ipv6Hdr := v_activeIpv6Packet.extHdrList[i].tunneledIpv6;
					for (j:=0; (i+j+1)<sizeof(v_activeIpv6Packet.extHdrList) ;j:=j+1) {
						v_innerIpv6Packet.extHdrList[j] := v_activeIpv6Packet.extHdrList[i+1];	
					}
					if (ispresent(v_activeIpv6Packet.ipv6Payload)) {
						v_innerIpv6Packet.ipv6Payload := v_activeIpv6Packet.ipv6Payload;	
mullers's avatar
mullers committed

					// recursive call, inner packet can still contain other headers
					f_setExtensionHeaders(	v_innerIpv6Packet );
					// include recursion results into the active packet
					v_activeIpv6Packet.extHdrList[i].tunneledIpv6.payloadLength := v_innerIpv6Packet.ipv6Hdr.payloadLength;
					if (ispresent(v_innerIpv6Packet.extHdrList)) {
						for (j:=0; j<sizeof(v_innerIpv6Packet.extHdrList) ;j:=j+1) {
							v_activeIpv6Packet.extHdrList[i+1] := v_innerIpv6Packet.extHdrList[j];	
					if (ispresent(v_innerIpv6Packet.ipv6Payload)) {
						v_activeIpv6Packet.ipv6Payload := v_innerIpv6Packet.ipv6Payload;	

					// Update the active packet						
					v_activeIpv6Packet.ipv6Hdr.payloadLength := fx_payloadLength (v_activeIpv6Packet);
				
					// Stop processing extension headers :
					// the remaining extension headers belong to the inner packet,
					// and have already been processed by the recursive call	
					v_loop := false;				
				}
				
				// Process ESP Header, recursive
				// Build the orignal, ESP-less, inner packet and process it recursively
				// Active packet has to be updated once the recursion call returns
				else if (ischosen(v_activeIpv6Packet.extHdrList[i].espHeader)) {
mullers's avatar
mullers committed

					var integer v_idx := -1;
					if (f_getSaBySpi(vc_sad, v_activeIpv6Packet.extHdrList[i].espHeader.spi, v_idx) == e_error) {
						return e_error;
					}
					
					// set IV if needed. 
					// Payload length may change.
					if (vc_sad[v_idx].espEncryptionAlgo == e_encr_null) {
mullers's avatar
mullers committed
						v_activeIpv6Packet.extHdrList[i].espHeader.espPayload.iv := omit; 
					}
					else {
						v_activeIpv6Packet.extHdrList[i].espHeader.espPayload.iv := vc_sad[v_idx].espIv;
						//int2oct(128, f_getEncryptionIvLen(vc_sad[v_idx].espEncryptionAlgo)); 	
mullers's avatar
mullers committed
					}
					v_ret := f_getOriginalIpv6Packet(
									v_activeIpv6Packet,
									v_activeIpv6Packet.extHdrList[i].espHeader,
									v_innerIpv6Packet);
					v_innerIpv6Packet.ipv6Hdr.destinationAddress := v_pseudoDstAddr;
					v_innerIpv6Packet.ipv6Hdr.sourceAddress := v_pseudoSrcAddr;

					if (v_ret == e_success) {
						
						// recursive call, inner packet can still contain other headers
						f_setExtensionHeaders(	v_innerIpv6Packet );
						// include recursion results into the active packet
						if (ispresent(v_innerIpv6Packet.extHdrList)) {
							v_activeIpv6Packet.extHdrList[i].espHeader.espPayload.espIpDatagram.extHdrList := v_innerIpv6Packet.extHdrList
						if (ispresent(v_innerIpv6Packet.ipv6Payload)) {
							v_activeIpv6Packet.extHdrList[i].espHeader.espPayload.espIpDatagram.ipv6Payload := v_innerIpv6Packet.ipv6Payload;	

						// Update the active packet						
						v_activeIpv6Packet.ipv6Hdr.payloadLength := fx_payloadLength (v_activeIpv6Packet);

						// Stop processing extension headers :
						// the remaining extension headers belong to the inner packet,
						// and have already been processed by the recursive call	
						v_loop := false;
					}
vouffofeudji's avatar
vouffofeudji committed
				}
			}//end for
		}
		// all extension headers have been processed
		// Is there still a payload to be processed and which has not been already processed in a recursive call?
		if (v_loop==true and ispresent(v_activeIpv6Packet.ipv6Payload)) {
			
			// IKE message specific processing
berge's avatar
berge committed
			if(ischosen(v_activeIpv6Packet.ipv6Payload.ikeMsg)) {
				if (vc_ikeSad[0].udpTnPort == c_udpPort4500) {
					v_activeIpv6Packet.ipv6Payload.ikeMsg.padding := c_4ZeroBytes;
				}
berge's avatar
berge committed
				
				if(ischosen(v_activeIpv6Packet.ipv6Payload.ikeMsg.payloadList[0].encrypted)) {
					
					// set IV if needed. 
					if (f_getEncryptionIvLen(vc_ikeSad[0].ikeEncryptionAlgo) == 0) {
						v_activeIpv6Packet.ipv6Payload.ikeMsg.payloadList[0].encrypted.iv := omit; 
					}
					else {
						if (ispresent(vc_ikeSad[0].ikeIv)) {
							v_activeIpv6Packet.ipv6Payload.ikeMsg.payloadList[0].encrypted.iv := vc_ikeSad[0].ikeIv;
						}
						else {
							log("**** Errro: no IV provided.****");
							v_ret := e_error;
						}
berge's avatar
berge committed
					}
					//Payload length
					if(v_activeIpv6Packet.ipv6Payload.ikeMsg.payloadList[0].encrypted.payloadLength == 0) {
berge's avatar
berge committed
						v_activeIpv6Packet.ipv6Payload.ikeMsg.payloadList[0].encrypted.payloadLength := fx_ikeEncPayloadLength(v_activeIpv6Packet);//.ipv6Payload.ikeMsg.payloadList[0].encrypted); 
berge's avatar
berge committed
					}
					v_activeIpv6Packet.ipv6Payload.ikeMsg.ikev2Header.messageLength := c_ikev2HeaderLen + lengthof(fx_ikePayloadListToOct(v_activeIpv6Packet.ipv6Payload.ikeMsg.payloadList));
				}
berge's avatar
berge committed
				if(v_activeIpv6Packet.ipv6Payload.ikeMsg.msgLength == 0) {
					//calc payloadLen of UDP msg
berge's avatar
berge committed
					v_activeIpv6Packet.ipv6Payload.ikeMsg.msgLength := 	8 + f_getLenPadding(v_activeIpv6Packet.ipv6Payload.ikeMsg)
														//lengthof(fx_ikev2HeaderToOct(v_activeIpv6Packet.ipv6Payload.ikeMsg.ikev2Header))
														//+ lengthof(fx_ikePayloadListToOct(v_activeIpv6Packet.ipv6Payload.ikeMsg.payloadList));
														+ v_activeIpv6Packet.ipv6Payload.ikeMsg.ikev2Header.messageLength;
berge's avatar
berge committed
				}
			}
berge's avatar
berge committed
			
			// Update the active packet						
			v_activeIpv6Packet.ipv6Hdr.payloadLength := fx_payloadLength (v_activeIpv6Packet);

			// Compute payload checksum (Icmpv6, UDP, ...)
			v_ret := f_calcIpv6PayloadChecksum(v_pseudoSrcAddr, v_pseudoDstAddr, v_activeIpv6Packet.ipv6Payload);
		// Proccess Authentication, non-recursive
		// Compute ICV and ICV-Padding
berge's avatar
berge committed
		if ( ispresent(v_activeIpv6Packet.extHdrList)
			 and v_authHdrIndex<sizeof(v_activeIpv6Packet.extHdrList) 
			 and ischosen(v_activeIpv6Packet.extHdrList[v_authHdrIndex].authHeader)) {
			//Set Dummy ICV of correct length
			var integer v_idx := -1;
			if (f_getSaBySpi(vc_sad, v_activeIpv6Packet.extHdrList[v_authHdrIndex].authHeader.securityParametersIndex, v_idx) == e_error) {
				return e_error;
			}
					
			if (vc_sad[v_idx].ahIcvLen == 0) {
				v_activeIpv6Packet.extHdrList[v_authHdrIndex].authHeader.icv := omit;	
			}
			else {
				v_activeIpv6Packet.extHdrList[v_authHdrIndex].authHeader.icv := int2oct(0, vc_sad[v_idx].ahIcvLen);
			if (vc_sad[v_idx].ahIcvPadLen == 0) {
				v_activeIpv6Packet.extHdrList[v_authHdrIndex].authHeader.icvPadding := omit;
			}
			else {
				v_activeIpv6Packet.extHdrList[v_authHdrIndex].authHeader.icvPadding := int2oct(0, vc_sad[v_idx].ahIcvPadLen);
			//	Update AuthHeader payloadLen
			v_activeIpv6Packet.extHdrList[v_authHdrIndex].authHeader.payloadLen := (12 + vc_sad[v_idx].ahIcvLen 
																			 	 	   + vc_sad[v_idx].ahIcvPadLen) / 4 - 2;
			//Update IPv6 payload based on the calculated ICV + padding
berge's avatar
berge committed
			v_activeIpv6Packet.ipv6Hdr.payloadLength := fx_payloadLength (v_activeIpv6Packet);
			if (vc_sad[v_idx].ahIcvLen != 0) {
				// work on a temporary copy in order to be able to zero mutable fields
				v_tempIpv6Packet := v_activeIpv6Packet;
mullers's avatar
mullers committed

				//zero mutable fields
				v_tempIpv6Packet.ipv6Hdr.flowLabel := 0;
				v_tempIpv6Packet.ipv6Hdr.hopLimit := 0;
				
				// Compute ICV
				v_activeIpv6Packet.extHdrList[v_authHdrIndex].authHeader.icv := 
					fx_mac( vc_sad[v_idx].ahIntegrityAlgo , vc_sad[v_idx].ahIntegrityKey, fx_encodeMessage(v_tempIpv6Packet));
		
		p_ipv6Packet := v_activeIpv6Packet;
	}//end f_setExtensionHeaders

	}//end group extHdrFns

	function f_calcIpv6PayloadChecksum( in template Ipv6Address p_srcAddr,	
										in template Ipv6Address p_dstAddr, 
mullers's avatar
mullers committed
										inout Ipv6Payload p_ipv6Payload)
	return FncRetCode {
		
		if(ischosen(p_ipv6Payload.echoReplyMsg)) {
			if(p_ipv6Payload.echoReplyMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.echoReplyMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.echoRequestMsg)) {
			if(p_ipv6Payload.echoRequestMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.echoRequestMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.nbrAdvMsg)) {
			if(p_ipv6Payload.nbrAdvMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.nbrAdvMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.nbrSolMsg)) {
			if(p_ipv6Payload.nbrSolMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.nbrSolMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.routerAdvMsg)) {
			if(p_ipv6Payload.routerAdvMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.routerAdvMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.routerSolMsg)) {
			if(p_ipv6Payload.routerSolMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.routerSolMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.redirectMsg)) {
			if(p_ipv6Payload.redirectMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.redirectMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.parameterProblemMsg)) {
			if(p_ipv6Payload.parameterProblemMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.parameterProblemMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.timeExceededMsg)) {
			if(p_ipv6Payload.timeExceededMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.timeExceededMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.packetTooBigMsg)) {
			if(p_ipv6Payload.packetTooBigMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.packetTooBigMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.destinationUnreachableMsg)) {
			if(p_ipv6Payload.destinationUnreachableMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.destinationUnreachableMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.mobileRouterAdvMsg)) {
			if(p_ipv6Payload.mobileRouterAdvMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.mobileRouterAdvMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.homeAgentAddrDiscRequestMsg)) {
			if(p_ipv6Payload.homeAgentAddrDiscRequestMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.homeAgentAddrDiscRequestMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.homeAgentAddrDiscReplyMsg)) {
			if(p_ipv6Payload.homeAgentAddrDiscReplyMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.homeAgentAddrDiscReplyMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.mobilePrefixSolMsg)) {
			if(p_ipv6Payload.mobilePrefixSolMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.mobilePrefixSolMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.mobilePrefixAdvMsg)) {
			if(p_ipv6Payload.mobilePrefixAdvMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.mobilePrefixAdvMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
		else if(ischosen(p_ipv6Payload.otherIcmpv6Msg)) {
			if(p_ipv6Payload.otherIcmpv6Msg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.otherIcmpv6Msg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_icmpHdr);
mullers's avatar
mullers committed
		else if(ischosen(p_ipv6Payload.ikeMsg)) {
			if(p_ipv6Payload.ikeMsg.checksum == c_2ZeroBytes) {
				//calc checksum
berge's avatar
berge committed
				p_ipv6Payload.ikeMsg.checksum := fx_calcPayloadChecksum (p_srcAddr, p_dstAddr, p_ipv6Payload, c_udpHdr);
mullers's avatar
mullers committed
			}
		}
		return e_success;

	}//end f_calcIpv6PayloadChecksum


    } //end group ipv6Packets
	
}//end group rfc2460Root_Functions

group rfc3775Mipv6_ExtHdrFunctions {

	/*
	 * @desc 	This goes through the Mip header and calculates length, checksum
	 *			and other specific functions of the different messages.
	 *			This function is used when sending messages.
	 * @param 	p_msg ExtensionHeaderList to be treated	
	 * @return 	execution status 
	*/
berge's avatar
berge committed
	function f_setMobileHeader(	in Ipv6Address p_srcAddr,
								in Ipv6Address p_dstAddr,
								in Ipv6Address p_pseudoSrcAddr, 
								in Ipv6Address p_pseudoDstAddr, 	
								inout MobileHeader p_mobileHeader)
	runs on LibIpv6Node
	return FncRetCode {
		var MobileHeader v_mobileHeader := valueof(p_mobileHeader);
		var Ipv6Address v_homeAddress := c_16ZeroBytes ;

		if (ischosen(p_mobileHeader.mobileMessage.bindingUpdateMsg)) {//Authorization data is only needed for BU sent to CN=IUT
			var UInt8 v_position := 0;
			//Concept of including bindingAuthentication
			// specifiy on template level all options
			// 1) if authenticator == c_20ZeroBytes then value is calculated in f_setMobileHeader
			// 2) if authenticator != c_20ZeroBytes then no value is calculated in f_setMobileHeader,
			//     because it's assumed that the correct value was set on template level
			// 3) same applies to nonceIndex etc

			// Process Nonce Indices
			if (f_isPresentNonceIndicesInBU(p_mobileHeader.mobileMessage.bindingUpdateMsg, v_position) == e_success) {

				// Fill Home Nonce Index only when set to c_uInt16Zero
				if (p_mobileHeader.mobileMessage.bindingUpdateMsg.mobileOptions[v_position].mobileOptNonceIndices.homeNonceIndex == c_uInt16Zero ) {
					if(vc_mobileSec.mnSimuParams.receivedHomeNonceIndex != c_uInt16Zero) {
							p_mobileHeader.mobileMessage.bindingUpdateMsg.mobileOptions[v_position].mobileOptNonceIndices.homeNonceIndex
							:= vc_mobileSec.mnSimuParams.receivedHomeNonceIndex;
					}
					else {
						log("f_setMobileHeader: Info: NonceIndices included in Binding Update, but mnSimuParams.receivedHomeNonceIndex not initialized");
					}
				}
				
				// Fill Care-Of Nonce Index only when set to c_uInt16Zero
				if (p_mobileHeader.mobileMessage.bindingUpdateMsg.mobileOptions[v_position].mobileOptNonceIndices.careOfNonceIndex == c_uInt16Zero) {
					if(vc_mobileSec.mnSimuParams.receivedCareOfNonceIndex != c_uInt16Zero) {
							p_mobileHeader.mobileMessage.bindingUpdateMsg.mobileOptions[v_position].mobileOptNonceIndices.careOfNonceIndex
							:= vc_mobileSec.mnSimuParams.receivedCareOfNonceIndex;
					}
					else {
						log("f_setMobileHeader: Info: NonceIndices included in Binding Update, but mnSimuParams.receivedCareOfNonceIndex not initialized");
			} // end Process Nonce Indices
				
			if (f_isPresentBindingAuthorizationDataOptionInBU(p_mobileHeader.mobileMessage.bindingUpdateMsg, v_position) == e_success) {
				if(vc_mobileSec.mnSimuParams.receivedHomeKeygenToken != c_64ZeroBits
					and vc_mobileSec.mnSimuParams.receivedCareOfKeygenToken != c_64ZeroBits) {

						// kbm is different if BU is sent for de-registration				
						if (p_mobileHeader.mobileMessage.bindingUpdateMsg.lifeTime != 0) {
							vc_mobileSec.mnSimuParams.kbm := fx_mac(		e_auth_sha1/*e_sha1*/, c_1ZeroByte,
																			bit2oct(vc_mobileSec.mnSimuParams.receivedHomeKeygenToken)
																			& bit2oct(vc_mobileSec.mnSimuParams.receivedCareOfKeygenToken));
						}
						else {
							vc_mobileSec.mnSimuParams.kbm := fx_mac(		e_auth_sha1/*e_sha1*/, c_1ZeroByte,
																			bit2oct(vc_mobileSec.mnSimuParams.receivedHomeKeygenToken));	
						}
berge's avatar
berge committed
											
						//set Authenticator option with dummy Authenticator
						p_mobileHeader.mobileMessage.bindingUpdateMsg.mobileOptions[v_position].mobileBindingAuthorizationData := {
														mobileOptType := 5,
														mobileOptLen := 12,
														authenticator := c_12ZeroBytes}
																		
						//calculate the mipHeaderLength over the dummy Authenticator
berge's avatar
berge committed
						//modified by AMB to easily send packets with wrong mobileHdrLen
						//calc mobileHeaderLen
						if (p_mobileHeader.headerLen == c_uInt8Zero ) {
							p_mobileHeader.headerLen := fx_mipHeaderLength(p_mobileHeader) ;
						}
						
						//set Authenticator to omit in order to calc the authenticator
						p_mobileHeader.mobileMessage.bindingUpdateMsg.mobileOptions[v_position].mobileBindingAuthorizationData.authenticator := omit;
						// compute authenticator
berge's avatar
berge committed
						p_mobileHeader.mobileMessage.bindingUpdateMsg.mobileOptions[v_position].mobileBindingAuthorizationData.authenticator 
								 := fx_mac(	e_auth_hmacSha1_96/*e_hmac_sha1_96*/, vc_mobileSec.mnSimuParams.kbm,
berge's avatar
berge committed
																		p_srcAddr //careOfaddr 
																		& p_dstAddr //cnAddr
					log("f_setMobileHeader: Error: BindingAuthorizationDataOption included in Binding Update, but receivedHomeKeygenToken/receivedCareOfKeygenToken not initialized");
					return e_error;	
				}
		else if (ischosen(p_mobileHeader.mobileMessage.bindingAckMsg)) {
			var UInt8 v_position := 0;
			//Concept of including bindingAuthentication
			// specifiy on template level all options
			// 1) if authenticator == c_20ZeroBytes then value is calculated in f_setMobileHeader
			// 2) if authenticator != c_20ZeroBytes then no value is calculated in f_setMobileHeader,
			//     because it's assumed that the correct value was set on template level
			// 3) same applies to nonceIndex etc

			// Process Nonce Indices
			if (f_isPresentNonceIndicesInBA(p_mobileHeader.mobileMessage.bindingAckMsg, v_position) == e_success) {

				// Fill Home Nonce Index only when set to c_uInt16Zero
				if (p_mobileHeader.mobileMessage.bindingAckMsg.mobileOptions[v_position].mobileOptNonceIndices.homeNonceIndex == c_uInt16Zero ) {
					if(vc_mobileSec.cnSimuParams.nonceIndex != c_uInt16Zero) {
							p_mobileHeader.mobileMessage.bindingAckMsg.mobileOptions[v_position].mobileOptNonceIndices.homeNonceIndex
							:= vc_mobileSec.cnSimuParams.nonceIndex;
					}
					else {
						log("f_setMobileHeader: Info: NonceIndices included in Binding Ack, but cnSimuParams.nonceIndex not initialized");
					}
				}
				
				// Fill Care-Of Nonce Index only when set to c_uInt16Zero
				if (p_mobileHeader.mobileMessage.bindingAckMsg.mobileOptions[v_position].mobileOptNonceIndices.careOfNonceIndex == c_uInt16Zero) {
					if(vc_mobileSec.cnSimuParams.nonceIndex != c_uInt16Zero) {
							p_mobileHeader.mobileMessage.bindingAckMsg.mobileOptions[v_position].mobileOptNonceIndices.careOfNonceIndex
							:= vc_mobileSec.cnSimuParams.nonceIndex;
					}
					else {
						log("f_setMobileHeader: Info: NonceIndices included in Binding Ack, but cnSimuParams.nonceIndex not initialized");
					}
				}
			} // end Process Nonce Indices
				
			if (f_isPresentBindingAuthorizationDataOptionInBA(p_mobileHeader.mobileMessage.bindingAckMsg, v_position) == e_success) {
				if(vc_mobileSec.cnSimuParams.homeKeygenToken != c_64ZeroBits
					and vc_mobileSec.cnSimuParams.careOfKeygenToken != c_64ZeroBits) {

						// kbm is different if BA is sent for de-registration				
						if (p_mobileHeader.mobileMessage.bindingAckMsg.lifeTime != 0) {
							vc_mobileSec.cnSimuParams.kbm := fx_mac(		e_auth_sha1/*e_sha1*/, c_1ZeroByte,
																			bit2oct(vc_mobileSec.cnSimuParams.homeKeygenToken)
																			& bit2oct(vc_mobileSec.cnSimuParams.careOfKeygenToken));
						}
						else {
							vc_mobileSec.cnSimuParams.kbm := fx_mac(		e_auth_sha1/*e_sha1*/, c_1ZeroByte,
																			bit2oct(vc_mobileSec.cnSimuParams.homeKeygenToken));	
						}
											
						//set Authenticator option with dummy Authenticator
						p_mobileHeader.mobileMessage.bindingAckMsg.mobileOptions[v_position].mobileBindingAuthorizationData := {
														mobileOptType := 5,
														mobileOptLen := 12,
														authenticator := c_12ZeroBytes}
																		
						//calculate the mipHeaderLength over the dummy Authenticator
						//modified by AMB to easily send packets with wrong mobileHdrLen
						//calc mobileHeaderLen
						if (p_mobileHeader.headerLen == c_uInt8Zero ) {
							p_mobileHeader.headerLen := fx_mipHeaderLength(p_mobileHeader) ;
						}
						
						//set Authenticator to omit in order to calc the authenticator
						p_mobileHeader.mobileMessage.bindingAckMsg.mobileOptions[v_position].mobileBindingAuthorizationData.authenticator := omit;
				
						// compute authenticator
						p_mobileHeader.mobileMessage.bindingAckMsg.mobileOptions[v_position].mobileBindingAuthorizationData.authenticator 
								 := fx_mac(	e_auth_hmacSha1_96/*e_hmac_sha1_96*/, vc_mobileSec.cnSimuParams.kbm,
																		p_dstAddr //cnAddr			/!\ inverted /!\
																		& p_srcAddr //careOfaddr    /!\ for BA   /!\
																		& fx_mipHdrToOct(p_mobileHeader) );
				}
				else {
					log("f_setMobileHeader: Error: BindingAuthorizationDataOption included in Binding Ack, but HomeKeygenToken/CareOfKeygenToken not initialized");
					return e_error;	
				}
			}
		}
		// calc mobileHeaderLen only when set to c_uInt8Zero
berge's avatar
berge committed
		if (p_mobileHeader.headerLen == c_uInt8Zero ) {
			p_mobileHeader.headerLen := fx_mipHeaderLength(p_mobileHeader);
		}
		// calc mipChecksum only when set to c_2ZeroBytes
berge's avatar
berge committed
		if (p_mobileHeader.checksum == c_2ZeroBytes) {
berge's avatar
berge committed
			p_mobileHeader.checksum := fx_mipHeaderChecksum ( 	p_pseudoSrcAddr, 
																p_pseudoDstAddr, 
																p_mobileHeader);
berge's avatar
berge committed
		}
berge's avatar
berge committed
	function f_checkAuthenticator (	in Ipv6Address p_srcAddr,
									in Ipv6Address p_dstAddr,
									in MobileHeader p_mobileHeader,
									in octetstring p_receivedAuthenticator)
	runs on LibIpv6Node 
	return FncRetCode {
		var UInt8 v_position := 0;
		var octetstring v_computedAuthenticator;
		
		if (f_isPresentBindingAuthorizationDataOptionInBU(p_mobileHeader.mobileMessage.bindingUpdateMsg, v_position) == e_success) {
berge's avatar
berge committed
				
			p_mobileHeader.checksum := c_2ZeroBytes;			
				
berge's avatar
berge committed
			if (p_mobileHeader.mobileMessage.bindingUpdateMsg.lifeTime != 0) {
				vc_mobileSec.cnSimuParams.kbm := fx_mac(		e_auth_sha1/*e_sha1*/, c_1ZeroByte,
berge's avatar
berge committed
																bit2oct(vc_mobileSec.cnSimuParams.homeKeygenToken)
																& bit2oct(vc_mobileSec.cnSimuParams.careOfKeygenToken));
			}
			else {
				vc_mobileSec.cnSimuParams.kbm := fx_mac(		e_auth_sha1/*e_sha1*/, c_1ZeroByte,
berge's avatar
berge committed
																bit2oct(vc_mobileSec.cnSimuParams.homeKeygenToken));	
			}
									
			//set Authenticator option with dummy Authenticator
			p_mobileHeader.mobileMessage.bindingUpdateMsg.mobileOptions[v_position].mobileBindingAuthorizationData := {
											mobileOptType := 5,
											mobileOptLen := 12,
											authenticator := c_12ZeroBytes}
																
			//calculate the mipHeaderLength over the dummy Authenticator
			p_mobileHeader.headerLen := fx_mipHeaderLength(p_mobileHeader) ;
				
			//set Authenticator to omit in order to calc the authenticator
			p_mobileHeader.mobileMessage.bindingUpdateMsg.mobileOptions[v_position].mobileBindingAuthorizationData.authenticator := omit;
		
			v_computedAuthenticator := fx_mac(	e_auth_hmacSha1_96/*e_hmac_sha1_96*/, vc_mobileSec.cnSimuParams.kbm,
berge's avatar
berge committed
												p_srcAddr //careOfaddr 
												& p_dstAddr //cnAddr
												& fx_mipHdrToOct(p_mobileHeader) );
												
			if (p_receivedAuthenticator != v_computedAuthenticator) {
				return e_error;
			}
			
			return e_success;	
		}
		else {
			log("f_checkAuthenticator: Error: This packet does not contain any Binding Update");
			return e_error;
		}
	} //end function f_checkAuthenticator

	/*
	 * @desc 	This goes through the BindingAck and
	 *			checks if a NonceIndicesOption is present.
	 * @param 	p_bindingUpdate Binding Update to be treated
	 * @param 	v_position Position of the NonceIndicesOption in the MobileOptionList
	 * @return 	execution status 
	*/
	function f_isPresentNonceIndicesInBA(	in BindingAckMsg p_bindingAck,
														inout UInt8 v_position)
	runs on LibIpv6Node
	return FncRetCode {
		var FncRetCode v_ret := e_error;
		var UInt8 i;
	
		//select ext hdrs that need special calculation
		for (i:=0; i<sizeof(p_bindingAck.mobileOptions) and (v_ret != e_success); i:=i+1) {
			if (ischosen(p_bindingAck.mobileOptions[i].mobileOptNonceIndices)) {
					v_position := i;
					v_ret := e_success;
				}
		}
		return v_ret;
	}//end function f_isPresentNonceIndicesInBA
	
	/*
	 * @desc 	This goes through the BindingAck and
	 *			checks if a AuthorizationDataOption is present.
	 * @param 	p_bindingUpdate Binding Update to be treated
	 * @param 	v_position Position of the AuthorizationDataOption in the MobileOptionList
	 * @return 	execution status 
	*/
	function f_isPresentBindingAuthorizationDataOptionInBA(	in BindingAckMsg p_bindingAck,
														inout UInt8 v_position)
	runs on LibIpv6Node
	return FncRetCode {
		var FncRetCode v_ret := e_error;
		var UInt8 i;
	
		//select ext hdrs that need special calculation
		for (i:=0; i<sizeof(p_bindingAck.mobileOptions) and (v_ret != e_success); i:=i+1) {
			if (ischosen(p_bindingAck.mobileOptions[i].mobileBindingAuthorizationData)) {
					v_position := i;
					v_ret := e_success;
				}
		}
		return v_ret;
	}//end function f_isPresentBindingAuthorizationDataOptionInBA


	/*
	 * @desc 	This goes through the BindingUpdate and
	 *			checks if a NonceIndicesOption is present.
	 * @param 	p_bindingUpdate Binding Update to be treated
	 * @param 	v_position Position of the NonceIndicesOption in the MobileOptionList
	 * @return 	execution status 
	*/
	function f_isPresentNonceIndicesInBU(	in BindingUpdateMsg p_bindingUpdate,
														inout UInt8 v_position)
	runs on LibIpv6Node
	return FncRetCode {
		var FncRetCode v_ret := e_error;
		var UInt8 i;

		//select ext hdrs that need special calculation
		for (i:=0; i<sizeof(p_bindingUpdate.mobileOptions) and (v_ret != e_success); i:=i+1) {
			if (ischosen(p_bindingUpdate.mobileOptions[i].mobileOptNonceIndices)) {
					v_position := i;
					v_ret := e_success;
				}
		}
		return v_ret;
	}//end function f_isPresentNonceIndicesInBU

	/*
	 * @desc 	This goes through the BindingUpdate and
	 *			checks if a AuthorizationDataOption is present.
	 * @param 	p_bindingUpdate Binding Update to be treated
	 * @param 	v_position Position of the AuthorizationDataOption in the MobileOptionList
	 * @return 	execution status 
	*/
	function f_isPresentBindingAuthorizationDataOptionInBU(	in BindingUpdateMsg p_bindingUpdate,
														inout UInt8 v_position)
	runs on LibIpv6Node
	return FncRetCode {
		var FncRetCode v_ret := e_error;
		var UInt8 i;

		//select ext hdrs that need special calculation
		for (i:=0; i<sizeof(p_bindingUpdate.mobileOptions) and (v_ret != e_success); i:=i+1) {
			if (ischosen(p_bindingUpdate.mobileOptions[i].mobileBindingAuthorizationData)) {
					v_position := i;
					v_ret := e_success;
				}
		}
		return v_ret;
	}//end function f_isPresentBindingAuthorizationDataOptionInBU
mullers's avatar
mullers committed

	/*
	 * @desc 	This sends a IPv6 packet with MipExtHdr - Binding Update
	 *			from an IPv6 node to any NUT.
	 *			
	 * @remark  
	 * @param 	p_msg MIPHeader to be sent	
	 * @return 	execution status
	*/
	function f_sendBu(template BindingUpdate p_msg)
mullers's avatar
mullers committed
	runs on LibIpv6Node
	return FncRetCode {
		//Variables
		var BindingUpdate v_ipPkt;
		v_ipPkt := valueof(p_msg);
		
		//set extensionHeaders
		if(f_setExtensionHeaders(	v_ipPkt ) != e_success) {
			log(" **** f_sendBu: Error when calculating length of extension headers ****");
			return e_error;
		}

mullers's avatar
mullers committed
		//send
		ipPort.send(v_ipPkt);

		return e_success;
mullers's avatar
mullers committed

	/*
	 * @desc 	This sends a IPv6 packet with MipExtHdr - Binding Acknowledgement
	 *			from an IPv6 node to any NUT.
	 *			
	 * @remark  
	 * @param 	p_msg MIPHeader to be sent	
	 * @return 	execution status
	*/
	function f_sendBa(template BindingAcknowledgement p_msg)
mullers's avatar
mullers committed
	runs on LibIpv6Node
	return FncRetCode {
		//Variables
		var BindingAcknowledgement v_ipPkt;
		v_ipPkt := valueof(p_msg);

		//set extensionHeaders
		if(f_setExtensionHeaders(	v_ipPkt ) != e_success) {
			log(" **** f_sendBa: Error when calculating length of extension headers ****");
			return e_error;
		}
		
mullers's avatar
mullers committed
		//send
		ipPort.send(v_ipPkt);

		return e_success;
mullers's avatar
mullers committed

	/*
	 * @desc 	This sends a IPv6 packet with MipExtHdr - Binding Error
	 *			from an IPv6 node to any NUT.
	 *			
	 * @remark  
	 * @param 	p_msg MIPHeader to be sent	
	 * @return 	execution status
	*/
	function f_sendBe(template BindingError p_msg)
mullers's avatar
mullers committed
	runs on LibIpv6Node
	return FncRetCode {
		//Variables
		var BindingError v_ipPkt;
		v_ipPkt := valueof(p_msg);

		//set extensionHeaders
		if(f_setExtensionHeaders(	v_ipPkt ) != e_success) {
			log(" **** f_sendBe: Error when calculating length of extension headers ****");
			return e_error;
		}

mullers's avatar
mullers committed
		//send
		ipPort.send(v_ipPkt);

		return e_success;
mullers's avatar
mullers committed

	/*
	 * @desc 	This sends a IPv6 packet with MipExtHdr - Binding Refresh Request
	 *			from an IPv6 node to any NUT.
	 *			
	 * @remark  
	 * @param 	p_msg MIPHeader to be sent	
	 * @return 	execution status
	*/
	function f_sendBr(template BindingRefreshRequest p_msg)
mullers's avatar
mullers committed
	runs on LibIpv6Node
	return FncRetCode {
		//Variables
		var BindingRefreshRequest v_ipPkt;
		v_ipPkt := valueof(p_msg);
		if(f_setExtensionHeaders(	v_ipPkt ) != e_success) {
			log(" **** f_sendBr: Error when calculating length of extension headers ****");
			return e_error;
		}

mullers's avatar
mullers committed
		//send
		ipPort.send(v_ipPkt);

		return e_success;
mullers's avatar
mullers committed

	/*
	 * @desc 	This sends a IPv6 packet with MipExtHdr - Home Test
	 *			from an IPv6 node to any NUT.
	 *			
	 * @remark  
	 * @param 	p_msg MIPHeader to be sent	
	 * @return 	execution status
	*/
	function f_sendHot(template HomeTest p_msg)
	runs on LibIpv6Node
	return FncRetCode {
		//Variables
		var HomeTest v_ipPkt;
		v_ipPkt := valueof(p_msg);

		//set extensionHeaders
		if(f_setExtensionHeaders(	v_ipPkt ) != e_success) {
			log(" **** f_sendHot: Error when calculating length of extension headers ****");
			return e_error;
		}

mullers's avatar
mullers committed
		//send
		ipPort.send(v_ipPkt);

		return e_success;
	}//end f_sendHot

		/*
	 * @desc 	This sends a IPv6 packet with MipExtHdr - Home Test Init
	 *			from an IPv6 node to any NUT.
	 *			
	 * @remark  
	 * @param 	p_msg MIPHeader to be sent	
	 * @return 	execution status
	*/
	function f_sendHoti(template HomeTestInit p_msg)
	runs on LibIpv6Node
	return FncRetCode {
		//Variables
		var HomeTestInit v_ipPkt;
		v_ipPkt := valueof(p_msg);

		//set extensionHeaders
		if(f_setExtensionHeaders(	v_ipPkt ) != e_success) {
			log(" **** f_sendHoti: Error when calculating length of extension headers ****");
			return e_error;
		}

mullers's avatar
mullers committed
		//send
		ipPort.send(v_ipPkt);

		return e_success;
	}//end f_sendHoti

	/*
	 * @desc 	This sends a IPv6 packet with MipExtHdr - CareOfTestInit
	 *			from an IPv6 node to any NUT.
	 *			
	 * @remark  
	 * @param 	p_msg MIPHeader to be sent	
	 * @return 	execution status
	*/
	function f_sendCoti(template CareOfTestInit p_msg)
	runs on LibIpv6Node
	return FncRetCode {
		//Variables
		var CareOfTestInit v_ipPkt;
		v_ipPkt := valueof(p_msg);

		//set extensionHeaders
		if(f_setExtensionHeaders(	v_ipPkt ) != e_success) {
			log(" **** f_sendCoti: Error when calculating length of extension headers ****");
			return e_error;
		}

mullers's avatar
mullers committed
		//send
		ipPort.send(v_ipPkt);

		return e_success;
	}//end f_sendCoti

		/*
	 * @desc 	This sends a IPv6 packet with MipExtHdr - CareOfTest
	 *			from an IPv6 node to any NUT.
	 *			
	 * @remark  
	 * @param 	p_msg MIPHeader to be sent	
	 * @return 	execution status
	*/
	function f_sendCot(template CareOfTest p_msg)
	runs on LibIpv6Node
	return FncRetCode {
		//Variables
		var CareOfTest v_ipPkt;
		v_ipPkt := valueof(p_msg);

		//set extensionHeaders
		if(f_setExtensionHeaders(	v_ipPkt ) != e_success) {
			log(" **** f_sendCoti: Error when calculating length of extension headers ****");
			return e_error;
		}