networkprotocols/tcpipv4v6prt/src/in_flow.cpp
changeset 0 af10295192d8
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // in_flow.cpp - stack side of the general part of the flow
       
    15 //
       
    16 
       
    17 #include <es_mbuf.h>
       
    18 #include "in_flow.h"
       
    19 #include "inet6log.h"
       
    20 #include "iface.h"
       
    21 
       
    22 static const TUint16 KNoFrag = 0xFFFF;
       
    23 //
       
    24 //	TFlowHook
       
    25 //
       
    26 class TFlowHook
       
    27 	{
       
    28 public:
       
    29 	TFlowHook(MFlowHook &aHook, TInt aFrag) : iHook(aHook), iFrag(aFrag < 0 ? KNoFrag : (TUint16)aFrag) {}
       
    30 	MFlowHook &iHook;			//< The Flow Hook
       
    31 	const TUint16 iFrag;		//< The header size before OpenL (or 0xFFFF, if no fragmenting)
       
    32 	TUint16 iMtu;				//< The Fragmenting MTU (only if iFrag != 0xFFFF)
       
    33 	};
       
    34 
       
    35 CFlowInternalContext::~CFlowInternalContext()
       
    36 	{
       
    37 	RemoveHooks();
       
    38 	}
       
    39 
       
    40 //	**********************
       
    41 //	CFlowContext::AddHookL
       
    42 //	**********************
       
    43 //	aHook must never be NULL!
       
    44 //
       
    45 void CFlowInternalContext::AddHookL(MFlowHook *aHook, TInt aFrag)
       
    46 	{
       
    47 	//
       
    48 	// Allow call with NULL aHook, does nothing then...
       
    49 	//
       
    50 	if (!aHook)
       
    51 		return;
       
    52 	//
       
    53 	// iHookList is created only if actual hooks are required
       
    54 	//
       
    55 	if (iHookList == NULL)
       
    56 		iHookList = new (ELeave) CArrayFixFlat<TFlowHook>(4);
       
    57 	TFlowHook h(*aHook, aFrag);
       
    58 	iHookList->AppendL(h);
       
    59 	aHook->Open();
       
    60 	}
       
    61 
       
    62 //	*************************
       
    63 //	CFlowContext::RemoveHooks
       
    64 //	*************************
       
    65 //
       
    66 void CFlowInternalContext::RemoveHooks()
       
    67 	{
       
    68 	//
       
    69 	// Remove hooks
       
    70 	//
       
    71 	if (iHookList)
       
    72 		{
       
    73 		for (TInt i = iHookList->Count(); i > 0; )
       
    74 			{
       
    75 			const TFlowHook &h = iHookList->At(--i);
       
    76 			h.iHook.Close();
       
    77 			}
       
    78 		delete iHookList;
       
    79 		iHookList = NULL;
       
    80 		}
       
    81 	}
       
    82 
       
    83 //	*******************
       
    84 //	CFlowContext::Start
       
    85 //	*******************
       
    86 //	Must be called once when the flow Open/Hook adding has
       
    87 //	been completed, but before calling the hook Ready methods
       
    88 //
       
    89 void CFlowInternalContext::Start()
       
    90 	{
       
    91 	__ASSERT_DEBUG(iHead.iPacket.IsEmpty(), User::Panic(_L("iHead.iPacket not empty"), 0));
       
    92 
       
    93 	iStart = iHead;					// Just save a copy of the iHead.
       
    94 	iStart.iOffset = iHdrSize;		// Borrow the iOffset field to hold the initial header overhead
       
    95 	}
       
    96 
       
    97 //	*******************
       
    98 //	CFlowContext::Reset
       
    99 //	*******************
       
   100 //	Can be called any time to set the flow into initial state
       
   101 //	(called before hook Ready method calls)
       
   102 //
       
   103 void CFlowInternalContext::Reset()
       
   104 	{
       
   105 	iHead.iPacket.Free();
       
   106 	iHead = iStart;
       
   107 	//
       
   108 	// Reset the initial (after Open-phase) header overhead
       
   109 	//
       
   110 	iHdrSize = iHead.iOffset;
       
   111 	iHead.iOffset = 0;
       
   112 	}
       
   113 
       
   114 //
       
   115 //	CFlowContext::RefreshHooks
       
   116 //	**************************
       
   117 //	(Utility for derived classes)
       
   118 //	Call the Ready() methods of the registered hooks
       
   119 //	and check if all of them are ready. If so, the state
       
   120 //	of the flow will be EFlow_READY, otherwise the state
       
   121 //	will be the state of the first hook that reports
       
   122 //	not READY.
       
   123 //
       
   124 void CFlowInternalContext::RefreshHooks()
       
   125 	{
       
   126 	TInt err;
       
   127 	iStatus = EFlow_READY;
       
   128 	if (iHookList)
       
   129 		{
       
   130 		LOG(const MFlowHook *tmp = NULL);
       
   131 		TRAP(err,
       
   132 			for (TInt i = iHookList->Count(); iStatus == EFlow_READY && i > 0; )
       
   133 				{
       
   134 				TFlowHook &h = iHookList->At(--i);
       
   135 				iStatus = h.iHook.ReadyL(iHead);
       
   136 				LOG(tmp = &h.iHook);
       
   137 				// Compute fragmenting MTU, if fragmenting is requested
       
   138 				// (result is garbage if iFrag == KNoFrag, but it does not matter)
       
   139 				h.iMtu = (TUint16)(PathMtu() - HeaderSize() - h.iFrag);
       
   140 				}
       
   141 			); // TRAP
       
   142 		if (err != KErrNone)
       
   143 			{
       
   144 			LOG(Log::Printf(_L("\tMFlowHook[%u] ReadyL LEAVE WITH err=%d"), (TInt)tmp, err));
       
   145 			// *NOTE*
       
   146 			//		Must ensure that the status will be negative,
       
   147 			//		because positive values are interpreted as
       
   148 			//		"pending" signals and a later wakeup is
       
   149 			//		expected. It is doubtful that a hook leaves
       
   150 			//		unexpectedly and still has set for the wakeup!
       
   151 			//		... though, I suppose this should never
       
   152 			//		happen? Leave errors are always negative?
       
   153 			//		-- msa
       
   154 			//	Force KErrGeneral, if err is not negative!
       
   155 			iStatus = err < 0 ? err : KErrGeneral;
       
   156 			}
       
   157 		LOG(if (iStatus != EFlow_READY) Log::Printf(_L("\tMFlowHook[%u] ReadyL iStatus = %d"), (TInt)tmp, iStatus));
       
   158 		}
       
   159 	}
       
   160 
       
   161 //	CFlowInternalContext::ApplyHooksL
       
   162 // **********************************
       
   163 TInt CFlowInternalContext::ApplyHooksL(RMBufSendPacket &aPacket, RMBufSendInfo &aInfo)
       
   164 	{
       
   165 	const TInt n = iHookList->Count();
       
   166 	for (TInt i = 0; i < n; )
       
   167 		{
       
   168 		const TFlowHook &h = iHookList->At(i++);
       
   169 		if (h.iFrag != KNoFrag && aInfo.iLength > h.iMtu)
       
   170 			return --i;
       
   171 		
       
   172 		const TInt ret = h.iHook.ApplyL(aPacket, aInfo);
       
   173 		if (ret > 0)
       
   174 			{
       
   175 			LOG(Log::Printf(_L("\tMFlowHook[%u] ApplyL returns %d, restarat ApplyL (*deprecated feature used*)"), (TInt)&h.iHook, ret));
       
   176 			i = 0;			// Restart hooks.
       
   177 			}
       
   178 		else if (ret < 0)
       
   179 			{
       
   180 			LOG(Log::Printf(_L("\tMFlowHook[%u] ApplyL returns %d, packet thrown away"), (TInt)&h.iHook, ret));
       
   181 			User::Leave(ret);
       
   182 			}
       
   183 		else if (iHookList == NULL)
       
   184 			{
       
   185 			// Returned KErrNone, but the iHookList has disappeared
       
   186 			LOG(Log::Printf(_L("\tMFlowHook[%u] ApplyL disconnected the flow"), (TInt)&h.iHook));
       
   187 			User::Leave(KErrDisconnected);
       
   188 			}
       
   189 		}
       
   190 	return n;
       
   191 	}
       
   192 	
       
   193 void CFlowInternalContext::ApplyHooksFragmentedL(TInt aStart, RMBufSendPacket &aPacket)
       
   194 	{
       
   195 	RMBufSendInfo *info = aPacket.Unpack();
       
   196 	const TInt n = iHookList->Count();
       
   197 	for (TInt i = aStart; i < n; )
       
   198 		{
       
   199 		const TFlowHook &h = iHookList->At(i++);
       
   200 		const TInt ret = h.iHook.ApplyL(aPacket, *info);
       
   201 		if (ret > 0)
       
   202 			{
       
   203 			LOG(Log::Printf(_L("\tMFlowHook[%u] ApplyL (fragment) returns %d, restart ApplyL (*deprecated feature used*)"), (TInt)&h.iHook, ret));
       
   204 			i = 0;			// Restart hooks.
       
   205 			}
       
   206 		else if (ret < 0)
       
   207 			{
       
   208 			LOG(Log::Printf(_L("\tMFlowHook[%u] ApplyL (fragment) returns %d"), (TInt)&h.iHook, ret));
       
   209 			User::Leave(ret);
       
   210 			}
       
   211 		else if (iHookList == NULL)
       
   212 			{
       
   213 			// Returned KErrNone, but the iHookList has disappeared
       
   214 			LOG(Log::Printf(_L("\tMFlowHook[%u] ApplyL (fragment) disconnected the flow"), (TInt)&h.iHook));
       
   215 			User::Leave(KErrDisconnected);
       
   216 			}
       
   217 		}
       
   218 	aPacket.Pack();
       
   219 	}
       
   220 //
       
   221 //	CFlowContext::ApplyHooks
       
   222 //	************************
       
   223 //	Apply hooks on flow to the packet. This has only two possible
       
   224 //	returns
       
   225 //
       
   226 //	== KErrNone	- hooks applied successfully
       
   227 //	!= KErrNone - error occurred, packet has been released	
       
   228 //
       
   229 TInt CFlowInternalContext::ApplyHooks(RMBufSendPacket &aPacket, RMBufSendInfo &aInfo, RMBufPktQ &aFragments, MNetworkServiceExtension &aExt)
       
   230 	{
       
   231 	TInt ret = KErrNone;
       
   232 	if (iHookList)
       
   233 		{
       
   234 		TInt n = 0;
       
   235 		TRAPD(err, n = ApplyHooksL(aPacket, aInfo));
       
   236 		if (err != KErrNone)
       
   237 			{
       
   238 			// The ApplyL has left, free packet!
       
   239 			LOG(Log::Printf(_L("\tApplyHooks (ApplyL) dropping packet with reason %d"), err));
       
   240 			if (!aPacket.IsEmpty())
       
   241 				{
       
   242 				LOG(Log::Printf(_L("\tApplyHooks (ApplyL) packet is not empty, closing flow reference")));
       
   243 				aInfo.iFlow.Close();
       
   244 				}
       
   245 			aPacket.Free();
       
   246 			return err;
       
   247 			}
       
   248 		if (n < iHookList->Count())
       
   249 			{
       
   250 			// Packet too long for MTU and hook wants fragmenting
       
   251 			// done before it.
       
   252 			RMBufPktQ fragments;
       
   253 			if (aExt.Fragment(aPacket, aInfo, iHookList->At(n).iMtu, fragments))
       
   254 				{
       
   255 				TRAP(err,
       
   256 					while (fragments.Remove(aPacket))
       
   257 						{
       
   258 						ApplyHooksFragmentedL(n, aPacket);
       
   259 						aFragments.Append(aPacket);
       
   260 						}
       
   261 						);
       
   262 				ret = err;
       
   263 				}
       
   264 			aFragments.Append(fragments); // Just in case some was left there...
       
   265 			LOG(if (ret != KErrNone) Log::Printf(_L("\tApplyHooks (ApplyL fragments) returning %d"), err));
       
   266 			return ret;
       
   267 			}
       
   268 		}
       
   269 	if (aInfo.iLength > PathMtu() && !aExt.Fragment(aPacket, aInfo, PathMtu(), aFragments))
       
   270 		{
       
   271 		// Fragmentation required, but failed for some reason. The loopback ICMP has already been sent,
       
   272 		// Just return something != KErrNone for the caller to indicate that the aPacket has been
       
   273 		// processed (and should be empty at this point). 
       
   274 		ret = KErrNotSupported;
       
   275 		}
       
   276 	return ret;
       
   277 	}