示例#1
0
int CTCPConnection::PacketReceived (const void	*pPacket,
				    unsigned	 nLength,
				    CIPAddress	&rSenderIP,
				    int		 nProtocol)
{
	if (nProtocol != IPPROTO_TCP)
	{
		return 0;
	}

	if (nLength < sizeof (TTCPHeader))
	{
		return -1;
	}

	assert (pPacket != 0);
	TTCPHeader *pHeader = (TTCPHeader *) pPacket;

	if (m_nOwnPort != be2le16 (pHeader->nDestPort))
	{
		return 0;
	}
	
	if (m_State != TCPStateListen)
	{
		if (   m_ForeignIP != rSenderIP
		    || m_nForeignPort != be2le16 (pHeader->nSourcePort))
		{
			return 0;
		}
	}
	else
	{
		if (!(pHeader->nDataOffsetFlags & TCP_FLAG_SYN))
		{
			return 0;
		}

		m_Checksum.SetDestinationAddress (rSenderIP);
	}

	if (m_Checksum.Calculate (pPacket, nLength) != CHECKSUM_OK)
	{
		return 0;
	}

	u16 nFlags = pHeader->nDataOffsetFlags;
	u32 nDataOffset = TCP_DATA_OFFSET (pHeader->nDataOffsetFlags)*4;
	u32 nDataLength = nLength-nDataOffset;

	// Current Segment Variables
	u32 nSEG_SEQ = be2le32 (pHeader->nSequenceNumber);
	u32 nSEG_ACK = be2le32 (pHeader->nAcknowledgmentNumber);

	u32 nSEG_LEN = nDataLength;
	if (nFlags & TCP_FLAG_SYN)
	{
		nSEG_LEN++;
	}
	if (nFlags & TCP_FLAG_FIN)
	{
		nSEG_LEN++;
	}
	
	u32 nSEG_WND = be2le16 (pHeader->nWindow);
	//u16 nSEG_UP  = be2le16 (pHeader->nUrgentPointer);
	//u32 nSEG_PRC;	// segment precedence value

	ScanOptions (pHeader);

#ifdef TCP_DEBUG
	CLogger::Get ()->Write (FromTCP, LogDebug,
				"rx %c%c%c%c%c%c, seq %u, ack %u, win %u, len %u",
				nFlags & TCP_FLAG_URGENT ? 'U' : '-',
				nFlags & TCP_FLAG_ACK    ? 'A' : '-',
				nFlags & TCP_FLAG_PUSH   ? 'P' : '-',
				nFlags & TCP_FLAG_RESET  ? 'R' : '-',
				nFlags & TCP_FLAG_SYN    ? 'S' : '-',
				nFlags & TCP_FLAG_FIN    ? 'F' : '-',
				nSEG_SEQ-m_nIRS,
				nFlags & TCP_FLAG_ACK ? nSEG_ACK-m_nISS : 0,
				nSEG_WND,
				nDataLength);

	DumpStatus ();
#endif

	boolean bAcceptable = FALSE;

	// RFC 793 section 3.9 "SEGMENT ARRIVES"
	switch (m_State)
	{
	case TCPStateClosed:
		if (nFlags & TCP_FLAG_RESET)
		{
			// ignore
		}
		else if (!(nFlags & TCP_FLAG_ACK))
		{
			m_ForeignIP.Set (rSenderIP);
			m_nForeignPort = be2le16 (pHeader->nSourcePort);
			m_Checksum.SetDestinationAddress (rSenderIP);

			SendSegment (TCP_FLAG_RESET | TCP_FLAG_ACK, 0, nSEG_SEQ+nSEG_LEN);
		}
		else
		{
			m_ForeignIP.Set (rSenderIP);
			m_nForeignPort = be2le16 (pHeader->nSourcePort);
			m_Checksum.SetDestinationAddress (rSenderIP);

			SendSegment (TCP_FLAG_RESET, nSEG_ACK);
		}
		break;

	case TCPStateListen:
		if (nFlags & TCP_FLAG_RESET)
		{
			// ignore
		}
		else if (nFlags & TCP_FLAG_ACK)
		{
			m_ForeignIP.Set (rSenderIP);
			m_nForeignPort = be2le16 (pHeader->nSourcePort);
			m_Checksum.SetDestinationAddress (rSenderIP);

			SendSegment (TCP_FLAG_RESET, nSEG_ACK);
		}
		else if (nFlags & TCP_FLAG_SYN)
		{
			m_nRCV_NXT = nSEG_SEQ+1;
			m_nIRS = nSEG_SEQ;

			m_nSND_WND = nSEG_WND;
			m_nSND_WL1 = nSEG_SEQ;
			m_nSND_WL2 = nSEG_ACK;
	
			assert (nSEG_LEN > 0);

			if (nDataLength > 0)
			{
				m_RxQueue.Enqueue ((u8 *) pPacket+nDataOffset, nDataLength);
			}

			m_nISS = CalculateISN ();
			m_RTOCalculator.Initialize (m_nISS);

			m_ForeignIP.Set (rSenderIP);
			m_nForeignPort = be2le16 (pHeader->nSourcePort);
			m_Checksum.SetDestinationAddress (rSenderIP);

			SendSegment (TCP_FLAG_SYN | TCP_FLAG_ACK, m_nISS, m_nRCV_NXT);
			m_RTOCalculator.SegmentSent (m_nISS);

			m_nSND_NXT = m_nISS+1;
			m_nSND_UNA = m_nISS;
			
			NEW_STATE (TCPStateSynReceived);

			m_Event.Set ();
		}
		break;

	case TCPStateSynSent:
		if (nFlags & TCP_FLAG_ACK)
		{
			if (!bwh (m_nISS, nSEG_ACK, m_nSND_NXT))
			{
				if (!(nFlags & TCP_FLAG_RESET))
				{
					SendSegment (TCP_FLAG_RESET, nSEG_ACK);
				}

				return 1;
			}
			else if (bwlh (m_nSND_UNA, nSEG_ACK, m_nSND_NXT))
			{
				bAcceptable = TRUE;
			}
		}

		if (nFlags & TCP_FLAG_RESET)
		{
			if (bAcceptable)
			{
				NEW_STATE (TCPStateClosed);
				m_bSendSYN = FALSE;
				m_nErrno = -1;

				m_Event.Set ();
			}
			
			break;
		}
		
		if (   (nFlags & TCP_FLAG_ACK)
		    && !bAcceptable)
		{
			break;
		}

		if (nFlags & TCP_FLAG_SYN)
		{
			m_nRCV_NXT = nSEG_SEQ+1;
			m_nIRS = nSEG_SEQ;

			if (nFlags & TCP_FLAG_ACK)
			{
				m_RTOCalculator.SegmentAcknowledged (nSEG_ACK);

				if (nSEG_ACK-m_nSND_UNA > 1)
				{
					m_RetransmissionQueue.Advance (nSEG_ACK-m_nSND_UNA-1);
				}

				m_nSND_UNA = nSEG_ACK;
			}

			if (gt (m_nSND_UNA, m_nISS))
			{
				NEW_STATE (TCPStateEstablished);
				m_bSendSYN = FALSE;

				StopTimer (TCPTimerRetransmission);

				// next transmission starts with this count
				m_nRetransmissionCount = MAX_RETRANSMISSIONS;

				m_Event.Set ();

				// RFC 1122 section 4.2.2.20 (c)
				m_nSND_WND = nSEG_WND;
				m_nSND_WL1 = nSEG_SEQ;
				m_nSND_WL2 = nSEG_ACK;
	
				SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT);
				
				if (   (nFlags & TCP_FLAG_FIN)		// other controls?
				    || nDataLength > 0)
				{
					goto StepSix;
				}

				break;
			}
			else
			{
				NEW_STATE (TCPStateSynReceived);
				m_bSendSYN = FALSE;
				SendSegment (TCP_FLAG_SYN | TCP_FLAG_ACK, m_nISS, m_nRCV_NXT);
				m_RTOCalculator.SegmentSent (m_nISS);
				m_nRetransmissionCount = MAX_RETRANSMISSIONS;
				StartTimer (TCPTimerRetransmission, m_RTOCalculator.GetRTO ());

				if (   (nFlags & TCP_FLAG_FIN)		// other controls?
				    || nDataLength > 0)
				{
					if (nFlags & TCP_FLAG_FIN)
					{
						SendSegment (TCP_FLAG_RESET, m_nSND_NXT);
						NEW_STATE (TCPStateClosed);
					}

					if (nDataLength > 0)
					{
						m_RxQueue.Enqueue ((u8 *) pPacket+nDataOffset, nDataLength);
					}

					break;
				}
			}
		}
		break;

	case TCPStateSynReceived:
	case TCPStateEstablished:
	case TCPStateFinWait1:
	case TCPStateFinWait2:
	case TCPStateCloseWait:
	case TCPStateClosing:
	case TCPStateLastAck:
	case TCPStateTimeWait:
		// step 1 ( check sequence number)
		if (m_nRCV_WND > 0)
		{
			if (nSEG_LEN == 0)
			{
				if (bwl (m_nRCV_NXT, nSEG_SEQ, m_nRCV_NXT+m_nRCV_WND))
				{
					bAcceptable = TRUE;
				}
			}
			else
			{
				if (   bwl (m_nRCV_NXT, nSEG_SEQ, m_nRCV_NXT+m_nRCV_WND)
				    || bwl (m_nRCV_NXT, nSEG_SEQ+nSEG_LEN-1, m_nRCV_NXT+m_nRCV_WND))
				{
					bAcceptable = TRUE;
				}
			}
		}
		else
		{
			if (nSEG_LEN == 0)
			{
				if (nSEG_SEQ == m_nRCV_NXT)
				{
					bAcceptable = TRUE;
				}
			}
		}

		if (   !bAcceptable
		    && m_State != TCPStateSynReceived)
		{
			SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT);
			break;
		}

		// step 2 (check RST bit)
		if (nFlags & TCP_FLAG_RESET)
		{
			switch (m_State)
			{
			case TCPStateSynReceived:
				m_RetransmissionQueue.Flush ();
				if (!m_bActiveOpen)
				{
					NEW_STATE (TCPStateListen);
					return 1;
				}
				else
				{
					m_nErrno = -1;
					NEW_STATE (TCPStateClosed);
					m_Event.Set ();
					return 1;
					
				}
				break;

			case TCPStateEstablished:
			case TCPStateFinWait1:
			case TCPStateFinWait2:
			case TCPStateCloseWait:
				m_nErrno = -1;
				m_RetransmissionQueue.Flush ();
				m_TxQueue.Flush ();
				m_RxQueue.Flush ();
				NEW_STATE (TCPStateClosed);
				m_Event.Set ();
				return 1;

			case TCPStateClosing:
			case TCPStateLastAck:
			case TCPStateTimeWait:
				NEW_STATE (TCPStateClosed);
				m_Event.Set ();
				return 1;

			default:
				UNEXPECTED_STATE ();
				return 1;
			}
		}

		// step 3 (check security and precedence, not supported)
		
		// step 4 (check SYN bit)
		if (nFlags & TCP_FLAG_SYN)
		{
			// RFC 1122 section 4.2.2.20 (e)
			if (   m_State == TCPStateSynReceived
			    && !m_bActiveOpen)
			{
				NEW_STATE (TCPStateListen);
				return 1;
			}
			
			SendSegment (TCP_FLAG_RESET, m_nSND_NXT);
			m_nErrno = -1;
			m_RetransmissionQueue.Flush ();
			m_TxQueue.Flush ();
			m_RxQueue.Flush ();
			NEW_STATE (TCPStateClosed);
			m_Event.Set ();
			return 1;
		}

		// step 5 (check ACK field)
		if (!(nFlags & TCP_FLAG_ACK))
		{
			return 1;
		}

		switch (m_State)
		{
		case TCPStateSynReceived:
			if (bwlh (m_nSND_UNA, nSEG_ACK, m_nSND_NXT))
			{
				// RFC 1122 section 4.2.2.20 (f)
				m_nSND_WND = nSEG_WND;
				m_nSND_WL1 = nSEG_SEQ;
				m_nSND_WL2 = nSEG_ACK;

				m_nSND_UNA = nSEG_ACK;		// got ACK for SYN

				m_RTOCalculator.SegmentAcknowledged (nSEG_ACK);

				NEW_STATE (TCPStateEstablished);

				// next transmission starts with this count
				m_nRetransmissionCount = MAX_RETRANSMISSIONS;
			}
			else
			{
				SendSegment (TCP_FLAG_RESET, nSEG_ACK);
			}
			break;

		case TCPStateEstablished:
		case TCPStateFinWait1:
		case TCPStateFinWait2:
		case TCPStateCloseWait:
		case TCPStateClosing:
			if (bwh (m_nSND_UNA, nSEG_ACK, m_nSND_NXT))
			{
				m_RTOCalculator.SegmentAcknowledged (nSEG_ACK);

				unsigned nBytesAck = nSEG_ACK-m_nSND_UNA;
				m_nSND_UNA = nSEG_ACK;

				if (nSEG_ACK == m_nSND_NXT)	// all segments are acknowledged
				{
					StopTimer (TCPTimerRetransmission);

					// next transmission starts with this count
					m_nRetransmissionCount = MAX_RETRANSMISSIONS;

					m_Event.Set ();
				}

				if (   m_State == TCPStateFinWait1
				    || m_State == TCPStateClosing)
				{
					nBytesAck--;		// acknowledged FIN does not count
					m_bFINQueued = FALSE;
				}

				if (   m_State == TCPStateEstablished
				    && nBytesAck == 1)
				{
					nBytesAck--;
				}
				
				if (nBytesAck > 0)
				{
					m_RetransmissionQueue.Advance (nBytesAck);
				}

				// update send window
				if (   lt (m_nSND_WL1, nSEG_SEQ)
				    || (   m_nSND_WL1 == nSEG_SEQ
				        && le (m_nSND_WL2, nSEG_ACK)))
				{
					m_nSND_WND = nSEG_WND;
					m_nSND_WL1 = nSEG_SEQ;
					m_nSND_WL2 = nSEG_ACK;
				}
			}
			else if (le (nSEG_ACK, m_nSND_UNA))	// RFC 1122 section 4.2.2.20 (g)
			{
				// ignore duplicate ACK ...
				
				// RFC 1122 section 4.2.2.20 (g)
				if (bwlh (m_nSND_UNA, nSEG_ACK, m_nSND_NXT))
				{
					// ... but update send window
					if (   lt (m_nSND_WL1, nSEG_SEQ)
					    || (   m_nSND_WL1 == nSEG_SEQ
						&& le (m_nSND_WL2, nSEG_ACK)))
					{
						m_nSND_WND = nSEG_WND;
						m_nSND_WL1 = nSEG_SEQ;
						m_nSND_WL2 = nSEG_ACK;
					}
				}
			}
			else if (gt (nSEG_ACK, m_nSND_NXT))
			{
				SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT);
				return 1;
			}
			
			switch (m_State)
			{
			case TCPStateEstablished:
			case TCPStateCloseWait:
				break;

			case TCPStateFinWait1:
				if (nSEG_ACK == m_nSND_NXT)	// if our FIN is now acknowledged
				{
					m_RTOCalculator.SegmentAcknowledged (nSEG_ACK);

					m_bFINQueued = FALSE;
					StopTimer (TCPTimerRetransmission);
					NEW_STATE (TCPStateFinWait2);
				}
				else
				{
					break;
				}
				// fall through

			case TCPStateFinWait2:
				if (m_RetransmissionQueue.IsEmpty ())
				{
					m_Event.Set ();
				}
				break;
				
			case TCPStateClosing:
				if (nSEG_ACK == m_nSND_NXT)	// if our FIN is now acknowledged
				{
					m_RTOCalculator.SegmentAcknowledged (nSEG_ACK);

					m_bFINQueued = FALSE;
					StopTimer (TCPTimerRetransmission);
					NEW_STATE (TCPStateTimeWait);
					StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT);
				}
				break;

			default:
				UNEXPECTED_STATE ();
				break;
			}
			break;
			
		case TCPStateLastAck:
			if (nSEG_ACK == m_nSND_NXT)	// if our FIN is now acknowledged
			{
				m_bFINQueued = FALSE;
				NEW_STATE (TCPStateClosed);
				m_Event.Set ();
				return 1;
			}
			break;

		case TCPStateTimeWait:
			if (nSEG_ACK == m_nSND_NXT)	// if our FIN is now acknowledged
			{
				m_bFINQueued = FALSE;
				SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT);
				StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT);
			}
			break;

		default:
			UNEXPECTED_STATE ();
			break;
		}

		// step 6 (check URG bit, not supported)
	StepSix:

		// step 7 (process text segment)
		if (nSEG_LEN == 0)
		{
			return 1;
		}
		
		switch (m_State)
		{
		case TCPStateEstablished:
		case TCPStateFinWait1:
		case TCPStateFinWait2:
			if (nSEG_SEQ == m_nRCV_NXT)
			{
				if (nDataLength > 0)
				{
					m_RxQueue.Enqueue ((u8 *) pPacket+nDataOffset, nDataLength);

					m_nRCV_NXT += nDataLength;

					// m_nRCV_WND should be adjusted here (section 3.7)

					// following ACK could be piggybacked with data
					SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT);

					if (nFlags & TCP_FLAG_PUSH)
					{
						m_Event.Set ();
					}
				}
			}
			else
			{
				SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT);
			}
			break;

		case TCPStateCloseWait:
		case TCPStateClosing:
		case TCPStateLastAck:
		case TCPStateTimeWait:
			break;

		default:
			UNEXPECTED_STATE ();
			break;
		}

		// step 8 (check FIN bit)
		if (   m_State == TCPStateClosed
		    || m_State == TCPStateListen
		    || m_State == TCPStateSynSent)
		{
			return 1;
		}
			
		if (!(nFlags & TCP_FLAG_FIN))
		{
			return 1;
		}

		// connection is closing
		m_nRCV_NXT++;
		SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT);
		
		switch (m_State)
		{
		case TCPStateSynReceived:
		case TCPStateEstablished:
			NEW_STATE (TCPStateCloseWait);
			m_Event.Set ();
			break;

		case TCPStateFinWait1:
			if (nSEG_ACK == m_nSND_NXT)	// if our FIN is now acknowledged
			{
				m_bFINQueued = FALSE;
				StopTimer (TCPTimerRetransmission);
				StopTimer (TCPTimerUser);
				NEW_STATE (TCPStateTimeWait);
				StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT);
			}
			else
			{
				NEW_STATE (TCPStateClosing);
			}
			break;

		case TCPStateFinWait2:
			StopTimer (TCPTimerRetransmission);
			StopTimer (TCPTimerUser);
			NEW_STATE (TCPStateTimeWait);
			StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT);
			break;

		case TCPStateCloseWait:
		case TCPStateClosing:
		case TCPStateLastAck:
			break;
			
		case TCPStateTimeWait:
			StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT);
			break;

		default:
			UNEXPECTED_STATE ();
			break;
		}
		break;
	}

	return 1;
}
示例#2
0
int CTCPRejector::PacketReceived (const void *pPacket, unsigned nLength,
				  CIPAddress &rSenderIP, CIPAddress &rReceiverIP, int nProtocol)
{
	if (nProtocol != IPPROTO_TCP)
	{
		return 0;
	}

	if (nLength < sizeof (TTCPHeader))
	{
		return -1;
	}

	assert (pPacket != 0);
	TTCPHeader *pHeader = (TTCPHeader *) pPacket;

	m_nOwnPort = be2le16 (pHeader->nDestPort);
	if (m_nOwnPort == 0)
	{
		return -1;
	}

	assert (m_pNetConfig != 0);
	if (m_pNetConfig->GetIPAddress ()->IsNull ())
	{
		return 0;
	}

	m_Checksum.SetSourceAddress (*m_pNetConfig->GetIPAddress ());
	m_Checksum.SetDestinationAddress (rSenderIP);

	if (m_Checksum.Calculate (pPacket, nLength) != CHECKSUM_OK)
	{
		return 0;
	}

	u16 nFlags = pHeader->nDataOffsetFlags;
	u32 nDataOffset = TCP_DATA_OFFSET (pHeader->nDataOffsetFlags)*4;
	u32 nDataLength = nLength-nDataOffset;

	// Current Segment Variables
	u32 nSEG_SEQ = be2le32 (pHeader->nSequenceNumber);
	u32 nSEG_ACK = be2le32 (pHeader->nAcknowledgmentNumber);

	u32 nSEG_LEN = nDataLength;
	if (nFlags & TCP_FLAG_SYN)
	{
		nSEG_LEN++;
	}
	if (nFlags & TCP_FLAG_FIN)
	{
		nSEG_LEN++;
	}
	
#ifdef TCP_DEBUG
	u32 nSEG_WND = be2le16 (pHeader->nWindow);

	CLogger::Get ()->Write (FromTCP, LogDebug,
				"rx %c%c%c%c%c%c, seq %u, ack %u, win %u, len %u",
				nFlags & TCP_FLAG_URGENT ? 'U' : '-',
				nFlags & TCP_FLAG_ACK    ? 'A' : '-',
				nFlags & TCP_FLAG_PUSH   ? 'P' : '-',
				nFlags & TCP_FLAG_RESET  ? 'R' : '-',
				nFlags & TCP_FLAG_SYN    ? 'S' : '-',
				nFlags & TCP_FLAG_FIN    ? 'F' : '-',
				nSEG_SEQ,
				nFlags & TCP_FLAG_ACK ? nSEG_ACK : 0,
				nSEG_WND,
				nDataLength);
#endif

	m_ForeignIP.Set (rSenderIP);
	m_nForeignPort = be2le16 (pHeader->nSourcePort);

	if (nFlags & TCP_FLAG_RESET)
	{
		// ignore
	}
	else if (!(nFlags & TCP_FLAG_ACK))
	{
		SendSegment (TCP_FLAG_RESET | TCP_FLAG_ACK, 0, nSEG_SEQ+nSEG_LEN);
	}
	else
	{
		SendSegment (TCP_FLAG_RESET, nSEG_ACK);
	}

	return 1;
}
示例#3
0
int CUDPConnection::PacketReceived (const void *pPacket, unsigned nLength, CIPAddress &rSenderIP, int nProtocol)
{
	if (nProtocol != IPPROTO_UDP)
	{
		return 0;
	}

	m_Checksum.SetSourceAddress (rSenderIP);

	// TODO: may not work with some UDP based protocol, would need receiver IP from network layer here
	if (   m_bActiveOpen
	    && m_ForeignIP.IsBroadcast ())
	{
		m_Checksum.SetDestinationAddress (m_ForeignIP);
	}
	else
	{
		if (   m_bActiveOpen
		    && m_ForeignIP != rSenderIP)
		{
			return 0;
		}

		assert (m_pNetConfig != 0);
		m_Checksum.SetDestinationAddress (*m_pNetConfig->GetIPAddress ());
	}
	
	if (nLength <= sizeof (TUDPHeader))
	{
		return 0;
	}
	TUDPHeader *pHeader = (TUDPHeader *) pPacket;

	if (m_nOwnPort != be2le16 (pHeader->nDestPort))
	{
		return 0;
	}

	u16 nSourcePort = be2le16 (pHeader->nSourcePort);
	if (   m_bActiveOpen
	    && m_nForeignPort != nSourcePort)
	{
		return 0;
	}

	if (nLength < be2le16 (pHeader->nLength))
	{
		return -1;
	}
	
	if (   pHeader->nChecksum != UDP_CHECKSUM_NONE
	    && m_Checksum.Calculate (pPacket, nLength) != CHECKSUM_OK)
	{
		return -1;
	}

	nLength -= sizeof (TUDPHeader);
	assert (nLength > 0);

	TUDPPrivateData *pData = new TUDPPrivateData;
	assert (pData != 0);
	rSenderIP.CopyTo (pData->SourceAddress);
	pData->nSourcePort = nSourcePort;

	m_RxQueue.Enqueue ((u8 *) pPacket + sizeof (TUDPHeader), nLength, pData);

	return 1;
}
示例#4
0
int CUDPConnection::PacketReceived (const void *pPacket, unsigned nLength,
				    CIPAddress &rSenderIP, CIPAddress &rReceiverIP, int nProtocol)
{
	if (nProtocol != IPPROTO_UDP)
	{
		return 0;
	}

	if (nLength <= sizeof (TUDPHeader))
	{
		return -1;
	}
	TUDPHeader *pHeader = (TUDPHeader *) pPacket;

	if (m_nOwnPort != be2le16 (pHeader->nDestPort))
	{
		return 0;
	}

	assert (m_pNetConfig != 0);

	u16 nSourcePort = be2le16 (pHeader->nSourcePort);
	if (m_bActiveOpen)
	{
		if (m_nForeignPort != nSourcePort)
		{
			return 0;
		}

		if (   m_ForeignIP != rSenderIP
		    && !m_ForeignIP.IsBroadcast ()
		    && m_ForeignIP != *m_pNetConfig->GetBroadcastAddress ())
		{
			return 0;
		}
	}

	if (nLength < be2le16 (pHeader->nLength))
	{
		return -1;
	}
	
	if (pHeader->nChecksum != UDP_CHECKSUM_NONE)
	{
		m_Checksum.SetSourceAddress (rSenderIP);
		m_Checksum.SetDestinationAddress (rReceiverIP);

		if (m_Checksum.Calculate (pPacket, nLength) != CHECKSUM_OK)
		{
			return -1;
		}
	}

	if (   !m_bBroadcastsAllowed
	    && (   rReceiverIP.IsBroadcast ()
	        || rReceiverIP == *m_pNetConfig->GetBroadcastAddress ()))
	{
		return 1;
	}

	nLength -= sizeof (TUDPHeader);
	assert (nLength > 0);

	TUDPPrivateData *pData = new TUDPPrivateData;
	assert (pData != 0);
	rSenderIP.CopyTo (pData->SourceAddress);
	pData->nSourcePort = nSourcePort;

	m_RxQueue.Enqueue ((u8 *) pPacket + sizeof (TUDPHeader), nLength, pData);

	m_Event.Set ();

	return 1;
}