diff -r 000000000000 -r af10295192d8 networkprotocols/tcpipv4v6prt/src/inet.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/networkprotocols/tcpipv4v6prt/src/inet.cpp Tue Jan 26 15:23:49 2010 +0200 @@ -0,0 +1,800 @@ +// 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: +// inet.cpp - inet protocol base +// + +#include +#include +#include +#include +#include "inet.h" +#include "networkinfo.h" +#include "inet6log.h" + +// +// CProtocolInet6Base +// +// + +CProtocolInet6Base::CProtocolInet6Base() + { + // Nothing here -- rely on CBase zero fill! + } + +void CProtocolInet6Base::InitL(TDesC& /*aTag*/) + { +#ifdef _LOG + // Fetch the protocol name for logging purposes + TServerProtocolDesc info; + Identify(&info); + iName = info.iName; +#endif + } + +void CProtocolInet6Base::BindL(CProtocolBase* /*aProtocol*/, TUint /*aId*/) + { + Panic(EInet6Panic_NotSupported); + } + +void CProtocolInet6Base::Unbind(CProtocolBase* /*aProtocol*/, TUint /*aId*/) + { + } + +void CProtocolInet6Base::StartL() + { + } + +// +// *NOTE* +// In the INET6 stack the Error upcall is passed up from the drivers +// but, it does not require any actions by default (doing something +// here is only useful for protocols modules that want to know about +// changes in the interfaces and possibly doing there own +// reconfiguring after this (for example, 6to4). +// +// In INET6 the interface manager takes care of notifying individual +// flows about the interface changes that affect them. -- msa +// +// This here is required, because the base CProtocolBase::Error() +// calls Panic. A similar consideration applies to the StartSending(), +// but as the CProtocolBase::StartSending() is already a NOP, nothing +// needs to be done here. +// +void CProtocolInet6Base::Error(TInt /*anError*/, CProtocolBase* /*aSourceProtocol*/) + { + } + + +CProtocolInet6Base::~CProtocolInet6Base() + { + // All SAP's should have been detached from this by now! + ASSERT(iSapCount == 0); + } + + +// +// SAP counting +// +void CProtocolInet6Base::IncSAPs() + { + iSapCount++; + } + +void CProtocolInet6Base::DecSAPs() + { + ASSERT(iSapCount > 0); + iSapCount--; + } + +// +// SAP database routines +// +void CProtocolInet6Base::BindProvider(CProviderInet6Base* aSAP) + { +#ifdef _LOG + TBuf<50> local; aSAP->iFlow.FlowContext()->LocalAddr().OutputWithScope(local); + TBuf<50> remote; aSAP->iFlow.FlowContext()->RemoteAddr().OutputWithScope(remote); + Log::Printf(_L("\t%S SAP[%u] BindProvider({%S,%d} <--> {%S,%d})"), + &ProtocolName(), (TInt)aSAP, + &local, aSAP->iFlow.FlowContext()->LocalPort(), &remote, aSAP->iFlow.FlowContext()->RemotePort()); +#endif + + TUint key = ProviderHashKey(aSAP->iFlow.FlowContext()->LocalPort()); + aSAP->iNextSAP = iSAP[key]; + iSAP[key] = aSAP; + } + +void CProtocolInet6Base::QueueBindProvider(CProviderInet6Base* aSAP) + { +#ifdef _LOG + TBuf<50> local; aSAP->iFlow.FlowContext()->LocalAddr().OutputWithScope(local); + TBuf<50> remote; aSAP->iFlow.FlowContext()->RemoteAddr().OutputWithScope(remote); + Log::Printf(_L("\t%S SAP[%u] QueueBindProvider(): {%S,%d} <--> {%S,%d}"), + &ProtocolName(), (TInt)this, + &local, aSAP->iFlow.FlowContext()->LocalPort(), &remote, aSAP->iFlow.FlowContext()->RemotePort()); +#endif + + TUint key = ProviderHashKey(aSAP->iFlow.FlowContext()->LocalPort()); + CProviderInet6Base **sap = &iSAP[key]; + while (*sap != NULL) + sap = &(*sap)->iNextSAP; + *sap = aSAP; + } + +void CProtocolInet6Base::UnbindProvider(CProviderInet6Base* aSAP) + { + CProviderInet6Base **sapPtr; + TUint key; + + if (aSAP->iFlow.FlowContext() == NULL) + return; + + key = ProviderHashKey(aSAP->iFlow.FlowContext()->LocalPort()); + for (sapPtr = &iSAP[key]; *sapPtr != NULL; sapPtr = &((*sapPtr)->iNextSAP)) + if (*sapPtr == aSAP) + { +#ifdef _LOG + TBuf<50> local; aSAP->iFlow.FlowContext()->LocalAddr().OutputWithScope(local); + TBuf<50> remote; aSAP->iFlow.FlowContext()->RemoteAddr().OutputWithScope(remote); + Log::Printf(_L("\t%S SAP[%u] UnbindProvider({%S,%d} <--> {%S,%d})"), + &ProtocolName(), (TInt)aSAP, + &local, aSAP->iFlow.FlowContext()->LocalPort(), &remote, aSAP->iFlow.FlowContext()->RemotePort()); +#endif + *sapPtr = (*sapPtr)->iNextSAP; + aSAP->iNextSAP = NULL; + return; + } + } + +CProviderInet6Base* CProtocolInet6Base::LocateProvider(TUint aPort) + { + CProviderInet6Base *sap; + TUint key = ProviderHashKey(aPort); + + for (sap = iSAP[key]; sap != NULL; sap = sap->iNextSAP) + if (sap->iFlow.FlowContext()->LocalPort() == aPort) + return sap; + + return NULL; + } + +void CProviderInet6Base::InitL() + { + TInt err = iFlow.Open(iProtocol->NetworkService()); + if (err != KErrNone) + User::Leave(err); + + iFlow.SetNotify(this); + + iLastError.iStatus = KErrNone; + iLastError.iErrType = 0; + iLastError.iErrCode = 0; + iErrorMask = 0; + } + +void CProviderInet6Base::Start() + { +#if 0 + // XXX - Setting socket write buffer to 1024 seems to seriously + // hamper TCP performance over loopback. Default is 4096 and 2048 + // also works ok. Have to look at this later. -ML + TVersion v = RNif::Version(); + TUint32 ver = (v.iMajor << 24) | (v.iMinor << 16) | v.iBuild; + if (ver >= 0x01000044) + Nif::SetSocketState(ENifBuffers1024, this); +#endif + } + + +// +// CProviderInet6Base +// +// + +CProviderInet6Base::CProviderInet6Base(CProtocolInet6Base* aProtocol) : iProtocol(aProtocol) + { + LOG(Log::Printf(_L("\t%S SAP[%u] New"), &ProtocolName(), (TInt)this)); + iNextSAP = NULL; + iProtocol->Open(); + iProtocol->IncSAPs(); + if (iIsUser == 0) + { + iProtocol->NetworkService()->IncUsers(); + iIsUser = 1; + } + } + +CProviderInet6Base::~CProviderInet6Base() + { + ((CProtocolInet6Base*)iProtocol)->UnbindProvider(this); + CFlowContext *flow = iFlow.FlowContext(); + if (flow) + { + TPckgBuf< TInt > opt(0); // Currently there is no use for the option parameter + flow->SetOption(KSOLProvider, KSoFlowClosing, opt); + } + iFlow.Close(); + if (iIsUser == 1) + { + iProtocol->NetworkService()->DecUsers(); + iIsUser = 0; + } + iProtocol->DecSAPs(); + LOG(Log::Printf(_L("\t%S SAP[%u] Deleted"), &ProtocolName(), (TInt)this)); + iProtocol->Close(); + } + + +void CProviderInet6Base::ActiveOpen() + { + Panic(EInet6Panic_NotSupported); + } + + +TInt CProviderInet6Base::PassiveOpen(TUint /*aQueSize*/) + { + Panic(EInet6Panic_NotSupported); + return 0; + } + + +void CProviderInet6Base::ActiveOpen(const TDesC8& /*aConnectionData*/) + { + Panic(EInet6Panic_NotSupported); + } + + +TInt CProviderInet6Base::PassiveOpen(TUint /*aQueSize*/,const TDesC8& /*aConnectionData*/) + { + Panic(EInet6Panic_NotSupported); + return 0; + } + +void CProviderInet6Base::Shutdown(TCloseType /*option*/,const TDesC8& /*aDisconnectionData*/) + { + Panic(EInet6Panic_NotSupported); + } + +// *NOTE* +// Why are level KSoInetIfCtrl and KSoInetRtCtrl handled at this +// level? Why not just let iProtocol->SetOption() handle them (as +// would be logical)? The reason is KSoInetEnum*/KSoInetNext*, which +// need a SAP specific context, and that is *NOT* provided by the +// iProtocol->SetOption interface. However, only these options are +// handled here, rest of the KSoInetRtCtrl/KSoInetIfCtrl are passed +// to the protocol -- msa +// +TInt CProviderInet6Base::SetOption(TUint aLevel, TUint aName, const TDesC8& aOption) + { + if (aLevel == KSolInetIp) + { + // Prefetch the option parameter (error return is ignored, + // if the option is not implemented at this level). + TInt val; + const TInt ret = GetOptionInt(aOption, val); + + switch (aName) + { + case KSoHeaderIncluded: + case KSoRawMode: + // *note* Need to arrange KErrNotSupported for TCP! -- msa + + // Implementation of setting HeaderIncluded and RawMode options + if (ret != KErrNone) + return ret; + // [The raw/headerincluded logic here is unnecessarily convoluted. + // In EPOC they could be handled independently, as there is no + // special priviledges required for setting the raw mode either. + // But, because it is specified to work in this way, sigh ... + // -- msa] + // + // Only allow setting of iHeaderIncluded when iRawMode is set + // Clearing is always allowed. + // When iRawMode==0, then *ALWAYS* iHeaderIncluded == 0 + if (aName == KSoRawMode) + { + if (val) + iRawMode = 1; + else + { + iRawMode = 0; + iHeaderIncluded = 0; + } + } + else if (val == 0) + iHeaderIncluded = 0; + else if (iRawMode) + { + iHeaderIncluded = 1; + } + else + return KErrNotSupported; // attempted to set KSoHeaderIncluded without Raw mode +#ifdef _LOG + Log::Printf(_L("SetOpt\t%S SAP[%u] RawMode=%d HeaderInclude=%d"), + &ProtocolName(), (TInt)this, iRawMode, iHeaderIncluded); +#endif + return KErrNone; + + case KSoUserSocket: + if (ret != KErrNone) + return ret; +#ifdef _LOG + Log::Printf(_L("SetOpt\t%S SAP[%u] KSoUserSocket %d -> %d"), + &ProtocolName(), (TInt)this, iIsUser, val); +#endif + if ((TUint)val == iIsUser) + return KErrNone; // No change in state + else if (val == 0) + { + iProtocol->NetworkService()->DecUsers(); + iIsUser = 0; + return KErrNone; + } + else if (val == 1) + { + iProtocol->NetworkService()->IncUsers(); + iIsUser = 1; + return KErrNone; + } + else + return KErrArgument; + default: + // For now, give generic LOG here, but should really log at each implementation -- msa + LOG(Log::Printf(_L("SetOpt\t%S SAP[%u] level=KSolInetIp name=%d"), &ProtocolName(), (TInt)this, aName)); + break; + } + } + else if (aLevel == KSolInetIfCtrl) + { + if (aName == STATIC_CAST(TUint, KSoInetEnumInterfaces)) // See *NOTE* above! + { + iInterfaceIndex = 0; + LOG(Log::Printf(_L("SetOpt\t%S SAP[%u] KSoInetEnumInterfaces"), &ProtocolName(), (TInt)this)); + return KErrNone; + } + } + else if (aLevel == KSolInetRtCtrl) + { + if (aName == STATIC_CAST(TUint, KSoInetEnumRoutes)) // See *NOTE* above! + { + iRouteIndex = 0; + LOG(Log::Printf(_L("SetOpt\t%S SAP[%u] KSoInetEnumRoutes"), &ProtocolName(), (TInt)this)); + return KErrNone; + } + } + else if (aLevel == KNifOptLevel) + { + return KErrNotSupported; + } + if (iFlow.FlowContext()) + { + const TInt ret = iFlow.FlowContext()->SetOption(aLevel, aName, aOption); + if (ret != KErrNotSupported) + return ret; + } + return iProtocol->Interfacer()->SetOption(aLevel, aName, aOption, *this); + } + +TInt CProviderInet6Base::GetOption(TUint aLevel, TUint aName, TDes8& aOption) const + { + LOG(Log::Printf(_L("GetOpt\t%S SAP[%u] level=%x, name=%x, len=%d"), &iProtocol->ProtocolName(), (TInt)this, aLevel, aName, aOption.Length());) + if (aLevel == KSolInetIp) + switch (aName) + { + case KSoInetLastError: + if (STATIC_CAST(TUint, aOption.MaxLength()) >= sizeof(iLastError)) + { + aOption.SetLength(sizeof(TSoInetLastErr)); + aOption.Copy((TUint8*)&iLastError, sizeof(iLastError)); + return KErrNone; + } + return KErrTooBig; + + case KSoHeaderIncluded: + return SetOptionInt(aOption, iHeaderIncluded); + case KSoRawMode: + return SetOptionInt(aOption, iRawMode); + case KSoUserSocket: + return SetOptionInt(aOption, iIsUser != 0); + + default: + break; + } + else if (aLevel == KSolInetIfCtrl && aName == STATIC_CAST(TUint, KSoInetNextInterface)) // See *NOTE* above! + { + TSoInetInterfaceInfo& opt = *(TSoInetInterfaceInfo*)aOption.Ptr(); + if (STATIC_CAST(TUint, aOption.MaxLength()) < sizeof(TSoInetInterfaceInfo)) + return KErrTooBig; + (void) new (&opt) TSoInetInterfaceInfo; // Make sure descriptors are correct. + aOption.SetLength(sizeof(TSoInetInterfaceInfo)); + ((CProviderInet6Base *)this)->iInterfaceIndex = iProtocol->Interfacer()->InterfaceInfo(iInterfaceIndex, opt); + if (iInterfaceIndex > 0) + return KErrNone; + else + return KErrNotFound; + } + else if (aLevel == KSolInetRtCtrl && aName == STATIC_CAST(TUint, KSoInetNextRoute)) // See *NOTE* above! + { + TSoInetRouteInfo& opt = *(TSoInetRouteInfo*)aOption.Ptr(); + if (STATIC_CAST(TUint, aOption.MaxLength()) < sizeof(TSoInetRouteInfo)) + return KErrTooBig; + aOption.SetLength(sizeof(TSoInetRouteInfo)); + (void) new (&opt) TSoInetRouteInfo; // Make sure descriptors are correct. + ((CProviderInet6Base *)this)->iRouteIndex = iProtocol->Interfacer()->RouteInfo(iRouteIndex, opt); + if (iRouteIndex > 0) + return KErrNone; + else + return KErrNotFound; + } + else if (aLevel == KNifOptLevel) + { + return KErrNotSupported; + } + // + // if none of the above "supported", falls here... + // + CFlowContext *flow = iFlow.FlowContext(); + if (flow) + { + const TInt ret = flow->GetOption(aLevel, aName, aOption); + if (ret != KErrNotSupported) + return ret; + } + return iProtocol->Interfacer()->GetOption(aLevel, aName, aOption, *((CProviderInet6Base *)this)); + } + +void CProviderInet6Base::Ioctl(TUint aLevel, TUint aName, TDes8* /*anOption*/) + { + LOG(Log::Printf(_L("Ioctl\t%S SAP[%u] %x, %x)"), &ProtocolName(), (TInt)this, aLevel, aName)); + if (aLevel == KSolInetIp && aName == KIoctlInetLastError) + { + TPckg lastError(iLastError); + iSocket->IoctlComplete(&lastError); + } + else + Error(KErrNotSupported, MSocketNotify::EErrorIoctl); + } + +void CProviderInet6Base::CancelIoctl(TUint aLevel, TUint aName) + { +#ifdef _LOG + Log::Printf(_L("CancelIoctl\t%S SAP[%u] %x, %x)"), &ProtocolName(), (TInt)this, aLevel, aName); +#else + (void)aLevel; // silence compiler warning + (void)aName; // silence compiler warning +#endif + // Error call removed. Fixes defect IP/76. -MikaL + //Error(KErrNotSupported); + } + + +void CProviderInet6Base::Process(RMBufChain& /*aPacket*/, CProtocolBase* /*aSourceProtocol*/) + { + Panic(EInet6Panic_NotSupported); + } + +// +// Error report routine. +// +// Soft errors are not immediately reported to the socket server. +// A soft error is indicated by a zero aOperationMask. +// +// The socket error can be cleared by calling this routing with +// aError == KErrNone. +// +void CProviderInet6Base::Error(TInt aError, TUint aOperationMask) + { + if (aError <= KErrNone && !FatalState()) + { + iLastError.iStatus = aError; + if (aError == KErrNone) + iErrorMask = aOperationMask; + else + iErrorMask |= aOperationMask; + if (iSocket && aOperationMask) + { + LOG(Log::Printf(_L("\t%S SAP[%u] Error %d, mask %b"), + &ProtocolName(), (TInt)this, aError, aOperationMask)); + iSocket->Error(aError, aOperationMask); + } + else + { + LOG(Log::Printf(_L("\t%S SAP[%u] Error %d, mask %b pending"), + &ProtocolName(), (TInt)this, aError, aOperationMask)); + } + } + else + { + LOG(Log::Printf(_L("\t%S SAP[%u] Error %d, mask %b ignored"), + &ProtocolName(), (TInt) this, aError, aOperationMask)); + } + } + +void CProviderInet6Base::SaveIcmpError(TInt aType, TInt aCode, const TInetAddr& aSrcAddr, + const TInetAddr& aDstAddr, const TInetAddr& aErrAddr) + { + iLastError.iErrType = aType; + iLastError.iErrCode = aCode; + iLastError.iSrcAddr = aSrcAddr; + iLastError.iDstAddr = aDstAddr; + iLastError.iErrAddr = aErrAddr; + } + +void CProviderInet6Base::CanSend() + { + if(iSocket && /*iFlow.Status() == EFlow_READY && */!FatalState()) + { + LOG(Log::Printf(_L("\t%S SAP[%u] CanSend() Flow UNBLOCKED"), &ProtocolName(), (TInt)this)); + iSocket->CanSend(); + } + } + +void CProviderInet6Base::NoBearer(const TDesC8& aConnectionParams) + { + if(iSocket) + { + LOG(Log::Printf(_L("\t%S SAP[%u] NoBearer()"), &ProtocolName(), (TInt)this)); + iSocket->NoBearer(aConnectionParams); + } + } + +void CProviderInet6Base::Bearer(const TDesC8 &aConnectionInfo) + { + if(iSocket) + { + LOG(Log::Printf(_L("\t%S SAP[%u] Bearer()"), &ProtocolName(), (TInt)this)); + iSocket->Bearer(aConnectionInfo); + } + } + +TInt CProviderInet6Base::CheckPolicy(const TSecurityPolicy& aPolicy, const char *aDiagnostic) + { + return iSecurityChecker ? iSecurityChecker->CheckPolicy(aPolicy, aDiagnostic) : KErrDisconnected; + } + +TInt CProviderInet6Base::SecurityCheck(MProvdSecurityChecker *aSecurityChecker) + { + iSecurityChecker = aSecurityChecker; + iHasNetworkServices = CheckPolicy(KPolicyNetworkServices, 0) == KErrNone; + return KErrNone; + } + +TInt CProviderInet6Base::GetOptionInt(const TDesC8 &anOption, TInt &aVal) + { + if (STATIC_CAST(TUint, anOption.Length()) < sizeof(aVal)) + return KErrTooBig; + Mem::Copy(&aVal, anOption.Ptr(), sizeof(aVal)); + return KErrNone; + } + +TInt CProviderInet6Base::SetOptionInt(TDes8 &anOption, TInt aVal) + { + if (STATIC_CAST(TUint, anOption.MaxLength()) < sizeof(aVal)) + return KErrTooBig; + anOption.SetLength(sizeof(aVal)); + anOption.Copy((TUint8*)&aVal, sizeof(aVal)); + return KErrNone; + } + +TInt CProviderInet6Base::Write(RMBufChain& aData, TUint aOptions, TSockAddr* aToAddr) + { + RMBufSendPacket packet; + packet.Assign(aData); // *beware!* It is legal for aData to be EMPTY! +#ifdef _LOG + TBuf<70> tmp(_L("NULL")); +#endif + + TInt offset = 0; + RMBufSendInfo* info = NULL; + TInt err(0); + // Allocate the info block for the packet. + info = packet.NewInfo(); + // Because many RMBufChain methods do not handle the empty + // chain "logically", must make sure the chain has at least + // one RMBuf in it (without no content). Allocate one and + // make its content empty. + if (info) + { + if (packet.IsEmpty()) + { + err = packet.Alloc(0); // <-- *WARNING* Assumed to allocate single RMBuf + if (err == KErrNone) + { + packet.First()->AdjustStart(packet.Length()); + info->iLength = 0; + } + } + else + info->iLength = packet.Length(); + } + else + err = KErrNoMBufs; // The info allocation was not successful + + + if(err < 0) + { + // Treat all leaves in above as no MBufs. + LOG(Log::Printf(_L("Write\t%S SAP[%u] No Mbufs (%d)"), &ProtocolName(), (TInt)this, err)); + err = KErrNoMBufs; + goto notify_error; + } + +#ifdef _LOG + if (aToAddr) + TInetAddr::Cast(*aToAddr).OutputWithScope(tmp); + Log::Printf(_L("Write\t%S SAP[%u] len=%d, opt=%x, to=%S"), &ProtocolName(), (TInt)this, info->iLength, aOptions, &tmp); +#endif + + // + // Initialize the info + // + TInetAddr::Cast(info->iSrcAddr).Init(0); + info->iSrcAddr.SetPort(0); + TInetAddr::Cast(info->iDstAddr).Init(0); + info->iDstAddr.SetPort(0); + // + // Get the protocol number to use. + // iProtocolId must be NON-ZERO for anything else, except + // for IP/IP6 raw sockets. Only those sockets have specified + // that the protocol number can be given in port field! + info->iProtocol = iProtocolId != 0 ? iProtocolId : + aToAddr != NULL ? aToAddr->Port() : 0; + info->iFlags = aOptions & (KIpHeaderIncluded | KIpDontFragment); + if (iHeaderIncluded) + info->iFlags |= KIpHeaderIncluded; + (void)new (&info->iFlow) RFlowContext(); + + // + // Prepare iDstAddr from aToAddr, if specified + // + if (aToAddr) + { + info->iDstAddr = *aToAddr; // Copy as is, including port, flow label and scope. + if (info->iDstAddr.Family() != KAfInet6) + TInetAddr::Cast(info->iDstAddr).ConvertToV4Mapped(); + } + // + // Prepare from included header, if present + // + err = KErrNotSupported; + if (info->iFlags & KIpHeaderIncluded) + { + // The packet starts with an IPv4 or IPv6 header. + TInt next_header = info->iProtocol; + TIpHeader *const ip = ((RMBufPacketPeek &)packet).GetIpHeader(); + if (!ip) + { + LOG(Log::Printf(_L("\t%S SAP[%u] HeaderIncluded, short/bad IP header"), &ProtocolName(), (TInt)this)); + goto notify_error; + } + switch (ip->ip4.Version()) + { + case 4: + offset = ip->ip4.HeaderLength(); + // If protocol is ZERO in header, default to aProtocol. This is + // a backward compatibility issue. Applications should not rely + // on this. If they are providing the IPv4 header, they SHOULD + // ALSO fill the proper protocol number in there. + if (!ip->ip4.Protocol()) + ip->ip4.SetProtocol(next_header); + else + next_header = ip->ip4.Protocol(); + TInetAddr::Cast(info->iSrcAddr).SetV4MappedAddress(ip->ip4.SrcAddr()); + if (aToAddr) + ip->ip4.SetDstAddr(TInetAddr::Cast(info->iDstAddr).Address()); + else + TInetAddr::Cast(info->iDstAddr).SetV4MappedAddress(ip->ip4.DstAddr()); + info->iProtocol = KProtocolInetIp; + break; + case 6: + offset = ip->ip6.HeaderLength(); + // Note: ZERO NextHeader() does not cause default processing. In + // IPv6 ZERO is the Hop-by-Hop extension header and potentially + // provided by the application. + next_header = ip->ip6.NextHeader(); + TInetAddr::Cast(info->iSrcAddr).SetAddress(ip->ip6.SrcAddr()); + if (aToAddr) + ip->ip6.SetDstAddr(TInetAddr::Cast(info->iDstAddr).Ip6Address()); + else + TInetAddr::Cast(info->iDstAddr).SetAddress(ip->ip6.DstAddr()); + info->iProtocol = KProtocolInet6Ip; + break; + default: + LOG(Log::Printf(_L("\t%S SAP[%u] HeaderIncluded, bad IP version (= %d)"), &ProtocolName(), (TInt)this, (TInt)ip->ip4.Version())); + goto notify_error; + } + // + // Need to locate the upper layer header + // + while (info->iProtocol != next_header) + { + TInet6Packet hdr(packet, offset); + if (hdr.iHdr == NULL || !TPacketPoker::IsExtensionHeader(next_header)) + { + LOG(Log::Printf(_L("\t%S SAP[%u] HeaderIncluded, unknown extension hdr (= %d)"), &ProtocolName(), (TInt)this, next_header)); + goto notify_error; + } + offset += hdr.iHdr->HeaderLength(); + next_header = hdr.iHdr->NextHeader(); + } + } + + iFlow.SetProtocol(info->iProtocol); + err = DoWrite(packet, *info, aOptions, offset); + if (err == KErrNone) + { + // If packet is Empty, assume DoWrite handled it, and + // don't send it to the protocol. + if (!packet.IsEmpty()) + { + packet.Pack(); + iProtocol->Send(packet); + } + goto packet_done; + } + // DoWrite indicated problem: + // err > 0, flow cannot receive packet + // err < 0, some error condition + // +notify_error: + if (err >= 0) + err = 0; // Return 0 to indicate that packet has not been accepted + else if (err != KErrNoMBufs) + { + // + // Cannot send the packet, report error and drop packet. + // + Error(err, MSocketNotify::EErrorSend); + goto packet_done; + } + else + { + if (iSynchSend == 0) + { + // Out of buffer space (KErrNoMBufs). If iSynchSend is not set, just + // drop the packet silently, + LOG(Log::Printf(_L("\t%S SAP[%u] Dropping packet for KErrNoMBufs"), &ProtocolName(), (TInt)this)); + goto packet_done; + } + LOG(Log::Printf(_L("\t%S SAP[%u] Blocking for KErrNoMBufs"), &ProtocolName(), (TInt)this)); + } + + // note: err == 0 or KErrNoMBufs! + aData.Assign(packet); // Try to return original chain (approximately correct only + // if DoWrite does not add anything to the chain!) + packet.Free(); // Need to release info! + return err; +packet_done: + // Packet has been sent or dropped + packet.Free(); // Cleanup, not always needed (does nothing then). + return 1; // Return 1 to indicate that packet has been accepted + } + +TUint CProviderInet6Base::Write(const TDesC8& aDesc, TUint aOptions, TSockAddr* aAddr) + { + LOG(Log::Printf(_L("Write\t%S SAP[%u] Desclen=%d, opt=%x)"), &ProtocolName(), (TInt)this, aDesc.Length(), aOptions)); + RMBufChain data; + if (aDesc.Length() > 0) + { + TRAPD(err, data.CreateL(aDesc)); + if (err != KErrNone) + { + data.Free(); // just to be sure.. + return 1; + } + } + const TInt ret = Write(data, aOptions, aAddr) != 0; // Return 0 or 1 only. + data.Free(); + return ret; + }