networkprotocols/tcpipv4v6prt/src/tcp.cpp
changeset 0 af10295192d8
child 25 d15a50675083
child 53 7e41d162e158
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2006-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 // tcp.cpp - TCP protocol for IPv6/IPv4
       
    15 //
       
    16 
       
    17 #include "tcp.h"
       
    18 #include <icmp6_hdr.h>
       
    19 #include <ip4_hdr.h>
       
    20 #include "tcpip_ini.h"
       
    21 
       
    22 // Copied from ip6.cpp. Should move to some common definition file?
       
    23 static const TLitC8<sizeof(TInt)> KInetOptionDisable = {sizeof(TInt), {0}};
       
    24 
       
    25 //
       
    26 // TCP Protocol Description
       
    27 //
       
    28 
       
    29 void CProtocolTCP6::Describe(TServerProtocolDesc &aDesc)
       
    30 	{
       
    31 	aDesc.iName		  = _S("tcp");
       
    32 	aDesc.iAddrFamily	  = KAfInet;
       
    33 	aDesc.iSockType	  = KSockStream;
       
    34 	aDesc.iProtocol	  = KProtocolInetTcp;
       
    35 	aDesc.iVersion	  = TVersion(KInet6MajorVersionNumber,
       
    36 		KInet6MinorVersionNumber,
       
    37 		KInet6BuildVersionNumber);
       
    38 	aDesc.iByteOrder	  = EBigEndian;
       
    39 	aDesc.iServiceInfo	  = KSIStreamBased | KSIInOrder | KSIReliable |
       
    40 		KSIGracefulClose | KSIPeekData | KSIUrgentData |
       
    41 		KSIRequiresOwnerInfo;
       
    42 	aDesc.iNamingServices	  = KNSNameResolution | KNSRequiresConnectionStartup;
       
    43 	aDesc.iSecurity	  = KSocketNoSecurity;
       
    44 	aDesc.iMessageSize	  = KSocketMessageSizeIsStream;
       
    45 	aDesc.iServiceTypeInfo  = ESocketSupport | ETransport | EPreferMBufChains | ENeedMBufs | EUseCanSend;
       
    46 	aDesc.iNumSockets	  = KUnlimitedSockets;
       
    47 	}
       
    48 
       
    49 
       
    50 
       
    51 CProtocolTCP6::CProtocolTCP6()
       
    52 	{
       
    53 	__DECLARE_NAME(_S("CProtocolTCP6"));
       
    54 	}
       
    55 
       
    56 
       
    57 CProtocolTCP6::~CProtocolTCP6()
       
    58 	{
       
    59 	LOG(Log::Printf(_L("\ttcp Deleted")));
       
    60 	}
       
    61 
       
    62 CServProviderBase* CProtocolTCP6::NewSAPL(TUint aSockType)
       
    63 	{
       
    64 	LOG(Log::Printf(_L("NewSAPL\ttcp SockType=%d)"), aSockType));
       
    65 	if (aSockType!=KSockStream)
       
    66 		User::Leave(KErrNotSupported);
       
    67 	CProviderTCP6 *sap = new (ELeave) CProviderTCP6(this);
       
    68 	CleanupStack::PushL(sap);
       
    69 	sap->InitL();
       
    70 	CleanupStack::Pop();
       
    71 	LOG(Log::Printf(_L("NewSAPL\ttcp SAP[%u] OK"), (TInt)sap));
       
    72 	return sap;
       
    73 	}
       
    74 
       
    75 
       
    76 void CProtocolTCP6::InitL(TDesC& aTag)
       
    77 	{
       
    78 	CProtocolInet6Transport::InitL(aTag);
       
    79 
       
    80 	iRandomIncrement = 0;
       
    81 	UserHal::TickPeriod((TTimeIntervalMicroSeconds32&)iClockGranularity);
       
    82 	}
       
    83 
       
    84 
       
    85 void CProtocolTCP6::StartL()
       
    86 	{
       
    87 	CProtocolInet6Transport::StartL();
       
    88 
       
    89 	iMSS = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_MSS,
       
    90 			KTcpDefaultMSS, KTcpMinimumMSS, 65535, ETrue);
       
    91 
       
    92 	iRecvBuf = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RECV_BUF,
       
    93 			KTcpDefaultRcvWnd, KTcpMinimumWindow, KTcpMaximumWindow, ETrue); 
       
    94 	
       
    95 	iSendBuf = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_SEND_BUF,
       
    96 			KTcpDefaultSndWnd, KTcpMinimumWindow, KTcpMaximumWindow, ETrue);
       
    97 
       
    98 	// Argh: ini is in millisecs, but CProtocolTCP6 member is in microsecs.
       
    99 	iMinRTO = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_MIN_RTO,
       
   100 			KTcpMinRTO/1000, iClockGranularity/1000, KTcpMaxRTO/1000, ETrue) * 1000;
       
   101 
       
   102 	iMaxRTO = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_MAX_RTO,
       
   103 			KTcpMaxRTO/1000, iMinRTO/1000, KTcpMaxRTO/1000, ETrue) * 1000;
       
   104 
       
   105 	iInitialRTO = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_INITIAL_RTO,
       
   106 			KTcpInitialRTO/1000, iMinRTO/1000, iMaxRTO/1000, ETrue) * 1000;
       
   107 			
       
   108 	iSrttSmooth = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_SRTT_SMOOTH,
       
   109 			KTcpSrttSmooth, 1, KMaxTInt, ETrue);
       
   110 			
       
   111 	iMdevSmooth = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RTTVAR_SMOOTH,
       
   112 			KTcpMdevSmooth, 1, KMaxTInt, ETrue);
       
   113 
       
   114 	iRTO_K = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RTO_K,
       
   115 			KTcpRTO_K, 1, KMaxTInt, ETrue);
       
   116 
       
   117 	iRTO_G = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RTO_G,
       
   118 			iClockGranularity/1000, iClockGranularity/1000, KMaxTInt, ETrue) * 1000;
       
   119 
       
   120 	iMaxBurst = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_MAX_BURST,
       
   121 			KTcpMaxTransmit, 1, KMaxTInt, ETrue);
       
   122 
       
   123 	iAckDelay = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_ACK_DELAY,
       
   124 			KTcpAckDelay/1000, iClockGranularity/1000, KMaxTInt/1000, ETrue) * 1000;
       
   125 
       
   126 	iSynRetries = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_SYN_RETRIES,
       
   127 			KTcpSynRetries, 0, KMaxTInt, ETrue);
       
   128 
       
   129 	iRetries1 = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RETRIES1,
       
   130 			KTcpMaxRetries1, 0, KMaxTInt, ETrue);
       
   131 
       
   132 	iRetries2 = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RETRIES2,
       
   133 			KTcpMaxRetries2, iRetries1, KMaxTInt, ETrue);
       
   134 
       
   135 	iProbeStyle = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_PROBE_STYLE,	2, 0, 2, EFalse);
       
   136 
       
   137 	iMsl2Delay = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_MSL2,
       
   138 			KTcpMsl2Delay/1000, 1, KMaxTInt/1000, ETrue) * 1000;
       
   139 
       
   140 	iReordering = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_REORDERING,
       
   141 			KTcpReordering, 0, KMaxTInt, ETrue);
       
   142 
       
   143 	iInitialCwnd = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_INITIAL_CWND,
       
   144 			KTcpInitialCwnd, 0, KMaxTInt, ETrue);
       
   145 
       
   146 	iLtxWindow = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_LTX_WINDOW,
       
   147 			KTcpLtxWindow, 0, KMaxTInt, ETrue);
       
   148 
       
   149 	iKeepAliveIntv = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_KEEPALIVE_INTV,
       
   150 			KTcpKeepAliveIntv, 0, KMaxTInt, ETrue);
       
   151 
       
   152 	iNumKeepAlives = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_NUM_KEEPALIVES,
       
   153 			KTcpNumKeepAlives, 0, KMaxTInt, ETrue);
       
   154 
       
   155 	// keepalive retransmission timer cannot be longer than 30 min, because timers are in microseconds.
       
   156 	iKeepAliveRxmt = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_KEEPALIVE_RXMT,
       
   157 			KTcpKeepAliveRxmt, 0, 1800, ETrue);
       
   158 
       
   159 	iFinPersistency = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_FIN_PERSISTENCY,
       
   160 			KTcpFinPersistency, 0, iRetries2, ETrue);
       
   161 	
       
   162 	// ECN settings: 0 = disabled, 1 = enabled with ECT(1), 2 = enabled with ECT(0)
       
   163 	iEcn = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_ECN, 0, 0, 2, EFalse);
       
   164 
       
   165 	iSpuriousRtoResponse = GetIniValue(TCPIP_INI_TCP,
       
   166 			TCPIP_INI_TCP_SPURIOUS_RTO_RESPONSE, 1, 1, 3, EFalse);
       
   167 
       
   168 	iWinScale = (TInt8)GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_WINSCALE, 0, -1, 7, ETrue);
       
   169 
       
   170 	// Flags enabled by default
       
   171 	iTimeStamps = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_TIMESTAMPS, 1, 0, 1);
       
   172 	iSack = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_SACK, 1, 0, 1);
       
   173 	iRFC2414 = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RFC2414, 1, 0, 1);
       
   174 	iDSack = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_DSACK, 1, 0, 1);
       
   175 	iFRTO = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_FRTO, 1, 0, 1);
       
   176 
       
   177 	// Flags disabled by default
       
   178 	iLocalTimeWait = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_LOCAL_TIMEWAIT, 0, 0, 1);
       
   179 	iStrictNagle = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_STRICT_NAGLE, 0, 0, 1);
       
   180 	iPushAck = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_PUSH_ACK, 0, 0, 1);
       
   181 	iAlignOpt = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_ALIGNOPT, 0, 0, 1);
       
   182 
       
   183 	// Note: 'dstcache' is in [ip] section, because it is not necessarily TCP specific
       
   184 	iDstCache = GetIniValue(TCPIP_INI_IP, TCPIP_INI_DSTCACHE, 0, 0, 1);
       
   185 	
       
   186 #ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
       
   187 	iTcpMaxRecvWin = GetIniValue(TCPIP_INI_TCP, TCPIP_INI_TCP_RECV_MAX_WND,
       
   188 				KTcpDefaultRcvMaxWnd, KTcpMinimumWindow, KTcpMaximumWindow, ETrue);
       
   189 #endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
       
   190 	}
       
   191 
       
   192 
       
   193 void CProtocolTCP6::Identify(TServerProtocolDesc *aInfo) const
       
   194 	{
       
   195 	Describe(*aInfo);
       
   196 	}
       
   197 
       
   198 TInt CProtocolTCP6::Send(RMBufChain& aPacket,CProtocolBase* /*aSourceProtocol=NULL*/)
       
   199 	{
       
   200 #ifdef _LOGx
       
   201 	RMBufSendPacket seg;
       
   202 	seg.Assign(aPacket);
       
   203 	RMBufSendInfo *info = seg.Unpack();
       
   204 	LOG(LogPacket('>', seg, info));
       
   205 	seg.Pack();
       
   206 	aPacket.Assign(seg);
       
   207 #endif
       
   208 	return iNetwork->Send(aPacket);
       
   209 	}
       
   210 
       
   211 void CProtocolTCP6::Process(RMBufChain& aPacket, CProtocolBase* /*aSourceProtocol*/)
       
   212 	{
       
   213 	RMBufRecvPacket seg;
       
   214 	seg.Assign(aPacket);
       
   215 	//  RMBufRecvPacket& seg = (RMBufRecvPacket&)aPacket;
       
   216 	RMBufRecvInfo* info = seg.Unpack();
       
   217 
       
   218 #ifdef _LOG
       
   219 	TBuf<50> src, dst;
       
   220 	LOG(Log::Printf(_L("\ttcp Process(%d bytes)"), seg.Length()));
       
   221 #endif
       
   222 
       
   223 	ASSERT(info->iLength == seg.Length());
       
   224 
       
   225 	TTcpPacket pkt;
       
   226 	TInet6Packet<TInet6HeaderIP4> ip4;
       
   227 	TInet6Packet<TInet6HeaderIP>  ip6;
       
   228 	TInt err = KErrNone, errMask = MSocketNotify::EErrorAllOperations;
       
   229 	CProviderTCP6 *sap;
       
   230 	TInetAddr icmpSender;
       
   231 
       
   232 	switch (info->iIcmp)
       
   233 		{
       
   234 	case 0:
       
   235 
       
   236 		// Check source and destination addresses
       
   237 		if (!(TInetAddr::Cast(info->iDstAddr).IsUnicast() && TInetAddr::Cast(info->iSrcAddr).IsUnicast()))
       
   238 			{
       
   239 			LOG(Log::Printf(_L("\ttcpProcess() Invalid source or destination address. Packet discarded")));
       
   240 			seg.Free();
       
   241 			break;
       
   242 			}
       
   243 
       
   244 		pkt.Set(seg, info->iOffset, KTcpMinHeaderLength);
       
   245 
       
   246 		// Verify header length.
       
   247 		if (!pkt.iHdr || info->iLength < pkt.iHdr->HeaderLength())
       
   248 			{
       
   249 			LOG(Log::Printf(_L("\ttcp Process() Invalid header. Packet discarded")));
       
   250 			seg.Free();
       
   251 			return;
       
   252 			}
       
   253 
       
   254 		// Get port numbers from header
       
   255 		info->iSrcAddr.SetPort(pkt.iHdr->SrcPort());
       
   256 		info->iDstAddr.SetPort(pkt.iHdr->DstPort());
       
   257 
       
   258 #ifdef _LOG
       
   259 		LogPacket('<', seg, info, info->iOffset);
       
   260 		pkt.Set(seg, info->iOffset, pkt.iHdr->HeaderLength()); // LogPacket() may have realigned the header.
       
   261 #endif
       
   262 
       
   263 		// Verify TCP checksum
       
   264 		if (!pkt.VerifyChecksum(seg, info, info->iOffset))
       
   265 			{
       
   266 			LOG(Log::Printf(_L("\ttcp Process() Bad checksum. Packet discarded")));
       
   267 			seg.Free();
       
   268 			break;
       
   269 			}
       
   270 
       
   271 #ifdef _LOGx
       
   272 		TInetAddr(info->iSrcAddr).OutputWithScope(src); TInetAddr(info->iDstAddr).Output(dst);
       
   273 		LOG(Log::Printf(_L("\ttcp Process(%d bytes): {%S,%d} -> {%S,%d}"),
       
   274 			seg.Length(), &src, info->iSrcAddr.Port(), &dst, info->iDstAddr.Port()));
       
   275 #endif
       
   276 
       
   277 		// More sanity checking.
       
   278 		if (info->iSrcAddr.Port() == KInetPortNone ||
       
   279 			info->iDstAddr.Port() == KInetPortNone)
       
   280 			{
       
   281 			LOG(Log::Printf(_L("\ttcp Process() Illegal port number. Packet discarded")));
       
   282 			seg.Free();
       
   283 			break;
       
   284 			}
       
   285 
       
   286 		sap = (CProviderTCP6*)LocateSap(EMatchServerUnspecAddr,
       
   287 			info->iVersion == 4 ? KAfInet : KAfInet6,
       
   288 #ifndef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING
       
   289 			info->iDstAddr, info->iSrcAddr);
       
   290 #else
       
   291 			info->iDstAddr, info->iSrcAddr, NULL, info->iInterfaceIndex);
       
   292 #endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING
       
   293 		if (sap == NULL)
       
   294 			{
       
   295 			LOG(Log::Printf(_L("\ttcp Process() No socket. Packet discarded")));
       
   296 			if (!pkt.iHdr->RST())
       
   297 				{
       
   298 				//
       
   299 				// Send RST.
       
   300 				//
       
   301 				if (NetworkService()->Interfacer()->LocalScope(TInetAddr::Cast(info->iDstAddr).Ip6Address(),
       
   302 					info->iInterfaceIndex, EScopeType_IF))
       
   303 					{
       
   304 					if (pkt.iHdr->ACK())
       
   305 						{
       
   306 						SendControlSegment(NULL, info->iDstAddr, info->iSrcAddr, KTcpCtlRST,
       
   307 							pkt.iHdr->Acknowledgment(), 0);
       
   308 						}
       
   309 					else
       
   310 						{
       
   311 						//TTcpSeqNum seq = pkt.iHdr->Sequence() + aPacket.Length() - pkt.iHdr->HeaderLength();
       
   312 						TTcpSeqNum seq = pkt.iHdr->Sequence() + seg.Length() -
       
   313 							pkt.iHdr->HeaderLength() - info->iOffset;
       
   314 
       
   315 						// Adjust for SYN and FIN
       
   316 						if (pkt.iHdr->SYN() || pkt.iHdr->FIN())
       
   317 							seq++;
       
   318 
       
   319 						SendControlSegment(NULL, info->iDstAddr, info->iSrcAddr, KTcpCtlRST|KTcpCtlACK, 0, seq);
       
   320 						}
       
   321 					}
       
   322 				}
       
   323 			seg.Free();
       
   324 			break;
       
   325 			}
       
   326 
       
   327 		// Bump it to the SAP.
       
   328 		seg.Pack();
       
   329 		sap->Process(seg);
       
   330 		break;
       
   331 
       
   332 	case KProtocolInetIcmp:
       
   333 	case KProtocolInet6Icmp:
       
   334 
       
   335         /* From RFC1122:
       
   336         4.2.3.9  ICMP Messages
       
   337  
       
   338             TCP MUST act on an ICMP error message passed up from the IP
       
   339             layer, directing it to the connection that created the
       
   340             error.  The necessary demultiplexing information can be
       
   341             found in the IP header contained within the ICMP message.
       
   342  
       
   343             o    Source Quench
       
   344  
       
   345                  TCP MUST react to a Source Quench by slowing
       
   346                  transmission on the connection.  The RECOMMENDED
       
   347                  procedure is for a Source Quench to trigger a "slow
       
   348                  start," as if a retransmission timeout had occurred.
       
   349  
       
   350             o    Destination Unreachable -- codes 0, 1, 5
       
   351  
       
   352                  Since these Unreachable messages indicate soft error
       
   353                  conditions, TCP MUST NOT abort the connection, and it
       
   354                  SHOULD make the information available to the
       
   355                  application.
       
   356  
       
   357                  DISCUSSION:
       
   358                       TCP could report the soft error condition directly
       
   359                       to the application layer with an upcall to the
       
   360                       ERROR_REPORT routine, or it could merely note the
       
   361                       message and report it to the application only when
       
   362                       and if the TCP connection times out.
       
   363  
       
   364             o    Destination Unreachable -- codes 2-4
       
   365  
       
   366                  These are hard error conditions, so TCP SHOULD abort
       
   367                  the connection.
       
   368  
       
   369             o    Time Exceeded -- codes 0, 1
       
   370  
       
   371                  This should be handled the same way as Destination
       
   372                  Unreachable codes 0, 1, 5 (see above).
       
   373  
       
   374             o    Parameter Problem
       
   375  
       
   376                  This should be handled the same way as Destination
       
   377 		Unreachable codes 0, 1, 5 (see above).*/
       
   378 
       
   379 		//
       
   380 		// Map the first 8 bytes of TCP segment header
       
   381 		// (8 bytes is all there is in an ICMPv4 packet)
       
   382 		//
       
   383 		// WARNING!!!   Any attempt to access fields other than
       
   384 		//              SrcPort, DstPort, or Sequence WILL CAUSE
       
   385 		//              BAD THINGS TO HAPPEN!
       
   386 		//
       
   387 		//
       
   388 		pkt.Set(seg, info->iOffset, 8);
       
   389 		if (!pkt.iHdr)
       
   390 			{
       
   391 			LOG(Log::Printf(_L("\ttcp Process() Invalid TCP header in ICMP")));
       
   392 			seg.Free();
       
   393 			break;
       
   394 			}
       
   395 
       
   396 		// Get port numbers from header
       
   397 		info->iSrcAddr.SetPort(pkt.iHdr->SrcPort());
       
   398 		info->iDstAddr.SetPort(pkt.iHdr->DstPort());
       
   399 
       
   400 #ifdef _LOG
       
   401 		TInetAddr(info->iSrcAddr).OutputWithScope(src); TInetAddr(info->iDstAddr).OutputWithScope(dst);
       
   402 		LOG(Log::Printf(_L("\ttcp Process() ICMP reply to TCP segment {%S,%d} -> {%S,%d}"),
       
   403 			&src, info->iSrcAddr.Port(), &dst, info->iDstAddr.Port()));
       
   404 		LOG(Log::Printf(_L("\ttcp Process() ICMP type=%d code=%d param=%d received"),
       
   405 			info->iType, info->iCode, info->iParameter));
       
   406 #endif
       
   407 
       
   408 		sap = (CProviderTCP6*)LocateSap(EMatchServerUnspecAddr,
       
   409 			info->iVersion == 4 ? KAfInet : KAfInet6,
       
   410 			info->iSrcAddr, info->iDstAddr);
       
   411 		if (sap == NULL)
       
   412 			{
       
   413 			LOG(Log::Printf(_L("\ttcp Process() No socket. Discarding ICMP message")));
       
   414 			seg.Free();
       
   415 			break;
       
   416 			}
       
   417 
       
   418 		if (info->iIcmp == KProtocolInetIcmp)
       
   419 			{
       
   420 			//
       
   421 			// ICMPv4 message processing
       
   422 			//
       
   423 			ip4.Set(seg, 0, TInet6HeaderIP4::MinHeaderLength());
       
   424 			if (!ip4.iHdr)
       
   425 				{
       
   426 				LOG(Log::Printf(_L("\ttcp SAP[%u] Invalid IPv4 header in ICMP"), (TInt)sap));
       
   427 				seg.Free();
       
   428 				break;
       
   429 				}
       
   430 			icmpSender.SetAddress(ip4.iHdr->SrcAddr());
       
   431 			switch (info->iType)
       
   432 				{
       
   433 			case KInet4ICMP_Unreachable:
       
   434 /*
       
   435    Code           0 = net unreachable
       
   436                   1 = host unreachable
       
   437                   2 = protocol unreachable
       
   438                   3 = port unreachable
       
   439                   4 = fragmentation needed and DF set
       
   440                   5 = source route failed
       
   441                   6 = destination network unknown
       
   442                   7 = destination host unknown
       
   443                   8 = source host isolated
       
   444                   9 = communication with destination network administratively prohibited
       
   445                  10 = communication with destination host administratively prohibited
       
   446                  11 = network unreachable for type of service
       
   447                  12 = host unreachable for type of service
       
   448 				*/
       
   449 				switch (info->iCode)
       
   450 					{
       
   451 				case 2:
       
   452 					err = KErrNoProtocolOpt;
       
   453 					break;
       
   454 
       
   455 				case 3:
       
   456 					err = KErrCouldNotConnect;
       
   457 					break;
       
   458 
       
   459 				case 0:                          // Transient condition
       
   460 					errMask = 0;
       
   461 					// Fall through
       
   462 
       
   463 				case 5: case 6: case 8: case 9:  // Persistent conditions
       
   464 					err = KErrNetUnreach;
       
   465 					break;
       
   466 
       
   467 				case 1:                          // Transient condition
       
   468 					errMask = 0;
       
   469 					// Fall through
       
   470 
       
   471 				case 7: case 10: case 12:        // Persistent conditions
       
   472 					err = KErrHostUnreach;
       
   473 					break;
       
   474 
       
   475 				default:
       
   476 					break;
       
   477 					}
       
   478 				break;
       
   479 
       
   480 			case KInet4ICMP_SourceQuench:        // Do a slow start
       
   481 				sap->SourceQuench();
       
   482 				break;
       
   483 
       
   484 			case KInet4ICMP_TimeExceeded:
       
   485 				err = KErrNetUnreach;
       
   486 				errMask = 0;
       
   487 				break;
       
   488 
       
   489 			case KInet4ICMP_ParameterProblem:
       
   490 				err = KErrArgument;
       
   491 				errMask = 0;
       
   492 				break;
       
   493 
       
   494 			default:
       
   495 				break;
       
   496 				}
       
   497 			}
       
   498 		else
       
   499 			{
       
   500 			//
       
   501 			// ICMPv6 message processing
       
   502 			//
       
   503 			ip6.Set(seg, 0, TInet6HeaderIP::MinHeaderLength());
       
   504 			if (!ip6.iHdr)
       
   505 				{
       
   506 				LOG(Log::Printf(_L("\ttcp SAP[%u] Invalid IPv6 header in ICMP"), (TInt)sap));
       
   507 				seg.Free();
       
   508 				break;
       
   509 				}
       
   510 			icmpSender.SetAddress(ip6.iHdr->SrcAddr());
       
   511 			switch (info->iType)
       
   512 				{
       
   513 			case KInet6ICMP_Unreachable:
       
   514 /*
       
   515    Code           0 - no route to destination
       
   516                   1 - communication with destination
       
   517                         administratively prohibited
       
   518                   2 - (not assigned)
       
   519                   3 - address unreachable
       
   520                   4 - port unreachable
       
   521 				*/
       
   522 				switch (info->iCode)
       
   523 					{
       
   524 				case 3:
       
   525 					err = KErrHostUnreach;
       
   526 					break;
       
   527 
       
   528 				case 4:
       
   529 					err = KErrCouldNotConnect;
       
   530 					break;
       
   531 
       
   532 				default:
       
   533 					err = KErrNetUnreach;
       
   534 					break;
       
   535 					}
       
   536 				break;
       
   537 
       
   538 			case KInet6ICMP_PacketTooBig:
       
   539 				//
       
   540 				// Treat this as a soft error. The flow should
       
   541 				// automatically adjust to changes in path MTU.
       
   542 				//
       
   543 				err = KErrTooBig;
       
   544 				errMask = 0;
       
   545 				break;
       
   546 
       
   547 			case KInet6ICMP_TimeExceeded:
       
   548 /*
       
   549    Code           0 - hop limit exceeded in transit
       
   550                   1 - fragment reassembly time exceeded
       
   551 				*/
       
   552 				err = KErrNetUnreach;
       
   553 				errMask = 0;
       
   554 				break;
       
   555 
       
   556 			case KInet6ICMP_ParameterProblem:
       
   557 /*
       
   558    Code           0 - erroneous header field encountered
       
   559                   1 - unrecognized Next Header type encountered
       
   560                   2 - unrecognized IPv6 option encountered
       
   561 				*/
       
   562 				err = KErrArgument;
       
   563 				errMask = 0;
       
   564 				break;
       
   565 
       
   566 			default:
       
   567 				break;
       
   568 				}
       
   569 			}
       
   570 
       
   571 		if (err != KErrNone)
       
   572 			{
       
   573 			//
       
   574 			// TCP only treats ICMP errors as hard errors if it's
       
   575 			// setting up a new connection. We make ICMP spoofing
       
   576 			// a little bit more difficult by checking the included
       
   577 			// TCP sequence number. If the sequence number does not
       
   578 			// match, we change the error to a soft error.
       
   579 			//
       
   580 			if (errMask && pkt.iHdr->Sequence() != sap->iSND.UNA)
       
   581 				{
       
   582 				LOG(Log::Printf(_L("\ttcp SAP[%u] TCP sequence mismatch. Converting to soft error"), (TInt)sap));
       
   583 				errMask = 0;
       
   584 				}
       
   585 
       
   586 			LOG(Log::Printf(_L("\ttcp SAP[%u] Reporting ICMP error %d, mask %d.\r\n"), (TInt)sap, err, errMask));
       
   587 			}
       
   588 
       
   589 		// Store and report
       
   590 		sap->IcmpError(err, errMask,
       
   591 			info->iType, info->iCode,
       
   592 			TInetAddr::Cast(info->iSrcAddr),
       
   593 			TInetAddr::Cast(info->iDstAddr),
       
   594 			TInetAddr::Cast(icmpSender));
       
   595 		seg.Free();
       
   596 		break;
       
   597 
       
   598 	default:
       
   599 		break;
       
   600 		}
       
   601 	}
       
   602 
       
   603 
       
   604 //
       
   605 // This routine generates and transmits a TCP control segment.
       
   606 //
       
   607 TInt CProtocolTCP6::SendControlSegment(RFlowContext *aFlow,
       
   608 	const TSockAddr& aSrcAddr, const TSockAddr& aDstAddr,
       
   609 	TUint8 aFlags, TTcpSeqNum aSeq, TTcpSeqNum aAck,
       
   610 	TUint32 aWnd, TUint32 aUP)
       
   611 	{
       
   612 	LOG(Log::Printf(_L("\ttcp SendControlSegment")));
       
   613 
       
   614 	RMBufSendPacket seg;
       
   615 	RMBufSendInfo *info = NULL;
       
   616 	TInt err;
       
   617 
       
   618 	// Reserve space for IP+TCP headers and info.
       
   619 	err = seg.Alloc(TInet6HeaderIP::MaxHeaderLength() + KTcpMinHeaderLength, iBufAllocator);
       
   620 	if (err != KErrNone)
       
   621 		return err;
       
   622 	info = seg.NewInfo();
       
   623 	if (!info)
       
   624 		{
       
   625 		seg.Free();
       
   626 		return KErrNoMBufs;
       
   627 		}
       
   628 
       
   629 	// Leave space for the IP header.
       
   630 	seg.TrimStart(TInet6HeaderIP::MaxHeaderLength());
       
   631 
       
   632 	// Fill in info struct
       
   633 	info->iProtocol = KProtocolInetTcp;
       
   634 	info->iSrcAddr = aSrcAddr;
       
   635 	info->iDstAddr = aDstAddr;
       
   636 	info->iLength = KTcpMinHeaderLength;
       
   637 
       
   638 	// Open flow context
       
   639 	if (aFlow != NULL && aFlow->IsOpen())
       
   640 		{
       
   641 		err = info->iFlow.Open(*aFlow, info);
       
   642 		}
       
   643 	else
       
   644 		{
       
   645 		if ((err = info->iFlow.Open(NetworkService(), info->iDstAddr, info->iSrcAddr, info->iProtocol))
       
   646 				== KErrNone)
       
   647 			{
       
   648 			info->iFlow.FlowContext()->SetOption(KSolInetIp, KSoKeepInterfaceUp, KInetOptionDisable);
       
   649 			}
       
   650 		}
       
   651 
       
   652 	if (err != KErrNone)
       
   653 		{
       
   654 		// If at first you don't succeed... Well, life is sometimes unforgiving.
       
   655 		info->iFlow.Close();
       
   656 		seg.Free();
       
   657 		return err;
       
   658 		}
       
   659 
       
   660 	//
       
   661 	// Fill in TCP header. Note that the header length has already
       
   662 	// been set and the checksum will be calculated later.
       
   663 	//
       
   664 	TTcpPacket pkt(seg);
       
   665 	pkt.iHdr->SetHeaderLength(KTcpMinHeaderLength);
       
   666 	pkt.iHdr->SetSrcPort(info->iSrcAddr.Port());
       
   667 	pkt.iHdr->SetDstPort(info->iDstAddr.Port());
       
   668 	pkt.iHdr->SetSequence(aSeq);
       
   669 	pkt.iHdr->SetAcknowledgment(aAck);
       
   670 	pkt.iHdr->SetControl(aFlags);
       
   671 	pkt.iHdr->SetWindow(aWnd);
       
   672 	pkt.iHdr->SetUrgent(aUP);
       
   673 
       
   674 	ASSERT(info->iLength == seg.Length());
       
   675 
       
   676 	//
       
   677 	// Compute checksum and send the segment.
       
   678 	//
       
   679 	pkt.ComputeChecksum(seg, info);
       
   680 	LOG(LogPacket('>', seg, info));
       
   681 	seg.Pack();
       
   682 	Send(seg);
       
   683 
       
   684 	return KErrNone;
       
   685 	}
       
   686 
       
   687 
       
   688 TUint32 CProtocolTCP6::RandomSequence()
       
   689 	{
       
   690 	iRandomIncrement += Random(1000000);
       
   691 	return ((User::TickCount() * iClockGranularity) >> 2) + iRandomIncrement;
       
   692 	}
       
   693 
       
   694 
       
   695 #ifdef _LOG
       
   696 void CProtocolTCP6::LogPacket(char aDir, RMBufChain& aPacket, RMBufPktInfo *info, TInt aOffset)
       
   697 	{
       
   698 	RMBufPacketBase pkt;
       
   699 	pkt.Assign(aPacket);
       
   700 	TBool packed = EFalse;
       
   701 
       
   702 	if (info == NULL)
       
   703 		{
       
   704 		info = pkt.Unpack();
       
   705 		packed = ETrue;
       
   706 		}
       
   707 
       
   708 	TBuf<0x100> output;
       
   709 	TBuf<50> src, dst;
       
   710 	TTcpPacket seg(pkt, aOffset);
       
   711 	TTcpSeqNum seq = seg.iHdr->Sequence();
       
   712 	TUint32 len = info->iLength - seg.iHdr->HeaderLength() - aOffset;
       
   713 	TTcpOptions opt;
       
   714 	TTime now;
       
   715 	now.UniversalTime();
       
   716 #ifdef I64LOW
       
   717 	TUint32 usec = I64LOW(now.Int64());
       
   718 #else
       
   719 	TUint32 usec = now.Int64().GetTInt();
       
   720 #endif
       
   721 
       
   722 	TInetAddr(info->iSrcAddr).OutputWithScope(src);
       
   723 	TInetAddr(info->iDstAddr).OutputWithScope(dst);
       
   724 
       
   725 	output.Format(_L("\t%6u.%03u "),
       
   726 		usec / 1000000, (usec / 1000) % 1000);
       
   727 
       
   728 	if (aDir == '>')
       
   729 		output.AppendFormat(_L("%S.%u > %S.%u"),
       
   730 		&src, info->iSrcAddr.Port(), &dst, info->iDstAddr.Port());
       
   731 	else
       
   732 		output.AppendFormat(_L("%S.%u < %S.%u"),
       
   733 		&dst, info->iDstAddr.Port(), &src, info->iSrcAddr.Port());
       
   734 
       
   735 	_LIT(KHdrSyn, "S");
       
   736 	_LIT(KHdrFin, "F");
       
   737 	_LIT(KHdrPsh, "P");
       
   738 	_LIT(KHdrRst, "R");
       
   739 	_LIT(KHdrEce, "E");
       
   740 	_LIT(KHdrCwr, "W");
       
   741 	_LIT(KHdrDot, ".");
       
   742 	_LIT(KHdrNot, "");
       
   743 
       
   744 	output.AppendFormat(_L(" %S%S%S%S%S%S%S %u:%u(%u) wnd=%u"),
       
   745 		seg.iHdr->SYN() ? &KHdrSyn : &KHdrNot,
       
   746 		seg.iHdr->FIN() ? &KHdrFin : &KHdrNot,
       
   747 		seg.iHdr->PSH() ? &KHdrPsh : &KHdrNot,
       
   748 		seg.iHdr->RST() ? &KHdrRst : &KHdrNot,
       
   749 		seg.iHdr->ECE() ? &KHdrEce : &KHdrNot,
       
   750 		seg.iHdr->CWR() ? &KHdrCwr : &KHdrNot,
       
   751 		!(seg.iHdr->Control() & ~KTcpCtlACK) ? &KHdrDot : &KHdrNot,
       
   752 		seq.Uint32(), (seq+len).Uint32(), len, seg.iHdr->Window());
       
   753 
       
   754 	if (seg.iHdr->ACK())
       
   755 		output.AppendFormat(_L(" ack=%u"), (seg.iHdr->Acknowledgment()).Uint32() );
       
   756 
       
   757 	if (seg.iHdr->URG())
       
   758 		output.AppendFormat(_L(" urg=%u"), seg.iHdr->Urgent());
       
   759 
       
   760 //	output.AppendFormat(_L("\r\n"));
       
   761 	Log::Write(output);
       
   762 
       
   763 	if (seg.iHdr->Options(opt) && opt.Length() > 0)
       
   764 		{
       
   765 		TUint32 tsVal, tsEcr;
       
   766 		TInt blockCount = opt.SackBlocks().Count();
       
   767 		output.Format(_L("\t  options ["));
       
   768 		if (opt.MSS() >= 0)
       
   769 			output.AppendFormat(_L(" MSS=%u"), opt.MSS());
       
   770 		if (opt.SackOk())
       
   771 			output.AppendFormat(_L(" SackOk"));
       
   772 		if (opt.TimeStamps(tsVal, tsEcr))
       
   773 			output.AppendFormat(_L(" TS=%u,%u"), tsVal, tsEcr);
       
   774 		if (opt.WindowScale())
       
   775 			output.AppendFormat(_L(" WS=%d"), opt.WindowScale()-1);
       
   776 			
       
   777 		if (blockCount)
       
   778 			{
       
   779 			SequenceBlockQueueIter iter(opt.SackBlocks());
       
   780 			SequenceBlock *block;
       
   781 
       
   782 			output.Append(_L(" SACK="));
       
   783 			iter.SetToFirst();
       
   784 			while (block = iter++, block != NULL)
       
   785 				output.AppendFormat(_L("%u-%u%s"),
       
   786 				(block->iLeft).Uint32(),
       
   787 				(block->iRight).Uint32(), --blockCount ? "," : "");
       
   788 			}
       
   789 		output.AppendFormat(_L(" ]"));
       
   790 		Log::Write(output);
       
   791 		}
       
   792 
       
   793 	if (packed)
       
   794 		pkt.Pack();
       
   795 
       
   796 	aPacket.Assign(pkt);
       
   797 	}
       
   798 #endif
       
   799