diff -r 000000000000 -r af10295192d8 networkprotocols/tcpipv4v6prt/src/udp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/networkprotocols/tcpipv4v6prt/src/udp.cpp Tue Jan 26 15:23:49 2010 +0200 @@ -0,0 +1,509 @@ +// Copyright (c) 2006-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: +// udp.cpp - UDP protocol for IPv6/IPv4 +// + +#include "udp.h" +#include +#include +#include +#include "tcpip_ini.h" +#include "inet6log.h" + +#define SYMBIAN_NETWORKING_UPS + +// +// UDP Protocol Description +// + +void CProtocolUDP6::Describe(TServerProtocolDesc &aDesc) + { + aDesc.iName = _S("udp"); + aDesc.iAddrFamily = KAfInet; + aDesc.iSockType = KSockDatagram; + aDesc.iProtocol = KProtocolInetUdp; + aDesc.iVersion = TVersion(KInet6MajorVersionNumber, + KInet6MinorVersionNumber, + KInet6BuildVersionNumber); + aDesc.iByteOrder = EBigEndian; + aDesc.iServiceInfo = KSIConnectionLess | KSIDatagram | + KSIGracefulClose | KSIPeekData | + KSIRequiresOwnerInfo; + aDesc.iNamingServices = KNSNameResolution | KNSRequiresConnectionStartup; + aDesc.iSecurity = KSocketNoSecurity; + aDesc.iMessageSize = 65536-128; /*KSocketMessageSizeUndefined;*/ + aDesc.iServiceTypeInfo = ESocketSupport | ETransport | + EPreferMBufChains | ENeedMBufs | + EUseCanSend; + aDesc.iNumSockets = KUnlimitedSockets; + } + + + +CProtocolUDP6::CProtocolUDP6() + { + __DECLARE_NAME(_S("CProtocolUDP6")); + } + + +CProtocolUDP6::~CProtocolUDP6() + { + } + + +CServProviderBase* CProtocolUDP6::NewSAPL(TUint aSockType) + { + LOG(Log::Printf(_L("NewSAPL\tudp SockType=%d"), aSockType)); + if (aSockType!=KSockDatagram) + User::Leave(KErrNotSupported); + CProviderUDP6 *sap = new (ELeave) CProviderUDP6(this); + CleanupStack::PushL(sap); + sap->InitL(); + CleanupStack::Pop(); + LOG(Log::Printf(_L("NewSAPL\tudp SAP[%u] OK"), (TUint)sap)); + return sap; + } + +void CProtocolUDP6::InitL(TDesC& aTag) + { + CProtocolInet6Transport::InitL(aTag); + } + + +void CProtocolUDP6::StartL() + { + CProtocolInet6Transport::StartL(); + + iRecvBuf = GetIniValue(TCPIP_INI_UDP, TCPIP_INI_UDP_RECV_BUF, KUdpDefaultRecvBuf, 1, KMaxTInt); + + // Flags on by default + iWaitNif = GetIniValue(TCPIP_INI_UDP, TCPIP_INI_UDP_WAIT_NIF, 1, 0, 1); + } + + +void CProtocolUDP6::Identify(TServerProtocolDesc *aInfo) const + { + Describe(*aInfo); + } + +TInt CProtocolUDP6::Send(RMBufChain& aPacket,CProtocolBase* /*aSourceProtocol=NULL*/) + { + LOG(Log::Printf(_L("\tudp Send(%d bytes)"), RMBufSendPacket::PeekInfoInChain(aPacket)->iLength)); + return iNetwork->Send(aPacket); + } + + +void CProtocolUDP6::Process(RMBufChain& aPacket, CProtocolBase* /*aSourceProtocol*/) + { + RMBufRecvPacket datagram; + datagram.Assign(aPacket); + RMBufRecvInfo* info = datagram.Unpack(); + TInet6PacketUDP pkt(datagram, info->iOffset); + TInet6Packet ip4; + TInet6Packet ip6; + TInt err = KErrNone; + TInt version(0); + + CProviderUDP6 *sap = NULL; + TInetAddr icmpSender; + +#ifdef _LOG + TBuf<50> src, dst; + LOG(Log::Printf(_L("\tudp Process(%d bytes)"), datagram.Length())); +#endif + + ASSERT(info->iLength == datagram.Length()); + + // + // Preliminary checking for both UDP and ICMP + // + switch (info->iProtocol) + { + case KProtocolInetUdp: + // Sanity checking + if (!pkt.iHdr) + { + LOG(Log::Printf(_L("\tudp Process() Runt packet discarded"))); + datagram.Free(); + return; + } + +#ifdef _LOGx + TInetAddr(info->iSrcAddr).OutputWithScope(src); TInetAddr(info->iDstAddr).OutputWithScope(dst); + LOG(Log::Printf(_L("\tudp Process(%d bytes) {%S,%d} -> {%S,%d}"), + datagram.Length(), &src, pkt.iHdr->SrcPort(), &dst, pkt.iHdr->DstPort())); +#endif + + // More sanity checking. + if (pkt.iHdr->SrcPort() == KInetPortNone || pkt.iHdr->DstPort() == KInetPortNone) + { + LOG(Log::Printf(_L("\tudp Process() Zero port. Packet discarded."))); + datagram.Free(); + return; + } + break; + + default: + LOG(Log::Printf(_L("\tudp Process() Unknown protocol. Packet discarded."))); + datagram.Free(); + return; + } + + switch (info->iIcmp) + { + case 0: + + // Check source address + if (!TInetAddr::Cast(info->iSrcAddr).IsUnicast() && !TInetAddr::Cast(info->iSrcAddr).IsUnspecified()) + { + LOG(Log::Printf(_L("\tudp Process() Invalid source address. Packet discarded."))); + datagram.Free(); + break; + } + + // Sanity checking + if (info->iLength != info->iOffset + pkt.iHdr->Length()) + { + LOG(Log::Printf(_L("\tudp Process() Size mismatch. Packet discarded."))); + datagram.Free(); + break; + } + + // Process UDP checksum. Check for no checksum (legal in UDP/IPv4) + if (pkt.iHdr->Checksum() ? !pkt.VerifyChecksum(datagram, info, info->iOffset) : info->iVersion != 4) + { + LOG(Log::Printf(_L("\tudp Process() Bad checksum. Packet discarded."))); + datagram.Free(); + return; + } + + //LOG(Log::Printf(_L("Verified UDP checksum %04x."), pkt.iHdr->Checksum())); + + // Get port numbers from header + info->iSrcAddr.SetPort(pkt.iHdr->SrcPort()); + info->iDstAddr.SetPort(pkt.iHdr->DstPort()); + +#ifdef _LOG + TInetAddr(info->iSrcAddr).OutputWithScope(src); TInetAddr(info->iDstAddr).OutputWithScope(dst); + LOG(Log::Printf(_L("\tudp Process() UDP datagram {%S,%d} -> {%S,%d}"), + &src, info->iSrcAddr.Port(), &dst, info->iDstAddr.Port())); +#endif + + // Advance iOffset over the UDP header + info->iOffset += pkt.iHdr->HeaderLength(); + + // + // Replicate packets to all receivers. + // If there is only a single receiver, + // no extra packet copies will be made. + // + CProviderUDP6 *s; + version = info->iVersion == 4 ? KAfInet : KAfInet6; + + // Locate hash bucket and traverse hash chain + s = (CProviderUDP6*)CProtocolInet6Base::LocateProvider(info->iDstAddr.Port()); + // Locate best match if exists + if (s) + { + if (!s->iNextSAP) // only one possible receiver in hash entry + { + // Locate best match +#ifndef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING + sap = (CProviderUDP6*)LocateSap(EMatchServerUnspecAddr, + version, info->iDstAddr, info->iSrcAddr, s); +#else + sap = (CProviderUDP6*)LocateSap(EMatchServerUnspecAddr, + version, info->iDstAddr, info->iSrcAddr, s,info->iInterfaceIndex); +#endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING + } + else // Multiple possible receivers in hash entry + { +#ifndef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING + sap = (CProviderUDP6*)LocateSap(EMatchServerSpecAddr, //Since this is UDP we are only interested in the dst Ip addr + version, info->iDstAddr, info->iSrcAddr, s); +#else + sap = (CProviderUDP6*)LocateSap(EMatchServerSpecAddr, //Since this is UDP we are only interested in the dst Ip addr + version, info->iDstAddr, info->iSrcAddr, s,info->iInterfaceIndex); +#endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING + + if (!sap) // no explicit connections + { + for (; s != NULL; s = (CProviderUDP6*)s->iNextSAP) + { + // Locate next match +#ifndef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING + s = (CProviderUDP6*)LocateSap(EMatchServerUnspecAddr, + version, info->iDstAddr, info->iSrcAddr, s); +#else + s = (CProviderUDP6*)LocateSap(EMatchServerUnspecAddr, + version, info->iDstAddr, info->iSrcAddr, s,info->iInterfaceIndex); +#endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING + // No match? + if (s == NULL) + break; + +#ifdef SYMBIAN_NETWORKING_UPS + if (!s->HasNetworkServices() && (!s->ConnectionInfoSet())&& (info->iFlags & KIpLoopbackPacket) == 0) +#else + if (!s->HasNetworkServices() && (info->iFlags & KIpLoopbackPacket) == 0) +#endif + { + LOG(Log::Printf(_L("\tudp SAP[%u] Not allowed to receive external packets"), (TInt)s)); + continue; + } + + // More than one receiver found? Copy the packet. + if (sap != NULL) + { + RMBufRecvPacket copy; + TRAPD(err, datagram.CopyL(copy);datagram.CopyInfoL(copy)); + if (err == KErrNone) + { + copy.Pack(); + sap->Process(copy); + } + copy.Free(); + } + // Remember last match + sap = s; + } + } + } + } + // No match? Respond with ICMP + if (sap == NULL) + { + /* From RFC1122: + If a datagram arrives addressed to a UDP port for which + there is no pending LISTEN call, UDP SHOULD send an ICMP + Port Unreachable message.*/ + LOG(LogProviders(info->iDstAddr.Port())); + + // Include UDP header in ICMP payload + info->iOffset -= pkt.iHdr->HeaderLength(); + + if (info->iVersion == 4) + iNetwork->Icmp4Send(datagram, KInet4ICMP_Unreachable, 3 /* port unreachable*/); + else + iNetwork->Icmp6Send(datagram, KInet6ICMP_Unreachable, 4 /* port unreachable*/); + } + else + { +#ifdef SYMBIAN_NETWORKING_UPS + if (!sap->HasNetworkServices() && (!sap->ConnectionInfoSet()) && (info->iFlags & KIpLoopbackPacket) == 0) +#else + if (!sap->HasNetworkServices() && (info->iFlags & KIpLoopbackPacket) == 0) +#endif + { + LOG(Log::Printf(_L("\tudp SAP[%u] Not allowed to receive external packets"), (TInt)sap)); + datagram.Free(); + break; + } + const TInt iface = info->iOriginalIndex; + + // Punt the packet to the SAP + datagram.Pack(); + sap->Process(datagram); + + // Reset idle timers + Interfacer()->PacketAccepted(iface); + } + break; + + case KProtocolInetIcmp: + case KProtocolInet6Icmp: + + // Get port numbers from header + info->iSrcAddr.SetPort(pkt.iHdr->SrcPort()); + info->iDstAddr.SetPort(pkt.iHdr->DstPort()); + +#ifdef _LOG + TInetAddr(info->iSrcAddr).OutputWithScope(src); TInetAddr(info->iDstAddr).OutputWithScope(dst); + LOG(Log::Printf(_L("\tudp Process() ICMP reply to UDP datagram {%S,%d} -> {%S,%d}"), + &src, info->iSrcAddr.Port(), &dst, info->iDstAddr.Port())); + LOG(Log::Printf(_L("\tudp Process() ICMP type=%d code=%d param=%d received."), + info->iType, info->iCode, info->iParameter)); +#endif + + sap = (CProviderUDP6*)LocateSap(EMatchServerUnspecAddr, + info->iVersion == 4 ? KAfInet : KAfInet6, + info->iSrcAddr, info->iDstAddr); + if (sap == NULL) + { + LOG(Log::Printf(_L("\tudp Process() No socket. Discarding ICMP message."))); + datagram.Free(); + break; + } + + err = KErrUnknown; + if (info->iIcmp == KProtocolInetIcmp) + { + // + // ICMPv4 message processing + // + ip4.Set(datagram, 0, TInet6HeaderIP4::MinHeaderLength()); + if (!ip4.iHdr) + { + LOG(Log::Printf(_L("\tudp Process() Invalid IPv4 header in ICMP."))); + datagram.Free(); + break; + } + icmpSender.SetAddress(ip4.iHdr->SrcAddr()); + switch (info->iType) + { + case KInet4ICMP_Unreachable: +/* + Code 0 = net unreachable + 1 = host unreachable + 2 = protocol unreachable + 3 = port unreachable + 4 = fragmentation needed and DF set + 5 = source route failed + 6 = destination network unknown + 7 = destination host unknown + 8 = source host isolated + 9 = communication with destination network administratively prohibited + 10 = communication with destination host administratively prohibited + 11 = network unreachable for type of service + 12 = host unreachable for type of service + */ + switch (info->iCode) + { + case 2: + err = KErrNoProtocolOpt; + break; + + case 3: + err = KErrCouldNotConnect; + break; + + case 4: + err = KErrTooBig; + break; + + case 0: + case 5: + case 6: + case 8: + case 9: + case 11: + err = KErrNetUnreach; + break; + + case 1: + case 7: + case 10: + case 12: + err = KErrHostUnreach; + break; + + default: + break; + } + break; + + case KInet4ICMP_SourceQuench: + break; + + case KInet4ICMP_TimeExceeded: + err = KErrTimedOut; + break; + + case KInet4ICMP_ParameterProblem: + err = KErrArgument; + break; + + default: + break; + } + } + else + { + // + // ICMPv6 message processing + // + ip6.Set(datagram, 0, TInet6HeaderIP::MinHeaderLength()); + if (!ip6.iHdr) + { + LOG(Log::Printf(_L("\tudp Process() Invalid IPv6 header in ICMP."))); + datagram.Free(); + break; + } + icmpSender.SetAddress(ip6.iHdr->SrcAddr()); + switch (info->iType) + { + case KInet6ICMP_Unreachable: +/* + Code 0 - no route to destination + 1 - communication with destination administratively prohibited + 2 - (not assigned) + 3 - address unreachable + 4 - port unreachable + */ + switch (info->iCode) + { + case 3: + err = KErrHostUnreach; + break; + + case 4: + err = KErrCouldNotConnect; + break; + + default: + err = KErrNetUnreach; + break; + } + break; + + case KInet6ICMP_PacketTooBig: + err = KErrTooBig; + break; + + case KInet6ICMP_TimeExceeded: +/* + Code 0 - hop limit exceeded in transit + 1 - fragment reassembly time exceeded + */ + err = KErrTimedOut; + break; + + case KInet6ICMP_ParameterProblem: +/* + Code 0 - erroneous header field encountered + 1 - unrecognized Next Header type encountered + 2 - unrecognized IPv6 option encountered + */ + err = KErrArgument; + break; + + default: + break; + } + } + + // Store and report + sap->IcmpError(err, MSocketNotify::EErrorSend|MSocketNotify::EErrorRecv, + info->iType, info->iCode, + TInetAddr::Cast(info->iSrcAddr), + TInetAddr::Cast(info->iDstAddr), + TInetAddr::Cast(icmpSender)); + datagram.Free(); + break; + + default: + datagram.Free(); + break; + } + }