732 lines
22 KiB
C
732 lines
22 KiB
C
|
//=============================================================================
|
||
|
// Copyright (c) 1997 Microsoft Corporation
|
||
|
// File: packet.c
|
||
|
//
|
||
|
// Abstract:
|
||
|
// This module defines SendPacket, JoinMulticastGroup, LeaveMulticastGroup,
|
||
|
// and xsum.
|
||
|
//
|
||
|
// Author: K.S.Lokesh (lokeshs@) 11-1-97
|
||
|
//
|
||
|
// Revision History:
|
||
|
//=============================================================================
|
||
|
|
||
|
#include "pchigmp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
UCHAR
|
||
|
GetMaxRespCode(
|
||
|
PIF_TABLE_ENTRY pite,
|
||
|
DWORD val
|
||
|
);
|
||
|
|
||
|
|
||
|
UCHAR GetQqic (
|
||
|
DWORD val
|
||
|
);
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// _SendPacket
|
||
|
//
|
||
|
// Sends the packet. Called for ras server interfaces only for general queries.
|
||
|
// Locks: assumes IfRead lock
|
||
|
// for ver2 group specific query, send packet irrespective of pgie state.
|
||
|
//------------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
SendPacket (
|
||
|
PIF_TABLE_ENTRY pite,
|
||
|
PGI_ENTRY pgie, //null for gen query, and group_query_v2
|
||
|
DWORD PacketType, //MSG_GEN_QUERY,
|
||
|
//MSG_GROUP_QUERY_V2,MSG_GROUP_QUERY_V3
|
||
|
// MSG_SOURCES_QUERY
|
||
|
DWORD Group //destination McastGrp
|
||
|
)
|
||
|
{
|
||
|
DWORD Error = NO_ERROR;
|
||
|
SOCKADDR_IN saSrcAddr, saDstnAddr;
|
||
|
BYTE *SendBufPtr;
|
||
|
DWORD SendBufLen, IpHdrLen=0, NumSources, Count;
|
||
|
IGMP_HEADER UNALIGNED *IgmpHeader;
|
||
|
INT iLength;
|
||
|
BOOL bHdrIncl = IS_RAS_SERVER_IF(pite->IfType);
|
||
|
UCHAR RouterAlert[4] = {148, 4, 0, 0};
|
||
|
|
||
|
//MSG_SOURCES_QUERY
|
||
|
PIGMP_HEADER_V3_EXT pSourcesQuery;
|
||
|
LONGLONG llCurTime;
|
||
|
DWORD Version;
|
||
|
|
||
|
|
||
|
Trace0(ENTER1, "Entering _SendPacket()");
|
||
|
|
||
|
if (PacketType==MSG_GEN_QUERY)
|
||
|
Version = GET_IF_VERSION(pite);
|
||
|
else if (PacketType==MSG_GROUP_QUERY_V2)
|
||
|
Version =2;
|
||
|
else
|
||
|
Version = pgie->Version;
|
||
|
|
||
|
|
||
|
//
|
||
|
// make sure that the pgie->version has not meanwhile changed
|
||
|
//
|
||
|
if ( ((PacketType==MSG_SOURCES_QUERY)||(PacketType==MSG_GROUP_QUERY_V3))
|
||
|
&& pgie->Version!=3
|
||
|
) {
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
if ( (PacketType==MSG_GROUP_QUERY_V2) && pgie!=NULL && pgie->Version!=2)
|
||
|
return NO_ERROR;
|
||
|
|
||
|
|
||
|
//source query and list is empty
|
||
|
if (PacketType==MSG_SOURCES_QUERY && IsListEmpty(&pgie->V3SourcesQueryList))
|
||
|
return NO_ERROR;
|
||
|
|
||
|
|
||
|
SendBufLen = sizeof(IGMP_HEADER)
|
||
|
+ ((Version==3)?sizeof(IGMP_HEADER_V3_EXT):0);
|
||
|
IpHdrLen = (bHdrIncl)
|
||
|
? sizeof(IP_HEADER) + sizeof(RouterAlert) : 0;
|
||
|
|
||
|
if (PacketType==MSG_SOURCES_QUERY) {
|
||
|
SendBufPtr = (PBYTE) IGMP_ALLOC(SendBufLen + IpHdrLen
|
||
|
+ sizeof(IPADDR)*pgie->V3SourcesQueryCount,
|
||
|
0x4000,pite->IfIndex);
|
||
|
}
|
||
|
else {
|
||
|
SendBufPtr = (PBYTE) IGMP_ALLOC(SendBufLen+IpHdrLen, 0x8000,pite->IfIndex);
|
||
|
}
|
||
|
if (!SendBufPtr) {
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// set destination multicast addr (general queries sent to ALL_HOSTS_MCAST
|
||
|
// and group specific queries sent to the GroupAddr
|
||
|
//
|
||
|
ZeroMemory((PVOID)&saDstnAddr, sizeof(saDstnAddr));
|
||
|
saDstnAddr.sin_family = AF_INET;
|
||
|
saDstnAddr.sin_port = 0;
|
||
|
saDstnAddr.sin_addr.s_addr = (PacketType==MSG_GEN_QUERY) ?
|
||
|
ALL_HOSTS_MCAST : Group;
|
||
|
|
||
|
|
||
|
//
|
||
|
// set igmp header
|
||
|
//
|
||
|
|
||
|
IgmpHeader = (IGMP_HEADER UNALIGNED*)
|
||
|
(bHdrIncl
|
||
|
? &SendBufPtr[IpHdrLen]
|
||
|
: SendBufPtr);
|
||
|
|
||
|
|
||
|
IgmpHeader->Vertype = IGMP_QUERY;
|
||
|
|
||
|
// have to divide GenQueryInterval by 100, as it should be in units of 100ms
|
||
|
if (PacketType==MSG_GEN_QUERY) {
|
||
|
|
||
|
// for gen query, set response time if the IF-Ver2 else set it to 0
|
||
|
IgmpHeader->ResponseTime = GetMaxRespCode(pite,
|
||
|
pite->Config.GenQueryMaxResponseTime/100);
|
||
|
}
|
||
|
else {
|
||
|
IgmpHeader->ResponseTime = GetMaxRespCode(pite,
|
||
|
pite->Config.LastMemQueryInterval/100);
|
||
|
}
|
||
|
|
||
|
if (Version==3) {
|
||
|
|
||
|
llCurTime = GetCurrentIgmpTime();
|
||
|
pSourcesQuery = (PIGMP_HEADER_V3_EXT)
|
||
|
((PBYTE)IgmpHeader+sizeof(IGMP_HEADER));
|
||
|
|
||
|
pSourcesQuery->Reserved = 0;
|
||
|
pSourcesQuery->QRV = (UCHAR)pite->Config.RobustnessVariable;
|
||
|
pSourcesQuery->QQIC = GetQqic(pite->Config.GenQueryInterval);
|
||
|
|
||
|
pSourcesQuery->NumSources = 0;
|
||
|
|
||
|
if (PacketType==MSG_GROUP_QUERY_V3) {
|
||
|
pSourcesQuery->SFlag =
|
||
|
(QueryRemainingTime(&pgie->GroupMembershipTimer, llCurTime)
|
||
|
<=pite->Config.LastMemQueryInterval)
|
||
|
? 0 : 1;
|
||
|
}
|
||
|
// first send gen query and 1st sources query packet without suppress bit
|
||
|
else {
|
||
|
pSourcesQuery->SFlag = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// twice in loop for sources query
|
||
|
Count = (PacketType==MSG_SOURCES_QUERY)? 0 : 1;
|
||
|
|
||
|
|
||
|
for ( ; Count<2; Count++) {
|
||
|
|
||
|
IgmpHeader->Xsum = 0;
|
||
|
|
||
|
|
||
|
if (PacketType==MSG_SOURCES_QUERY) {
|
||
|
|
||
|
PLIST_ENTRY pHead, ple;
|
||
|
|
||
|
if (Count==1 && (PacketType==MSG_SOURCES_QUERY))
|
||
|
pSourcesQuery->SFlag = 1;
|
||
|
|
||
|
|
||
|
pHead = &pgie->V3SourcesQueryList;
|
||
|
for (NumSources=0,ple=pHead->Flink; ple!=pHead; ) {
|
||
|
|
||
|
PGI_SOURCE_ENTRY pSourceEntry =
|
||
|
CONTAINING_RECORD(ple, GI_SOURCE_ENTRY, V3SourcesQueryList);
|
||
|
ple = ple->Flink;
|
||
|
|
||
|
if ( (pSourcesQuery->SFlag
|
||
|
&&(QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)
|
||
|
>GET_IF_CONFIG_FOR_SOURCE(pSourceEntry).LastMemQueryInterval))
|
||
|
|| (!pSourcesQuery->SFlag
|
||
|
&&(QueryRemainingTime(&pSourceEntry->SourceExpTimer, llCurTime)
|
||
|
<=GET_IF_CONFIG_FOR_SOURCE(pSourceEntry).LastMemQueryInterval)) )
|
||
|
{
|
||
|
if (NumSources==0) {
|
||
|
Trace4(SEND,
|
||
|
"Sent Sources Query on IfIndex(%0x) IpAddr(%d.%d.%d.%d) "
|
||
|
"for Group(%d.%d.%d.%d) SFlag:%d",
|
||
|
pite->IfIndex, PRINT_IPADDR(pite->IpAddr),
|
||
|
PRINT_IPADDR(Group),pSourcesQuery->SFlag
|
||
|
);
|
||
|
}
|
||
|
|
||
|
pSourcesQuery->Sources[NumSources++] = pSourceEntry->IpAddr;
|
||
|
|
||
|
Trace1(SEND, " Source:%d.%d.%d.%d",
|
||
|
PRINT_IPADDR(pSourceEntry->IpAddr));
|
||
|
|
||
|
if (--pSourceEntry->V3SourcesQueryLeft==0) {
|
||
|
RemoveEntryList(&pSourceEntry->V3SourcesQueryList);
|
||
|
pSourceEntry->bInV3SourcesQueryList = FALSE;
|
||
|
pgie->V3SourcesQueryCount--;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NumSources==0)
|
||
|
continue;
|
||
|
|
||
|
pSourcesQuery->NumSources = htons((USHORT)NumSources);
|
||
|
|
||
|
SendBufLen += sizeof(IPADDR)*NumSources;
|
||
|
}
|
||
|
|
||
|
IgmpHeader->Group = (PacketType==MSG_GEN_QUERY) ? 0 : Group;
|
||
|
|
||
|
IgmpHeader->Xsum = ~xsum((PVOID)IgmpHeader, SendBufLen);
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// send the packet
|
||
|
//
|
||
|
if (!bHdrIncl) {
|
||
|
|
||
|
Error = NO_ERROR;
|
||
|
|
||
|
iLength = sendto(pite->SocketEntry.Socket, SendBufPtr,
|
||
|
SendBufLen+IpHdrLen, 0,
|
||
|
(PSOCKADDR) &saDstnAddr, sizeof(SOCKADDR_IN)
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// error messages and statistics updates
|
||
|
//
|
||
|
if ( (iLength==SOCKET_ERROR) || ((DWORD)iLength<SendBufLen+IpHdrLen) ) {
|
||
|
Error = WSAGetLastError();
|
||
|
Trace4(ERR,
|
||
|
"error %d sending query on McastAddr %d.%d.%d.%d on "
|
||
|
"interface %d(%d.%d.%d.%d)",
|
||
|
Error, PRINT_IPADDR(saDstnAddr.sin_addr.s_addr), pite->IfIndex,
|
||
|
PRINT_IPADDR(pite->IpAddr));
|
||
|
IgmpAssertOnError(FALSE);
|
||
|
Logwarn2(SENDTO_FAILED, "%I%I", pite->IpAddr, saDstnAddr.sin_addr, Error);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// for RAS server interface, use HDRINCL option. Build up the ip header and
|
||
|
// send the packet to all RAS clients.
|
||
|
//
|
||
|
else {
|
||
|
|
||
|
PIP_HEADER IpHdr;
|
||
|
DWORD IpHdrLen = sizeof(IP_HEADER) + sizeof(RouterAlert);
|
||
|
|
||
|
//
|
||
|
// igmp follows the ip header containing the routerAlert option
|
||
|
//
|
||
|
|
||
|
IpHdr = (IP_HEADER *)((PBYTE)SendBufPtr);
|
||
|
|
||
|
#define wordsof(x) (((x)+3)/4) /* Number of 32-bit words */
|
||
|
|
||
|
// Set IP version (4) and IP header length
|
||
|
IpHdr->Hl = (UCHAR) (IPVERSION * 16
|
||
|
+ wordsof(sizeof(IP_HEADER) + sizeof(RouterAlert)));
|
||
|
|
||
|
// No TOS bits are set
|
||
|
IpHdr->Tos = 0;
|
||
|
|
||
|
// Total IP length is set in host order
|
||
|
IpHdr->Len = (USHORT)(IpHdrLen+sizeof(IGMP_HEADER));
|
||
|
|
||
|
// Stack will fill in the ID
|
||
|
IpHdr->Id = 0;
|
||
|
|
||
|
// No offset
|
||
|
IpHdr->Offset = 0;
|
||
|
|
||
|
// Set the TTL to 1
|
||
|
IpHdr->Ttl = 1;
|
||
|
|
||
|
// Protocol is IGMP
|
||
|
IpHdr->Protocol = IPPROTO_IGMP;
|
||
|
|
||
|
// Checksum is set by stack
|
||
|
IpHdr->Xsum = 0;
|
||
|
|
||
|
// Set source and destination address
|
||
|
IpHdr->Src.s_addr = pite->IpAddr;
|
||
|
IpHdr->Dstn.s_addr = ALL_HOSTS_MCAST;
|
||
|
|
||
|
|
||
|
// set the router alert option, but still set it
|
||
|
memcpy( (void *)((UCHAR *)IpHdr + sizeof(IP_HEADER)),
|
||
|
(void *)RouterAlert, sizeof(RouterAlert));
|
||
|
|
||
|
|
||
|
// send packet to all RAS clients, with the destination address in sendto
|
||
|
// set to the unicast addr of the client
|
||
|
{
|
||
|
PLIST_ENTRY pHead, ple;
|
||
|
PRAS_TABLE_ENTRY prte;
|
||
|
pHead = &pite->pRasTable->ListByAddr;
|
||
|
|
||
|
Error = NO_ERROR;
|
||
|
|
||
|
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
|
||
|
|
||
|
// get address of ras client
|
||
|
prte = CONTAINING_RECORD(ple, RAS_TABLE_ENTRY, LinkByAddr);
|
||
|
saDstnAddr.sin_addr.s_addr = prte->NHAddr;
|
||
|
|
||
|
|
||
|
// send the packet to the client
|
||
|
iLength = sendto(pite->SocketEntry.Socket, SendBufPtr,
|
||
|
SendBufLen+IpHdrLen, 0,
|
||
|
(PSOCKADDR) &saDstnAddr, sizeof(SOCKADDR_IN)
|
||
|
);
|
||
|
|
||
|
|
||
|
// print error if sendto failed
|
||
|
if ((iLength==SOCKET_ERROR) || ((DWORD)iLength<SendBufLen+IpHdrLen) ) {
|
||
|
Error = WSAGetLastError();
|
||
|
Trace4(ERR,
|
||
|
"error %d sending query to Ras client %d.%d.%d.%d on "
|
||
|
"interface %d(%d.%d.%d.%d)",
|
||
|
Error, PRINT_IPADDR(saDstnAddr.sin_addr.s_addr), pite->IfIndex,
|
||
|
PRINT_IPADDR(pite->IpAddr)
|
||
|
);
|
||
|
IgmpAssertOnError(FALSE);
|
||
|
Logwarn2(SENDTO_FAILED, "%I%I", pite->IpAddr,
|
||
|
saDstnAddr.sin_addr.s_addr, Error);
|
||
|
}
|
||
|
else {
|
||
|
Trace1(SEND, "sent general query to ras client: %d.%d.%d.%d",
|
||
|
PRINT_IPADDR(prte->NHAddr));
|
||
|
}
|
||
|
|
||
|
}//for loop:sent packet to a RAS client
|
||
|
}//sent packets to all ras clients
|
||
|
}//created IPHeader and sent packets to all ras clients
|
||
|
|
||
|
}; //for loop. send both packets
|
||
|
|
||
|
if (PacketType==MSG_SOURCES_QUERY) {
|
||
|
|
||
|
pgie->bV3SourcesQueryNow = FALSE;
|
||
|
|
||
|
// set timer for next sources query
|
||
|
if (pgie->V3SourcesQueryCount>0) {
|
||
|
|
||
|
ACQUIRE_TIMER_LOCK("_SendPacket");
|
||
|
|
||
|
#if DEBUG_TIMER_TIMERID
|
||
|
SET_TIMER_ID(&pgie->V3SourcesQueryTimer,1001, pite->IfIndex,
|
||
|
Group, 0);
|
||
|
#endif
|
||
|
|
||
|
if (IS_TIMER_ACTIVE(pgie->V3SourcesQueryTimer)) {
|
||
|
UpdateLocalTimer(&pgie->V3SourcesQueryTimer,
|
||
|
(pite->Config.LastMemQueryInterval/pite->Config.LastMemQueryCount),
|
||
|
DBG_Y);
|
||
|
}
|
||
|
else {
|
||
|
InsertTimer(&pgie->V3SourcesQueryTimer,
|
||
|
(pite->Config.LastMemQueryInterval/pite->Config.LastMemQueryCount),
|
||
|
TRUE, DBG_Y);
|
||
|
}
|
||
|
RELEASE_TIMER_LOCK("_SendPacket");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// if successful, print trace and update statistics
|
||
|
//
|
||
|
if (Error==NO_ERROR) {
|
||
|
|
||
|
if (PacketType==MSG_GEN_QUERY) {
|
||
|
|
||
|
Trace2(SEND, "Sent GenQuery on IfIndex(%0x) IpAddr(%d.%d.%d.%d)",
|
||
|
pite->IfIndex, PRINT_IPADDR(pite->IpAddr));
|
||
|
|
||
|
InterlockedIncrement(&pite->Info.GenQueriesSent);
|
||
|
}
|
||
|
else if (PacketType==MSG_GROUP_QUERY_V2 || PacketType==MSG_GROUP_QUERY_V3) {
|
||
|
Trace3(SEND,
|
||
|
"Sent Group Query on IfIndex(%0x) IpAddr(%d.%d.%d.%d) "
|
||
|
"for Group(%d.%d.%d.%d)",
|
||
|
pite->IfIndex, PRINT_IPADDR(pite->IpAddr), PRINT_IPADDR(Group));
|
||
|
|
||
|
InterlockedIncrement(&pite->Info.GroupQueriesSent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
IGMP_FREE_NOT_NULL(SendBufPtr);
|
||
|
|
||
|
Trace0(LEAVE1, "Leaving _SendPacket()");
|
||
|
return Error;
|
||
|
|
||
|
} //end _SendPacket
|
||
|
|
||
|
DWORD
|
||
|
BlockSource (
|
||
|
SOCKET Sock,
|
||
|
DWORD dwGroup,
|
||
|
DWORD IfIndex,
|
||
|
IPADDR IpAddr,
|
||
|
IPADDR Source
|
||
|
)
|
||
|
{
|
||
|
struct ip_mreq imOption;
|
||
|
DWORD Error = NO_ERROR;
|
||
|
DWORD dwRetval;
|
||
|
|
||
|
|
||
|
struct ip_mreq_source imr;
|
||
|
imr.imr_multiaddr.s_addr = dwGroup;
|
||
|
imr.imr_sourceaddr.s_addr = Source;
|
||
|
imr.imr_interface.s_addr = IpAddr;
|
||
|
dwRetval = setsockopt(Sock, IPPROTO_IP, IP_BLOCK_SOURCE,
|
||
|
(PCHAR)&imr, sizeof(imr));
|
||
|
|
||
|
if (dwRetval == SOCKET_ERROR) {
|
||
|
|
||
|
Error = WSAGetLastError();
|
||
|
|
||
|
Trace5(ERR,
|
||
|
"ERROR %d BLOCKING MULTICAST GROUP(%d.%d.%d.%d) "
|
||
|
"Source:%d.%d.%d.%d ON INTERFACE (%d) %d.%d.%d.%d",
|
||
|
Error, PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source),
|
||
|
IfIndex, PRINT_IPADDR(IpAddr));
|
||
|
IgmpAssertOnError(FALSE);
|
||
|
}
|
||
|
|
||
|
Trace2(MGM, "Blocking MCAST: (%d.%d.%d.%d) SOURCE (%d.%d.%d.%d)",
|
||
|
PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source));
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
UnBlockSource (
|
||
|
SOCKET Sock,
|
||
|
DWORD dwGroup,
|
||
|
DWORD IfIndex,
|
||
|
IPADDR IpAddr,
|
||
|
IPADDR Source
|
||
|
)
|
||
|
{
|
||
|
struct ip_mreq imOption;
|
||
|
DWORD Error = NO_ERROR;
|
||
|
DWORD dwRetval;
|
||
|
|
||
|
|
||
|
struct ip_mreq_source imr;
|
||
|
imr.imr_multiaddr.s_addr = dwGroup;
|
||
|
imr.imr_sourceaddr.s_addr = Source;
|
||
|
imr.imr_interface.s_addr = IpAddr;
|
||
|
dwRetval = setsockopt(Sock, IPPROTO_IP, IP_UNBLOCK_SOURCE,
|
||
|
(PCHAR)&imr, sizeof(imr));
|
||
|
|
||
|
if (dwRetval == SOCKET_ERROR) {
|
||
|
|
||
|
Error = WSAGetLastError();
|
||
|
|
||
|
Trace5(ERR,
|
||
|
"ERROR %d UN-BLOCKING MULTICAST GROUP(%d.%d.%d.%d) "
|
||
|
"Source:%d.%d.%d.%d ON INTERFACE (%d) %d.%d.%d.%d",
|
||
|
Error, PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source),
|
||
|
IfIndex, PRINT_IPADDR(IpAddr));
|
||
|
IgmpAssertOnError(FALSE);
|
||
|
}
|
||
|
|
||
|
Trace2(MGM, "UnBlocking MCAST: (%d.%d.%d.%d) SOURCE (%d.%d.%d.%d)",
|
||
|
PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source));
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// _JoinMulticastGroup
|
||
|
//------------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
JoinMulticastGroup (
|
||
|
SOCKET Sock,
|
||
|
DWORD dwGroup,
|
||
|
DWORD IfIndex,
|
||
|
IPADDR IpAddr,
|
||
|
IPADDR Source
|
||
|
)
|
||
|
{
|
||
|
struct ip_mreq imOption;
|
||
|
DWORD Error = NO_ERROR;
|
||
|
DWORD dwRetval;
|
||
|
|
||
|
if (Source==0) {
|
||
|
imOption.imr_multiaddr.s_addr = dwGroup;
|
||
|
imOption.imr_interface.s_addr = IpAddr;
|
||
|
|
||
|
dwRetval = setsockopt(Sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||
|
(PBYTE)&imOption, sizeof(imOption));
|
||
|
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
struct ip_mreq_source imr;
|
||
|
|
||
|
imr.imr_multiaddr.s_addr = dwGroup;
|
||
|
imr.imr_sourceaddr.s_addr = Source;
|
||
|
imr.imr_interface.s_addr = IpAddr;
|
||
|
dwRetval = setsockopt(Sock, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
|
||
|
(PCHAR)&imr, sizeof(imr));
|
||
|
}
|
||
|
|
||
|
if (dwRetval == SOCKET_ERROR) {
|
||
|
|
||
|
Error = WSAGetLastError();
|
||
|
|
||
|
Trace5(ERR,
|
||
|
"ERROR %d JOINING MULTICAST GROUP(%d.%d.%d.%d) "
|
||
|
"Source:%d.%d.%d.%d ON INTERFACE (%d) %d.%d.%d.%d",
|
||
|
Error, PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source),
|
||
|
IfIndex, PRINT_IPADDR(IpAddr));
|
||
|
IgmpAssertOnError(FALSE);
|
||
|
|
||
|
Logerr2(JOIN_GROUP_FAILED, "%I%I", dwGroup, IpAddr, Error);
|
||
|
}
|
||
|
|
||
|
Trace2(MGM, "Joining MCAST: (%d.%d.%d.%d) SOURCE (%d.%d.%d.%d)",
|
||
|
PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source));
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// _LeaveMulticastGroup
|
||
|
//------------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
LeaveMulticastGroup (
|
||
|
SOCKET Sock,
|
||
|
DWORD dwGroup,
|
||
|
DWORD IfIndex,
|
||
|
IPADDR IpAddr,
|
||
|
IPADDR Source
|
||
|
)
|
||
|
{
|
||
|
struct ip_mreq imOption;
|
||
|
DWORD Error = NO_ERROR;
|
||
|
DWORD dwRetval;
|
||
|
|
||
|
if (Source==0) {
|
||
|
imOption.imr_multiaddr.s_addr = dwGroup;
|
||
|
imOption.imr_interface.s_addr = IpAddr;
|
||
|
|
||
|
dwRetval = setsockopt(Sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
|
||
|
(PBYTE)&imOption, sizeof(imOption));
|
||
|
}
|
||
|
else {
|
||
|
struct ip_mreq_source imr;
|
||
|
|
||
|
imr.imr_multiaddr.s_addr = dwGroup;
|
||
|
imr.imr_sourceaddr.s_addr = Source;
|
||
|
imr.imr_interface.s_addr = IpAddr;
|
||
|
dwRetval = setsockopt(Sock, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP,
|
||
|
(PCHAR)&imr, sizeof(imr));
|
||
|
}
|
||
|
|
||
|
if (dwRetval == SOCKET_ERROR) {
|
||
|
|
||
|
Error = WSAGetLastError();
|
||
|
|
||
|
Trace5(ERR,
|
||
|
"error %d leaving multicast group(%d.%d.%d.%d) "
|
||
|
"Source:%d.%d.%d.%d on interface (%d) %d.%d.%d.%d",
|
||
|
Error, PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source),
|
||
|
IfIndex, PRINT_IPADDR(IpAddr));
|
||
|
IgmpAssertOnError(FALSE);
|
||
|
}
|
||
|
|
||
|
Trace2(MGM, "Leaving MCAST: (%d.%d.%d.%d) SOURCE (%d.%d.%d.%d)",
|
||
|
PRINT_IPADDR(dwGroup), PRINT_IPADDR(Source));
|
||
|
|
||
|
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);
|
||
|
IgmpAssertOnError(FALSE);
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
|
||
|
UCHAR
|
||
|
GetMaxRespCode(
|
||
|
PIF_TABLE_ENTRY pite,
|
||
|
DWORD val
|
||
|
)
|
||
|
{
|
||
|
if (IS_IF_VER1(pite))
|
||
|
return 0;
|
||
|
|
||
|
if (IS_IF_VER2(pite))
|
||
|
return val>255 ? 0 : (UCHAR)val;
|
||
|
|
||
|
//version 3
|
||
|
if (val < 128)
|
||
|
return (UCHAR)val;
|
||
|
|
||
|
{
|
||
|
DWORD n,mant, exp;
|
||
|
|
||
|
n = val;
|
||
|
exp = mant = 0;
|
||
|
while (n) {
|
||
|
exp++;
|
||
|
n = n>>1;
|
||
|
}
|
||
|
exp=exp-2-3-3;
|
||
|
mant = 15;
|
||
|
|
||
|
if ( ((mant+16)<<(exp+3)) < val)
|
||
|
exp++;
|
||
|
|
||
|
mant = (val >> (exp+3)) - 15;
|
||
|
|
||
|
IgmpAssert(mant<16 && exp <8); //deldel
|
||
|
Trace4(KSL, "\n=======exp: LMQI:%d:%d exp:%d mant:%d\n",
|
||
|
val, (mant+16)<<(exp+3), exp, mant); //deldel
|
||
|
return (UCHAR)(0x80 + (exp<<4) + mant);
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
UCHAR
|
||
|
GetQqic (
|
||
|
DWORD val
|
||
|
)
|
||
|
{
|
||
|
val = val/1000;
|
||
|
if ((val) > 31744)
|
||
|
return 0;
|
||
|
|
||
|
if (val<128)
|
||
|
return (UCHAR)val;
|
||
|
|
||
|
{
|
||
|
DWORD n,mant, exp;
|
||
|
|
||
|
n = val;
|
||
|
exp = mant = 0;
|
||
|
while (n) {
|
||
|
exp++;
|
||
|
n = n>>1;
|
||
|
}
|
||
|
exp=exp-2-3-3;
|
||
|
mant = 15;
|
||
|
|
||
|
if ( ((mant+16)<<(exp+3)) < val)
|
||
|
exp++;
|
||
|
|
||
|
mant = (val >> (exp+3)) - 15;
|
||
|
|
||
|
IgmpAssert(mant<16 && exp <8); //deldel
|
||
|
Trace4(KSL, "\n=======exp: QQic:%d:%d exp:%d mant:%d\n",
|
||
|
val, (mant+16)<<(exp+3), exp, mant); //deldel
|
||
|
return (UCHAR)(0x80 + (exp<<4) + mant);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// xsum: copied from ipxmit.c
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
USHORT
|
||
|
xsum(PVOID Buffer, INT Size)
|
||
|
{
|
||
|
USHORT UNALIGNED *Buffer1 = (USHORT UNALIGNED *)Buffer; // Buffer expressed as shorts.
|
||
|
ULONG csum = 0;
|
||
|
|
||
|
while (Size > 1) {
|
||
|
csum += *Buffer1++;
|
||
|
Size -= sizeof(USHORT);
|
||
|
}
|
||
|
|
||
|
if (Size)
|
||
|
csum += *(UCHAR *)Buffer1; // For odd buffers, add in last byte.
|
||
|
|
||
|
csum = (csum >> 16) + (csum & 0xffff);
|
||
|
csum += (csum >> 16);
|
||
|
return (USHORT)csum;
|
||
|
}
|
||
|
|
||
|
|