bluetoothcommsprofiles/btpan/pannapiphook/src/pannapiphook.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:38:54 +0100
branchRCL_3
changeset 24 e9b924a62a66
parent 0 29b1cd4cb562
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201031 Kit: 201035

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

#include <bluetooth/logger.h>
#include "pannapiphook.h"
#include "RBnepFrame.h"			// For the DHCP / Forwarding RMBufPacket header flags

#include <in_sock.h>
#include <in_chk.h>
#include <udp_hdr.h>
#include <es_prot_internal.h>

_LIT(KProtocolPanNapIpHookName, "pannapiphook");

#ifdef __FLOG_ACTIVE
_LIT8(KLogComponent, LOG_COMPONENT_PAN_NAPIPHOOK);
#endif

#ifdef __FLOG_ACTIVE
// Define strings for logging.
_LIT(KStringTrue, "True");
_LIT(KStringFalse,  "False");
_LIT(KStringDropped, "Dropped");
_LIT(KStringPassed,  "Passed");
#endif


static const TUint KDhcpDstPort = 67;

// Returning a negative number from the ApplyL() method in an IP hook will make the IP
// stack drop the packet. No constant is defined in networking so define it here to
// help readability of the code.
static const TInt KIp6Hook_DROP = -1;

//
// CPanNapIpHook
//
CPanNapIpHook* CPanNapIpHook::NewL()
	{
	CPanNapIpHook* self = new(ELeave) CPanNapIpHook();
	return self;
	}

CPanNapIpHook::~CPanNapIpHook()
	{
	Unbind(this,BindHookAll());
	CProtocolPosthook::NetworkDetached();
	}

void CPanNapIpHook::NetworkAttachedL()
	{
	// This hook is dual purpose and checks both that incoming packets destined for the
	// DHCP server and any packets to be forwarded to the uplink have access to do so.
	// This is why the hook gets bound in 2 places, once for forwarding packets and once
	// for all incoming packets. The logic in ApplyL() determines where the hook has 
	// been called from.
	NetworkService()->BindL(this, BindForwardHook());
	NetworkService()->BindL(this, BindHookAll());
	iManager = NetworkService()->Interfacer();
	}

TInt CPanNapIpHook::ApplyL(RMBufHookPacket &aPacket, RMBufRecvInfo &aInfo)
	{
	TInt rCode = KIp6Hook_PASS;
	
	// This hook is for packets coming from BNEP only and performs two purposes depending
	// on whether or not the packet is destined for the local host or not.
	if(aInfo.iFlags & KBnep)
		{
		LOG1(_L("Remote device granted access to uplink: %S"), (aInfo.iFlags & KBnepForwardingAllowed) ? &KStringTrue() : &KStringFalse());
		
		if (iManager->IsForMeAddress(TInetAddr::Cast(aInfo.iDstAddr).Ip6Address(), aInfo.iInterfaceIndex))
			{
			LOG(_L("Packet destined for local host"));

			// Make sure that any packets from BNEP destined for the DHCP Server are processed
			// only if it has come from a remote device granted access to the uplink
			if(aInfo.iProtocol == KProtocolInetUdp)
				{
				TInet6Checksum<TInet6HeaderIP4> ipHeader(aPacket);
				TInet6Packet<TInet6HeaderUDP> udpHeader(aPacket, ipHeader.iHdr->HeaderLength());
				
				if(udpHeader.iHdr->DstPort() == KDhcpDstPort)
					{
					LOG(_L("DHCP packet detected"));
					
					// DHCP packet. Drop if forwarding flag not set.
					if(!(aInfo.iFlags & KBnepForwardingAllowed))
						{
						aPacket.Free();
						rCode = KIp6Hook_DROP;  // Drop packet
						}
					}
				}			
			}
		else
			{
			LOG(_L("Packet destined to be forwarded"));

			// Before forwarding packets from BNEP ensure that they have come from a remote
			// device granted access to the uplink
			if(!(aInfo.iFlags & KBnepForwardingAllowed))
				{
				aPacket.Free();
				rCode = KIp6Hook_DROP;  // Drop packet
				}
			}
		}
		
	// Finished with the flags
	aInfo.iFlags &= ~KBnep;
	aInfo.iFlags &= ~KBnepForwardingAllowed;

	LOG1(_L("Packet %S"), (rCode < 0) ? &KStringDropped() : &KStringPassed());

	return rCode;
	}

void CPanNapIpHook::Identify(TServerProtocolDesc* aProtocolDesc) const 
	{
	Describe(*aProtocolDesc);
	}

void CPanNapIpHook::Describe(TServerProtocolDesc& aEntry)
	{
	aEntry.iName = KProtocolPanNapIpHookName;
	aEntry.iAddrFamily = KAfInet;
	aEntry.iSockType = KSockDatagram;
	aEntry.iProtocol = KProtocolPanNapIpHook;
	aEntry.iVersion = TVersion(1, 0, 0);
	aEntry.iByteOrder = EBigEndian;
	aEntry.iServiceInfo = KSIDatagram | KSIConnectionLess;
	aEntry.iNamingServices = 0;
	aEntry.iSecurity = KSocketNoSecurity;
	aEntry.iMessageSize = 0xffff;
	aEntry.iServiceTypeInfo = 0;
	aEntry.iNumSockets = KUnlimitedSockets;
	aEntry.iServiceTypeInfo = ESocketSupport | EInterface;
	}

//
// CPanNapIpHookFamily
//	
CPanNapIpHookFamily::CPanNapIpHookFamily()
	{
	__DECLARE_NAME(_S("CPanNapIpHookFamily"));
	}

CPanNapIpHookFamily::~CPanNapIpHookFamily()
	{
	}

TInt CPanNapIpHookFamily::Install()
	{
	return KErrNone;
	}

TInt CPanNapIpHookFamily::Remove()
	{
	return KErrNone;
	}

TUint CPanNapIpHookFamily::ProtocolList(TServerProtocolDesc *& aProtocolList)
	{
	aProtocolList = new TServerProtocolDesc[1];
	
	if (!aProtocolList)
		{
		return 0;
		}
		
	CPanNapIpHook::Describe(aProtocolList[0]);
	return 1;
	}

CProtocolBase* CPanNapIpHookFamily::NewProtocolL(TUint /*aSockType*/, TUint aProtocol)
	{
	if (aProtocol != KProtocolPanNapIpHook)
		{
		User::Leave(KErrNotSupported);
		}
	return CPanNapIpHook::NewL();
	}

EXPORT_C CProtocolFamilyBase* Install(void)
	{
	CPanNapIpHookFamily* protocol = new CPanNapIpHookFamily();
	return protocol;
	}