bluetoothcommsprofiles/btpan/pannapiphook/src/pannapiphook.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothcommsprofiles/btpan/pannapiphook/src/pannapiphook.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,201 @@
+// 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;
+	}