networkprotocols/tcpipv4v6prt/src/udp.cpp
changeset 0 af10295192d8
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 // udp.cpp - UDP protocol for IPv6/IPv4
       
    15 //
       
    16 
       
    17 #include "udp.h"
       
    18 #include <icmp6_hdr.h>
       
    19 #include <ip4_hdr.h>
       
    20 #include <in6_if.h>
       
    21 #include "tcpip_ini.h"
       
    22 #include "inet6log.h"
       
    23 
       
    24 #define SYMBIAN_NETWORKING_UPS
       
    25 
       
    26 //
       
    27 // UDP Protocol Description
       
    28 //
       
    29 
       
    30 void CProtocolUDP6::Describe(TServerProtocolDesc &aDesc)
       
    31 	{
       
    32 	aDesc.iName		  = _S("udp");
       
    33 	aDesc.iAddrFamily	  = KAfInet;
       
    34 	aDesc.iSockType	  = KSockDatagram;
       
    35 	aDesc.iProtocol	  = KProtocolInetUdp;
       
    36 	aDesc.iVersion	  = TVersion(KInet6MajorVersionNumber,
       
    37 								KInet6MinorVersionNumber,
       
    38 								KInet6BuildVersionNumber);
       
    39 	aDesc.iByteOrder	  = EBigEndian;
       
    40 	aDesc.iServiceInfo	  = KSIConnectionLess | KSIDatagram |
       
    41 							KSIGracefulClose | KSIPeekData |
       
    42 							KSIRequiresOwnerInfo;
       
    43 	aDesc.iNamingServices	  = KNSNameResolution | KNSRequiresConnectionStartup;
       
    44 	aDesc.iSecurity	  = KSocketNoSecurity;
       
    45 	aDesc.iMessageSize	  = 65536-128; /*KSocketMessageSizeUndefined;*/
       
    46 	aDesc.iServiceTypeInfo  = ESocketSupport | ETransport |
       
    47 							EPreferMBufChains | ENeedMBufs |
       
    48 							EUseCanSend;
       
    49 	aDesc.iNumSockets	  = KUnlimitedSockets;
       
    50 	}
       
    51 
       
    52 
       
    53 
       
    54 CProtocolUDP6::CProtocolUDP6()
       
    55 	{
       
    56 	__DECLARE_NAME(_S("CProtocolUDP6"));
       
    57 	}
       
    58 
       
    59 
       
    60 CProtocolUDP6::~CProtocolUDP6()
       
    61 	{
       
    62 	}
       
    63 
       
    64 
       
    65 CServProviderBase* CProtocolUDP6::NewSAPL(TUint aSockType)
       
    66 	{
       
    67 	LOG(Log::Printf(_L("NewSAPL\tudp SockType=%d"), aSockType));
       
    68 	if (aSockType!=KSockDatagram)
       
    69 		User::Leave(KErrNotSupported);
       
    70 	CProviderUDP6 *sap = new (ELeave) CProviderUDP6(this);
       
    71 	CleanupStack::PushL(sap);
       
    72 	sap->InitL();
       
    73 	CleanupStack::Pop();
       
    74 	LOG(Log::Printf(_L("NewSAPL\tudp SAP[%u] OK"), (TUint)sap));
       
    75 	return sap;
       
    76 	}
       
    77 
       
    78 void CProtocolUDP6::InitL(TDesC& aTag)
       
    79 	{
       
    80 	CProtocolInet6Transport::InitL(aTag);
       
    81 	}
       
    82 
       
    83 
       
    84 void CProtocolUDP6::StartL()
       
    85 	{
       
    86 	CProtocolInet6Transport::StartL();
       
    87 
       
    88 	iRecvBuf = GetIniValue(TCPIP_INI_UDP, TCPIP_INI_UDP_RECV_BUF, KUdpDefaultRecvBuf, 1, KMaxTInt);
       
    89 
       
    90 	// Flags on by default
       
    91 	iWaitNif = GetIniValue(TCPIP_INI_UDP, TCPIP_INI_UDP_WAIT_NIF, 1, 0, 1);
       
    92 	}
       
    93 
       
    94 
       
    95 void CProtocolUDP6::Identify(TServerProtocolDesc *aInfo) const
       
    96 	{
       
    97 	Describe(*aInfo);
       
    98 	}
       
    99 
       
   100 TInt CProtocolUDP6::Send(RMBufChain& aPacket,CProtocolBase* /*aSourceProtocol=NULL*/)
       
   101 	{
       
   102 	LOG(Log::Printf(_L("\tudp Send(%d bytes)"), RMBufSendPacket::PeekInfoInChain(aPacket)->iLength));
       
   103 	return iNetwork->Send(aPacket);
       
   104 	}
       
   105 
       
   106 
       
   107 void CProtocolUDP6::Process(RMBufChain& aPacket, CProtocolBase* /*aSourceProtocol*/)
       
   108 	{
       
   109 	RMBufRecvPacket datagram;
       
   110 	datagram.Assign(aPacket);
       
   111 	RMBufRecvInfo* info = datagram.Unpack();
       
   112 	TInet6PacketUDP pkt(datagram, info->iOffset);
       
   113 	TInet6Packet<TInet6HeaderIP4> ip4;
       
   114 	TInet6Packet<TInet6HeaderIP>  ip6;
       
   115 	TInt err = KErrNone;
       
   116 	TInt version(0);
       
   117 	
       
   118 	CProviderUDP6 *sap = NULL;
       
   119 	TInetAddr icmpSender;
       
   120 
       
   121 #ifdef _LOG
       
   122 	TBuf<50> src, dst;
       
   123 	LOG(Log::Printf(_L("\tudp Process(%d bytes)"), datagram.Length()));
       
   124 #endif
       
   125 
       
   126 	ASSERT(info->iLength == datagram.Length());
       
   127 
       
   128 	//
       
   129 	// Preliminary checking for both UDP and ICMP
       
   130 	//
       
   131 	switch (info->iProtocol)
       
   132 		{
       
   133 	case KProtocolInetUdp:
       
   134 		// Sanity checking
       
   135 		if (!pkt.iHdr)
       
   136 			{
       
   137 			LOG(Log::Printf(_L("\tudp Process() Runt packet discarded")));
       
   138 			datagram.Free();
       
   139 			return;
       
   140 			}
       
   141 
       
   142 #ifdef _LOGx
       
   143 		TInetAddr(info->iSrcAddr).OutputWithScope(src); TInetAddr(info->iDstAddr).OutputWithScope(dst);
       
   144 		LOG(Log::Printf(_L("\tudp Process(%d bytes) {%S,%d} -> {%S,%d}"),
       
   145 			datagram.Length(), &src, pkt.iHdr->SrcPort(), &dst, pkt.iHdr->DstPort()));
       
   146 #endif
       
   147 
       
   148 		// More sanity checking.
       
   149 		if (pkt.iHdr->SrcPort() == KInetPortNone || pkt.iHdr->DstPort() == KInetPortNone)
       
   150 			{
       
   151 			LOG(Log::Printf(_L("\tudp Process() Zero port. Packet discarded.")));
       
   152 			datagram.Free();
       
   153 			return;
       
   154 			}
       
   155 		break;
       
   156 
       
   157 	default:
       
   158 		LOG(Log::Printf(_L("\tudp Process() Unknown protocol. Packet discarded.")));
       
   159 		datagram.Free();
       
   160 		return;
       
   161 		}
       
   162 
       
   163 	switch (info->iIcmp)
       
   164 		{
       
   165 	case 0:
       
   166 
       
   167 		// Check source address
       
   168 		if (!TInetAddr::Cast(info->iSrcAddr).IsUnicast() && !TInetAddr::Cast(info->iSrcAddr).IsUnspecified())
       
   169 			{
       
   170 			LOG(Log::Printf(_L("\tudp Process() Invalid source address. Packet discarded.")));
       
   171 			datagram.Free();
       
   172 			break;
       
   173 			}
       
   174 
       
   175 		// Sanity checking
       
   176 		if (info->iLength != info->iOffset + pkt.iHdr->Length())
       
   177 			{
       
   178 			LOG(Log::Printf(_L("\tudp Process() Size mismatch. Packet discarded.")));
       
   179 			datagram.Free();
       
   180 			break;
       
   181 			}
       
   182 
       
   183 		// Process UDP checksum. Check for no checksum (legal in UDP/IPv4)
       
   184 		if (pkt.iHdr->Checksum() ? !pkt.VerifyChecksum(datagram, info, info->iOffset) : info->iVersion != 4)
       
   185 			{
       
   186 			LOG(Log::Printf(_L("\tudp Process() Bad checksum. Packet discarded.")));
       
   187 			datagram.Free();
       
   188 			return;
       
   189 			}
       
   190 
       
   191 		//LOG(Log::Printf(_L("Verified UDP checksum %04x."), pkt.iHdr->Checksum()));
       
   192 
       
   193 		// Get port numbers from header
       
   194 		info->iSrcAddr.SetPort(pkt.iHdr->SrcPort());
       
   195 		info->iDstAddr.SetPort(pkt.iHdr->DstPort());
       
   196 
       
   197 #ifdef _LOG
       
   198 		TInetAddr(info->iSrcAddr).OutputWithScope(src); TInetAddr(info->iDstAddr).OutputWithScope(dst);
       
   199 		LOG(Log::Printf(_L("\tudp Process() UDP datagram {%S,%d} -> {%S,%d}"),
       
   200 			&src, info->iSrcAddr.Port(), &dst, info->iDstAddr.Port()));
       
   201 #endif
       
   202 
       
   203 		// Advance iOffset over the UDP header
       
   204 		info->iOffset += pkt.iHdr->HeaderLength();
       
   205 
       
   206 		//
       
   207 		// Replicate packets to all receivers.
       
   208 		// If there is only a single receiver,
       
   209 		// no extra packet copies will be made.
       
   210 		//
       
   211 		CProviderUDP6 *s;
       
   212 		version = info->iVersion == 4 ? KAfInet : KAfInet6;
       
   213 
       
   214 		// Locate hash bucket and traverse hash chain
       
   215 		s = (CProviderUDP6*)CProtocolInet6Base::LocateProvider(info->iDstAddr.Port());
       
   216 		// Locate best match if exists
       
   217 	    if (s)
       
   218 	    	{
       
   219 	    	if (!s->iNextSAP) // only one possible receiver in hash entry
       
   220 	    		{
       
   221 				// Locate best match
       
   222 #ifndef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING
       
   223 				sap = (CProviderUDP6*)LocateSap(EMatchServerUnspecAddr,
       
   224 					version, info->iDstAddr, info->iSrcAddr, s);	    		
       
   225 #else
       
   226 				sap = (CProviderUDP6*)LocateSap(EMatchServerUnspecAddr,
       
   227 					version, info->iDstAddr, info->iSrcAddr, s,info->iInterfaceIndex);	    		
       
   228 #endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING
       
   229 	    		}
       
   230 	    	else // Multiple possible receivers in hash entry
       
   231 	    		{
       
   232 #ifndef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING
       
   233 				sap = (CProviderUDP6*)LocateSap(EMatchServerSpecAddr, //Since this is UDP we are only interested in the dst Ip addr
       
   234 					version, info->iDstAddr, info->iSrcAddr, s);
       
   235 #else
       
   236 				sap = (CProviderUDP6*)LocateSap(EMatchServerSpecAddr, //Since this is UDP we are only interested in the dst Ip addr
       
   237 					version, info->iDstAddr, info->iSrcAddr, s,info->iInterfaceIndex);
       
   238 #endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING
       
   239 			
       
   240 				if (!sap) // no explicit connections
       
   241 					{
       
   242 					for (; s != NULL; s = (CProviderUDP6*)s->iNextSAP)
       
   243 						{
       
   244 						// Locate next match
       
   245 #ifndef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING
       
   246 						s = (CProviderUDP6*)LocateSap(EMatchServerUnspecAddr,
       
   247 							version, info->iDstAddr, info->iSrcAddr, s);
       
   248 #else
       
   249 						s = (CProviderUDP6*)LocateSap(EMatchServerUnspecAddr,
       
   250 							version, info->iDstAddr, info->iSrcAddr, s,info->iInterfaceIndex);
       
   251 #endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING
       
   252 						// No match?
       
   253 						if (s == NULL)
       
   254 							break;
       
   255 
       
   256 #ifdef SYMBIAN_NETWORKING_UPS
       
   257 						if (!s->HasNetworkServices() && (!s->ConnectionInfoSet())&& (info->iFlags & KIpLoopbackPacket) == 0)
       
   258 #else
       
   259 						if (!s->HasNetworkServices() && (info->iFlags & KIpLoopbackPacket) == 0)
       
   260 #endif
       
   261 							{
       
   262 							LOG(Log::Printf(_L("\tudp SAP[%u] Not allowed to receive external packets"), (TInt)s));
       
   263 							continue;
       
   264 							}
       
   265 
       
   266 						// More than one receiver found? Copy the packet.
       
   267 						if (sap != NULL)
       
   268 							{
       
   269 							RMBufRecvPacket copy;
       
   270 							TRAPD(err, datagram.CopyL(copy);datagram.CopyInfoL(copy));
       
   271 							if (err == KErrNone)
       
   272 								{
       
   273 								copy.Pack();
       
   274 								sap->Process(copy);
       
   275 								}
       
   276 							copy.Free();
       
   277 							}
       
   278 						// Remember last match
       
   279 						sap = s;
       
   280 						}
       
   281 					}
       
   282 	    		}
       
   283 	    	}
       
   284 		// No match? Respond with ICMP
       
   285 		if (sap == NULL)
       
   286 			{
       
   287             /* From RFC1122:
       
   288 			If a datagram arrives addressed to a UDP port for which
       
   289 			there is no pending LISTEN call, UDP SHOULD send an ICMP
       
   290 			Port Unreachable message.*/
       
   291 			LOG(LogProviders(info->iDstAddr.Port()));
       
   292 
       
   293 			// Include UDP header in ICMP payload
       
   294 			info->iOffset -= pkt.iHdr->HeaderLength();
       
   295 
       
   296 			if (info->iVersion == 4)
       
   297 				iNetwork->Icmp4Send(datagram, KInet4ICMP_Unreachable, 3 /* port unreachable*/);
       
   298 			else
       
   299 				iNetwork->Icmp6Send(datagram, KInet6ICMP_Unreachable, 4 /* port unreachable*/);
       
   300 			}
       
   301 		else
       
   302 			{
       
   303 #ifdef SYMBIAN_NETWORKING_UPS
       
   304 			if (!sap->HasNetworkServices() && (!sap->ConnectionInfoSet()) && (info->iFlags & KIpLoopbackPacket) == 0)
       
   305 #else
       
   306 			if (!sap->HasNetworkServices() && (info->iFlags & KIpLoopbackPacket) == 0)
       
   307 #endif
       
   308 				{
       
   309 				LOG(Log::Printf(_L("\tudp SAP[%u] Not allowed to receive external packets"), (TInt)sap));
       
   310 				datagram.Free();
       
   311 				break;
       
   312 				}
       
   313 			const TInt iface = info->iOriginalIndex;
       
   314 
       
   315 			// Punt the packet to the SAP
       
   316 			datagram.Pack();
       
   317 			sap->Process(datagram);
       
   318 
       
   319 			// Reset idle timers
       
   320 			Interfacer()->PacketAccepted(iface);
       
   321 			}
       
   322 		break;
       
   323 
       
   324 	case KProtocolInetIcmp:
       
   325 	case KProtocolInet6Icmp:
       
   326 
       
   327 		// Get port numbers from header
       
   328 		info->iSrcAddr.SetPort(pkt.iHdr->SrcPort());
       
   329 		info->iDstAddr.SetPort(pkt.iHdr->DstPort());
       
   330 
       
   331 #ifdef _LOG
       
   332 		TInetAddr(info->iSrcAddr).OutputWithScope(src); TInetAddr(info->iDstAddr).OutputWithScope(dst);
       
   333 		LOG(Log::Printf(_L("\tudp Process() ICMP reply to UDP datagram {%S,%d} -> {%S,%d}"),
       
   334 			&src, info->iSrcAddr.Port(), &dst, info->iDstAddr.Port()));
       
   335 		LOG(Log::Printf(_L("\tudp Process() ICMP type=%d code=%d param=%d received."),
       
   336 			info->iType, info->iCode, info->iParameter));
       
   337 #endif
       
   338 
       
   339 		sap = (CProviderUDP6*)LocateSap(EMatchServerUnspecAddr,
       
   340 			info->iVersion == 4 ? KAfInet : KAfInet6,
       
   341 			info->iSrcAddr, info->iDstAddr);
       
   342 		if (sap == NULL)
       
   343 			{
       
   344 			LOG(Log::Printf(_L("\tudp Process() No socket. Discarding ICMP message.")));
       
   345 			datagram.Free();
       
   346 			break;
       
   347 			}
       
   348 
       
   349 		err = KErrUnknown;
       
   350 		if (info->iIcmp == KProtocolInetIcmp)
       
   351 			{
       
   352 			//
       
   353 			// ICMPv4 message processing
       
   354 			//
       
   355 			ip4.Set(datagram, 0, TInet6HeaderIP4::MinHeaderLength());
       
   356 			if (!ip4.iHdr)
       
   357 				{
       
   358 				LOG(Log::Printf(_L("\tudp Process() Invalid IPv4 header in ICMP.")));
       
   359 				datagram.Free();
       
   360 				break;
       
   361 				}
       
   362 			icmpSender.SetAddress(ip4.iHdr->SrcAddr());
       
   363 			switch (info->iType)
       
   364 				{
       
   365 			case KInet4ICMP_Unreachable:
       
   366 /*
       
   367    Code           0 = net unreachable
       
   368                   1 = host unreachable
       
   369                   2 = protocol unreachable
       
   370                   3 = port unreachable
       
   371                   4 = fragmentation needed and DF set
       
   372                   5 = source route failed
       
   373                   6 = destination network unknown
       
   374                   7 = destination host unknown
       
   375                   8 = source host isolated
       
   376                   9 = communication with destination network administratively prohibited
       
   377                  10 = communication with destination host administratively prohibited
       
   378                  11 = network unreachable for type of service
       
   379                  12 = host unreachable for type of service
       
   380 				*/
       
   381 				switch (info->iCode)
       
   382 					{
       
   383 				case 2:
       
   384 					err = KErrNoProtocolOpt;
       
   385 					break;
       
   386 
       
   387 				case 3:
       
   388 					err = KErrCouldNotConnect;
       
   389 					break;
       
   390 
       
   391 				case 4:
       
   392 					err = KErrTooBig;
       
   393 					break;
       
   394 
       
   395 				case 0:
       
   396 				case 5:
       
   397 				case 6:
       
   398 				case 8:
       
   399 				case 9:
       
   400 				case 11:
       
   401 					err = KErrNetUnreach;
       
   402 					break;
       
   403 
       
   404 				case 1:
       
   405 				case 7:
       
   406 				case 10:
       
   407 				case 12:
       
   408 					err = KErrHostUnreach;
       
   409 					break;
       
   410 
       
   411 				default:
       
   412 					break;
       
   413 					}
       
   414 				break;
       
   415 
       
   416 			case KInet4ICMP_SourceQuench:
       
   417 				break;
       
   418 
       
   419 			case KInet4ICMP_TimeExceeded:
       
   420 				err = KErrTimedOut;
       
   421 				break;
       
   422 
       
   423 			case KInet4ICMP_ParameterProblem:
       
   424 				err = KErrArgument;
       
   425 				break;
       
   426 
       
   427 			default:
       
   428 				break;
       
   429 				}
       
   430 			}
       
   431 		else
       
   432 			{
       
   433 			//
       
   434 			// ICMPv6 message processing
       
   435 			//
       
   436 			ip6.Set(datagram, 0, TInet6HeaderIP::MinHeaderLength());
       
   437 			if (!ip6.iHdr)
       
   438 				{
       
   439 				LOG(Log::Printf(_L("\tudp  Process() Invalid IPv6 header in ICMP.")));
       
   440 				datagram.Free();
       
   441 				break;
       
   442 				}
       
   443 			icmpSender.SetAddress(ip6.iHdr->SrcAddr());
       
   444 			switch (info->iType)
       
   445 				{
       
   446 			case KInet6ICMP_Unreachable:
       
   447 /*
       
   448    Code           0 - no route to destination
       
   449                   1 - communication with destination administratively prohibited
       
   450                   2 - (not assigned)
       
   451                   3 - address unreachable
       
   452                   4 - port unreachable
       
   453 				*/
       
   454 				switch (info->iCode)
       
   455 					{
       
   456 				case 3:
       
   457 					err = KErrHostUnreach;
       
   458 					break;
       
   459 
       
   460 				case 4:
       
   461 					err = KErrCouldNotConnect;
       
   462 					break;
       
   463 
       
   464 				default:
       
   465 					err = KErrNetUnreach;
       
   466 					break;
       
   467 					}
       
   468 				break;
       
   469 
       
   470 			case KInet6ICMP_PacketTooBig:
       
   471 				err = KErrTooBig;
       
   472 				break;
       
   473 
       
   474 			case KInet6ICMP_TimeExceeded:
       
   475 /*
       
   476    Code           0 - hop limit exceeded in transit
       
   477                   1 - fragment reassembly time exceeded
       
   478 				*/
       
   479 				err = KErrTimedOut;
       
   480 				break;
       
   481 
       
   482 			case KInet6ICMP_ParameterProblem:
       
   483 /*
       
   484    Code           0 - erroneous header field encountered
       
   485                   1 - unrecognized Next Header type encountered
       
   486                   2 - unrecognized IPv6 option encountered
       
   487 				*/
       
   488 				err = KErrArgument;
       
   489 				break;
       
   490 
       
   491 			default:
       
   492 				break;
       
   493 				}
       
   494 			}
       
   495 
       
   496 		// Store and report
       
   497 		sap->IcmpError(err, MSocketNotify::EErrorSend|MSocketNotify::EErrorRecv,
       
   498 			info->iType, info->iCode,
       
   499 			TInetAddr::Cast(info->iSrcAddr),
       
   500 			TInetAddr::Cast(info->iDstAddr),
       
   501 			TInetAddr::Cast(icmpSender));
       
   502 		datagram.Free();
       
   503 		break;
       
   504 
       
   505 	default:
       
   506 		datagram.Free();
       
   507 		break;
       
   508 		}
       
   509 	}