// Copyright (c) 2006-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:
//

/**
 @file DHCPUnicastTranslator.cpp
 @internalComponent
*/

#include <in_chk.h>
#include <in_sock.h>
#include <in_bind.h>
#include "in6_opt.h"
#include <udp_hdr.h>

#include "DHCPUnicastTranslator.h"
#include "HookLog.h"
#include "ipeventlistener.h"




CDHCPUnicastTranslator::CDHCPUnicastTranslator(CProtocolInet6Binder& aParent):
	iParent(aParent)
	{
	}
		
CDHCPUnicastTranslator::~CDHCPUnicastTranslator()
	{
//	iParent.Unbind(this, 0);
	}

void CDHCPUnicastTranslator::FillIdentification(TServerProtocolDesc& anEntry)
/**
 * Fills in an existing protocol description structure with details of this protocol.
 *
 * @param aProtocolDesc: reference to the structure to be filled in
 */
	{
	anEntry.iName=_S("dhcpunicasttranslator");
	anEntry.iAddrFamily=KAfInet;
	anEntry.iSockType=0;
	anEntry.iProtocol=1; // not in a family so doesn't really matter
	anEntry.iVersion=TVersion(1, 0, 0);
	anEntry.iByteOrder=EBigEndian;
	anEntry.iServiceInfo=0;
	anEntry.iNamingServices=0;
	anEntry.iSecurity=0;
	anEntry.iMessageSize=0;
	anEntry.iServiceTypeInfo=0;
	anEntry.iNumSockets=0;
	}


void CDHCPUnicastTranslator::Identify(TServerProtocolDesc* aProtocolDesc) const
/**
 * Fills in an existing protocol description structure with details of this protocol.
 *
 * @param aProtocolDesc: pointer to the structure to be filled in
 */
	{
	FillIdentification(*aProtocolDesc);
	}



/**
 * Incoming packet
 */
TInt CDHCPUnicastTranslator::ApplyL(RMBufHookPacket& aPacket, RMBufRecvInfo& aInfo)
	{

	LOG	(
		_LIT(KHookNotifyStr,"CDHCPUnicastTranslator::ApplyL hit with protocol: %d");
		HookLog::Printf( KHookNotifyStr , aInfo.iProtocol );
		)
	
	/** Fix for INC079832 - DHCP must be able to receive unicast replies from
	 *   DHCP server (to an address that hasn't been set yet! chicken and egg).
	 *
	 *  Without this, a DHCP reply unicast to an address which isn't yet assigned
	 *   to the inbound interface will be dropped.
	 *
	 *  So we need to detect BOOTP packets which are about to be dropped. This is
	 *   done by installing this object as a "forwarding hook".
	 *
	 *  DHCP packets are detected as follows:
	 *   - packet is UDP
	 *   - UDP destination port is 0x0044
	 *
	 *  Modification is performed by setting dest address to broadcast address
	 *   (and updating checksum)
	 *
	 *  Then we return KIp6Hook_DONE (which signals to the stack to re-inject
	 *   the packet into the incoming data path).
	 *
	 *  Note: this trick isn't needed for IPv6 as link-local unicast is always
	 *   possible before network/global address has been assigned.
	 */
    if (aInfo.iVersion != 4 || aInfo.iProtocol != KProtocolInetUdp)
        return KIp6Hook_PASS;    // Only interested in IPv4 and UDP.

    TInetAddr&  dst = TInetAddr::Cast(aInfo.iDstAddr);

    if (!dst.IsUnicast())
        return KIp6Hook_PASS;    // Only the unicast case really needs fixing

    // Need to examine the UDP header
    TInet6Packet<TInet6HeaderUDP> udp(aPacket, aInfo.iOffset);
    if (udp.iHdr == NULL)
        return KIp6Hook_PASS;    // Oops, short packet, let someone else worry about it.

    // To cause least distruption, one could try to check that this really is
    // DCHP address configuration message with packet destination address
    // matching the offered address inside DCHP message (but this would need
    // more extensive packet snooping here)    
#ifndef _DEBUG
    if (udp.iHdr->DstPort() == 68)
#else
	if (udp.iHdr->DstPort() == 68 || udp.iHdr->DstPort() == 127 || udp.iHdr->DstPort() == 119 || udp.iHdr->DstPort() == 125
	#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
	|| udp.iHdr->DstPort() == 92 || udp.iHdr->DstPort() == 99
	#endif//SYMBIAN_NETWORKING_DHCP_MSG_HEADERS	
	)	// debug mode, src port 127, 119, 125, 91, 98
#endif
        {
        static const TIp6Addr broadcast = {{{0,0,0,0,0,0,0,0,0,0,0xff,0xff,255,255,255,255}}};

        dst.SetAddress(broadcast);
        udp.iHdr->SetChecksum(0);    // Either this or recompute the UDP checksum for broadcast address.
        return KIp6Hook_DONE;
        }
    return KIp6Hook_PASS;
	}


