--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/ConnectionMgr/src/CIcmpV6Receiver.cpp Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,208 @@
+// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Name : CIcmpV6Receiver.cpp
+// Part of : ConnectionMgr
+// Version : SIP/4.0
+// Destination Unreachable Message:
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// | Type | Code | Checksum |
+// | Unused |
+// | As much of invoking packet |
+// + as will fit without the ICMPv6 packet +
+// | exceeding the minimum IPv6 MTU [IPv6] |
+// IPv6 Header Format:
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// |Version| Traffic Class | Flow Label |
+// | Payload Length | Next Header | Hop Limit |
+// + Source Address +
+// + Destination Address +
+// Extension Header Format:
+// | Next Header | Hdr Ext Len | |
+// . type-specific data (variable length) .
+// User datagram:
+// 0 7 8 15 16 23 24 31
+// | Source | Destination |
+// | Port | Port |
+// | Length | Checksum |
+// | data octets ...
+// In the code the data is located in 8-bit pieces.
+//
+
+
+
+
+#include <ip6_hdr.h>
+#include <icmp6_hdr.h>
+#include <udp_hdr.h>
+#include <ext_hdr.h>
+#include <in_sock.h>
+#include "CIcmpV6Receiver.h"
+#include "MIcmpReceiver.h"
+#include "CSipConnection.h"
+#include "CommonConsts.h"
+#include "SipLogs.h"
+
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::NewL
+// -----------------------------------------------------------------------------
+//
+CIcmpV6Receiver* CIcmpV6Receiver::NewL(MIcmpErrorObserver& aObserver,
+ RSocketServ& aServer)
+ {
+ CIcmpV6Receiver* self = new (ELeave) CIcmpV6Receiver();
+ CleanupStack::PushL(self);
+ self->ConstructL(aObserver, aServer);
+ CleanupStack::Pop();
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::CIcmpV6Receiver
+// -----------------------------------------------------------------------------
+//
+CIcmpV6Receiver::CIcmpV6Receiver() : CActive( CActive::EPriorityStandard )
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CIcmpV6Receiver::ConstructL(MIcmpErrorObserver& aObserver,
+ RSocketServ& aServer)
+ {
+ CActiveScheduler::Add(this);
+ iObserver = &aObserver;
+ iServer = &aServer;
+
+ // Start
+ User::LeaveIfError(iSocket.Open(*iServer, KAfInet, KSockDatagram,
+ KProtocolInet6Icmp));
+ Receive();
+ }
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::~CIcmpV6Receiver
+// -----------------------------------------------------------------------------
+//
+CIcmpV6Receiver::~CIcmpV6Receiver()
+ {
+ Cancel();
+ iSocket.Close();
+ }
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::RunL
+// -----------------------------------------------------------------------------
+//
+void CIcmpV6Receiver::RunL()
+ {
+ if(iStatus == KErrNone)
+ {
+ CheckError();
+ Receive();
+ }
+ }
+
+// Disabled PC-Lint warning for "Suspicious pointer-to-pointer conversion
+// (area too small))". It was caused by TUin8* to TInet6xxx typecasts and could
+// not be avoided otherwise.
+/*lint -e826 */
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::CheckError
+// -----------------------------------------------------------------------------
+//
+void CIcmpV6Receiver::CheckError()
+ {
+ const TUint KDestinationUnreachable = 1;
+
+ // Pointer to ICMP header
+ TInet6HeaderICMP* icmpPtr = ( TInet6HeaderICMP* ) iData.Ptr();
+
+ // Pointer to IPv6 header
+ TInet6HeaderIP* ipv6Ptr = ( TInet6HeaderIP* )( iData.Ptr() + 8 );
+ // Get the whole length of the header in bytes
+ TUint32 payloadLength = ipv6Ptr->PayloadLength();
+ TUint32 offset = 0;
+
+ // Pointer to IPv6 extension header
+ TInet6HeaderExtension* extPtr =
+ ( TInet6HeaderExtension* )( iData.Ptr() + 14 );
+ // Get the extension header length in bytes
+ TUint32 extHdrLength = extPtr->HeaderLength();
+
+ // Pointer to UDP data
+ TInet6HeaderUDP* udpPtr = ( TInet6HeaderUDP* )( ipv6Ptr->EndPtr() );
+
+ // Error message type
+ TUint32 error = icmpPtr->Type();
+ if( error == KDestinationUnreachable )
+ {
+ TUint32 nextHeader = 0;
+ do // Search the correct header, if there are extension headers
+ {
+ nextHeader = extPtr->NextHeader();
+ if( nextHeader == KProtocolInetUdp )
+ {
+ // Get the destination port number
+ iAddress.SetPort( udpPtr->DstPort() );
+
+ // Set the destination address
+ iAddress.SetAddress( ipv6Ptr->DstAddr() );
+
+ __SIP_INT_LOG1( "ICMP error", error )
+ __SIP_ADDR_LOG( "ICMP error address", iAddress )
+
+ iObserver->IcmpError( iAddress );
+ }
+ else
+ {
+ // Step to next header
+ if( offset < payloadLength )
+ {
+ extPtr = extPtr + extHdrLength;
+ offset = offset + extHdrLength;
+ }
+ }
+ // Loop until UDP datagram is found. If it is not found,
+ // get out of here and do nothing.
+ } while ((nextHeader != KProtocolInetUdp) && (offset < payloadLength));
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::DoCancel
+// -----------------------------------------------------------------------------
+//
+void CIcmpV6Receiver::DoCancel()
+ {
+ iSocket.CancelRecv();
+ }
+
+// -----------------------------------------------------------------------------
+// CIcmpV6Receiver::Receive
+// -----------------------------------------------------------------------------
+//
+void CIcmpV6Receiver::Receive()
+ {
+ if(!IsActive())
+ {
+ iSocket.Recv( iData, 0, iStatus );
+ SetActive();
+ }
+ }