417 lines
9.2 KiB
C
417 lines
9.2 KiB
C
|
//=============================================================================
|
||
|
// Copyright (c) 1998 Microsoft Corporation
|
||
|
// File Name: packet.c
|
||
|
// Abstract:
|
||
|
//
|
||
|
// Author: K.S.Lokesh (lokeshs@) 1-1-98
|
||
|
//=============================================================================
|
||
|
|
||
|
|
||
|
#include "pchdvmrp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
VOID
|
||
|
ProcessDvmrpProbe(
|
||
|
PIF_TABLE_ENTRY pite,
|
||
|
UCHAR *Packet,
|
||
|
ULONG PacketSize,
|
||
|
IPADDR SrcAddr
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
ProcessDvmrpReport(
|
||
|
PIF_TABLE_ENTRY pite,
|
||
|
UCHAR *Packet,
|
||
|
ULONG PacketSize,
|
||
|
IPADDR SrcAddr
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
ProcessDvmrpPrune(
|
||
|
PIF_TABLE_ENTRY pite,
|
||
|
UCHAR *Packet,
|
||
|
ULONG PacketSize,
|
||
|
IPADDR SrcAddr
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
ProcessDvmrpGraft(
|
||
|
PIF_TABLE_ENTRY pite,
|
||
|
UCHAR *Packet,
|
||
|
ULONG PacketSize,
|
||
|
IPADDR SrcAddr
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
ProcessDvmrpGraftAck(
|
||
|
PIF_TABLE_ENTRY pite,
|
||
|
UCHAR *Packet,
|
||
|
ULONG PacketSize,
|
||
|
IPADDR SrcAddr
|
||
|
);
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// _JoinMulticastGroup
|
||
|
//-----------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
JoinMulticastGroup (
|
||
|
SOCKET Sock,
|
||
|
DWORD Group,
|
||
|
DWORD IfIndex,
|
||
|
IPADDR IpAddr
|
||
|
)
|
||
|
{
|
||
|
struct ip_mreq imOption;
|
||
|
DWORD Error = NO_ERROR;
|
||
|
DWORD Retval;
|
||
|
LPSTR lpszGroup = "tobefilled";
|
||
|
LPSTR lpszAddr = "tobefilled";
|
||
|
|
||
|
imOption.imr_multiaddr.s_addr = Group;
|
||
|
imOption.imr_interface.s_addr = IpAddr;
|
||
|
|
||
|
Retval = setsockopt(Sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||
|
(PBYTE)&imOption, sizeof(imOption));
|
||
|
|
||
|
if (Retval == SOCKET_ERROR) {
|
||
|
|
||
|
Error = WSAGetLastError();
|
||
|
|
||
|
Trace4(ERR,
|
||
|
"error %d joining multicast group(%d.%d.%d.%d) on interface "
|
||
|
"(%d) %d.%d.%d.%d",
|
||
|
Error, PRINT_IPADDR(Group), IfIndex, PRINT_IPADDR(IpAddr));
|
||
|
|
||
|
Logerr2(JOIN_GROUP_FAILED, "%s,%s", lpszGroup, lpszAddr, Error);
|
||
|
}
|
||
|
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// _PostAsyncRecv
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
DWORD
|
||
|
PostAsyncRecv(
|
||
|
PIF_TABLE_ENTRY pite
|
||
|
)
|
||
|
{
|
||
|
DWORD Error = NO_ERROR;
|
||
|
PASYNC_SOCKET_DATA pSocketData = pite->pSocketData;
|
||
|
|
||
|
pSocketData->Flags = 0;
|
||
|
pSocketData->FromLen = sizeof(SOCKADDR);
|
||
|
|
||
|
Error = WSARecvFrom(pite->Socket, &pSocketData->WsaBuf, 1,
|
||
|
&pSocketData->NumBytesReceived, &pSocketData->Flags,
|
||
|
(SOCKADDR FAR *)&pSocketData->SrcAddress,
|
||
|
&pSocketData->FromLen, &pSocketData->Overlapped, NULL);
|
||
|
|
||
|
|
||
|
if (Error!=SOCKET_ERROR) {
|
||
|
Trace0(RECEIVE, "the WSAReceiveFrom returned immediately\n");
|
||
|
}
|
||
|
else {
|
||
|
Error = WSAGetLastError();
|
||
|
if (Error!=WSA_IO_PENDING) {
|
||
|
Trace1(RECEIVE,
|
||
|
"WSARecvFrom returned in PostAsyncRecv() with error code:%0x",
|
||
|
Error);
|
||
|
Logerr0(RECVFROM_FAILED, Error);
|
||
|
}
|
||
|
else
|
||
|
Trace0(RECEIVE, "WSARecvFrom() returned WSA_IO_PENDING in ???");
|
||
|
}
|
||
|
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// _McastSetTtl
|
||
|
// set the ttl value for multicast data. the default ttl for multicast is 1.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
DWORD
|
||
|
McastSetTtl(
|
||
|
SOCKET sock,
|
||
|
UCHAR ttl
|
||
|
)
|
||
|
{
|
||
|
INT dwTtl = ttl;
|
||
|
DWORD Error=NO_ERROR;
|
||
|
|
||
|
Error = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL,
|
||
|
(char *)&dwTtl, sizeof(dwTtl));
|
||
|
if (Error != 0) {
|
||
|
Error = WSAGetLastError();
|
||
|
Trace1(ERR, "error:%d: unable to set ttl value", Error);
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// _ProcessAsyncReceivePacket
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
ProcessAsyncReceivePacket(
|
||
|
DWORD ErrorCode,
|
||
|
DWORD NumBytesRecv,
|
||
|
LPOVERLAPPED pOverlapped
|
||
|
)
|
||
|
{
|
||
|
PASYNC_SOCKET_DATA pSocketData;
|
||
|
DWORD IfIndex, Error;
|
||
|
IPADDR SrcAddr, DstnAddr;
|
||
|
CHAR SrcAddrString[20];
|
||
|
DWORD PacketSize, IpHdrLen;
|
||
|
UCHAR *pPacket;
|
||
|
LPBYTE Buffer;
|
||
|
DVMRP_HEADER UNALIGNED *pDvmrpHdr;
|
||
|
PIF_TABLE_ENTRY pite = NULL;
|
||
|
PIP_HEADER pIpHdr;
|
||
|
UCHAR PacketType;
|
||
|
|
||
|
//
|
||
|
// kslksl
|
||
|
// How to get pite?
|
||
|
//
|
||
|
|
||
|
IfIndex = pite->IfIndex;
|
||
|
|
||
|
//
|
||
|
// if the IO completed due to socket being closed, check if the
|
||
|
// refcount is down to 0, in which case safely delete the pite entry
|
||
|
//
|
||
|
|
||
|
if ( (ErrorCode != NO_ERROR) || (NumBytesRecv == 0)) {
|
||
|
|
||
|
//
|
||
|
// kslksl
|
||
|
//
|
||
|
|
||
|
if (InterlockedDecrement(&pite->RefCount) == 0)
|
||
|
DVMRP_FREE(pite);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pSocketData = CONTAINING_RECORD(pOverlapped, ASYNC_SOCKET_DATA,
|
||
|
Overlapped);
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// get interface read lock
|
||
|
//
|
||
|
|
||
|
ACQUIRE_IF_LOCK_SHARED(pite->IfIndex, "ProcessAsyncReceivePacket");
|
||
|
|
||
|
|
||
|
BEGIN_BREAKOUT_BLOCK1 {
|
||
|
|
||
|
// if interface is not active, then free pite if required and return
|
||
|
|
||
|
if (!IS_IF_ACTIVATED(pite)) {
|
||
|
|
||
|
if (InterlockedDecrement(&pite->RefCount) == 0) {
|
||
|
DVMRP_FREE(pite);
|
||
|
}
|
||
|
|
||
|
Trace1(RECEIVE,
|
||
|
"Received packet on inactive interface:%d", IfIndex);
|
||
|
|
||
|
Error = ERROR_CAN_NOT_COMPLETE;
|
||
|
GOTO_END_BLOCK1;
|
||
|
}
|
||
|
|
||
|
|
||
|
// set source addr of packet
|
||
|
|
||
|
SrcAddr = pSocketData->SrcAddress.sin_addr.s_addr;
|
||
|
lstrcpy(SrcAddrString, INET_NTOA(SrcAddr));
|
||
|
|
||
|
|
||
|
// check that the packet has min length
|
||
|
|
||
|
if (NumBytesRecv < MIN_PACKET_SIZE) {
|
||
|
LPSTR lpszAddr = "<tbd>";
|
||
|
|
||
|
Trace2(RECEIVE,
|
||
|
"Received very short packet of length:%d from:%s",
|
||
|
IfIndex, SrcAddrString);
|
||
|
|
||
|
Logwarn2(PACKET_TOO_SMALL, lpszAddr, SrcAddrString, NO_ERROR);
|
||
|
Error = ERROR_CAN_NOT_COMPLETE;
|
||
|
GOTO_END_BLOCK1;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// set packet ptr, IpHdr ptr, dwNumBytes, DstnMcastAddr
|
||
|
//
|
||
|
|
||
|
Buffer = pSocketData->WsaBuf.buf;
|
||
|
IpHdrLen = (Buffer[0]&0x0F)*4;
|
||
|
pIpHdr = (PIP_HEADER)Buffer;
|
||
|
pPacket = &Buffer[IpHdrLen];
|
||
|
PacketSize = NumBytesRecv - IpHdrLen;
|
||
|
DstnAddr = (ULONG)pIpHdr->Dstn.s_addr;
|
||
|
pDvmrpHdr = (DVMRP_HEADER UNALIGNED *) pPacket;
|
||
|
|
||
|
|
||
|
//
|
||
|
// verify that the packet has igmp type
|
||
|
//
|
||
|
|
||
|
if (pIpHdr->Protocol!=0x2) {
|
||
|
Trace4(RECEIVE,
|
||
|
"Packet received with IpDstnAddr(%d.%d.%d.%d) from (%s) on "
|
||
|
"interface:%d is not of Igmp type(%d)",
|
||
|
PRINT_IPADDR(pIpHdr->Dstn.s_addr),
|
||
|
SrcAddrString, pite->IfIndex, pIpHdr->Protocol
|
||
|
);
|
||
|
Error = ERROR_CAN_NOT_COMPLETE;
|
||
|
GOTO_END_BLOCK1;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// verify that the packet has dvmrp type field
|
||
|
//
|
||
|
|
||
|
if ( pDvmrpHdr->Vertype != 0x13) {
|
||
|
|
||
|
Error = ERROR_CAN_NOT_COMPLETE;
|
||
|
GOTO_END_BLOCK1;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
// kslksl
|
||
|
|
||
|
//
|
||
|
// Verify Igmp checksum
|
||
|
//
|
||
|
if (xsum(pDvmrpHdr, sizeof(DVMRP_HEADER)) != 0xffff) {
|
||
|
Trace0(RECEIVE, "Wrong checksum packet received");
|
||
|
GOTO_END_BLOCK1
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// verify that the packet has correct code
|
||
|
//
|
||
|
|
||
|
PacketType = pDvmrpHdr->Code;
|
||
|
|
||
|
switch (PacketType) {
|
||
|
|
||
|
case DVMRP_PROBE:
|
||
|
{
|
||
|
ProcessDvmrpProbe(pite, pPacket, PacketSize, SrcAddr);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case DVMRP_REPORT:
|
||
|
{
|
||
|
ProcessDvmrpReport(pite, pPacket, PacketSize, SrcAddr);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case DVMRP_PRUNE:
|
||
|
{
|
||
|
ProcessDvmrpPrune(pite, pPacket, PacketSize, SrcAddr);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case DVMRP_GRAFT:
|
||
|
{
|
||
|
ProcessDvmrpGraft(pite, pPacket, PacketSize, SrcAddr);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case DVMRP_GRAFT_ACK:
|
||
|
{
|
||
|
ProcessDvmrpGraftAck(pite, pPacket, PacketSize, SrcAddr);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} END_BREAKOUT_BLOCK1;
|
||
|
|
||
|
PostAsyncRecv(pite);
|
||
|
|
||
|
|
||
|
}//end ProcessAsyncReceive
|
||
|
|
||
|
|
||
|
VOID
|
||
|
ProcessDvmrpProbe(
|
||
|
PIF_TABLE_ENTRY pite,
|
||
|
UCHAR *Packet,
|
||
|
ULONG PacketSize,
|
||
|
IPADDR SrcAddr
|
||
|
)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ProcessDvmrpReport(
|
||
|
PIF_TABLE_ENTRY pite,
|
||
|
UCHAR *Packet,
|
||
|
ULONG PacketSize,
|
||
|
IPADDR SrcAddr
|
||
|
)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ProcessDvmrpPrune(
|
||
|
PIF_TABLE_ENTRY pite,
|
||
|
UCHAR *Packet,
|
||
|
ULONG PacketSize,
|
||
|
IPADDR SrcAddr
|
||
|
)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ProcessDvmrpGraft(
|
||
|
PIF_TABLE_ENTRY pite,
|
||
|
UCHAR *Packet,
|
||
|
ULONG PacketSize,
|
||
|
IPADDR SrcAddr
|
||
|
)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ProcessDvmrpGraftAck(
|
||
|
PIF_TABLE_ENTRY pite,
|
||
|
UCHAR *Packet,
|
||
|
ULONG PacketSize,
|
||
|
IPADDR SrcAddr
|
||
|
)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|