xbox-kernel/private/ntos/xnet/ip/igmp.c
2020-09-30 17:17:25 +02:00

295 lines
5.8 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
igmp.c
Abstract:
Handle IGMP protocol version 2
Revision History:
05/31/2000 davidx
Created it.
--*/
#include "precomp.h"
VOID
IgmpSendMessage(
IfInfo* ifp,
IPADDR dstaddr,
BYTE type,
IPADDR groupaddr
)
/*++
Routine Description:
Send out an IGMP report or leave message
Arguments:
ifp - Points to the interface structure
dstaddr - Specifies the message's destination address
type - Message type
groupaddr - Address of the multicast group in question
Return Value:
NONE
--*/
{
Packet* pkt;
IgmpMessage* igmpmsg;
IpHeader* iphdr;
pkt = XnetAllocIpPacket(0, IGMPHDRLEN);
if (!pkt) return;
igmpmsg = GETPKTDATA(pkt, IgmpMessage);
igmpmsg->type = type;
igmpmsg->maxresptime = 0;
igmpmsg->groupaddr = groupaddr;
COMPUTE_CHECKSUM(igmpmsg->checksum, igmpmsg, IGMPHDRLEN);
iphdr = GETPKTIPHDR(pkt);
pkt->data -= IPHDRLEN;
pkt->datalen += IPHDRLEN;
pkt->nexthop = dstaddr;
FILL_IPHEADER(
iphdr,
IPHDRLEN,
0,
pkt->datalen,
0,
1,
IPPROTOCOL_IGMP,
ifp->ipaddr,
dstaddr);
// Queue up the packet for transmission
IfEnqueuePacket(ifp, pkt);
ifp->StartOutput(ifp);
}
PRIVATE VOID
IgmpSetQueryReportTimer(
IfInfo* ifp,
IfMcastGroup* mcastgrp,
UINT maxresptime
)
/*++
Routine Description:
Set the query report timer on a multicast group we belong to.
Arguments:
ifp - Points to the interface structure
mcastgrp - Points to the multicast group in question
maxresptime - Specifies the maximum response time in 1/10 of a second
Return Value:
NONE
--*/
{
// If existing timer value is less than the new max response time,
// then we just leave the existing timer alone.
if (mcastgrp->reportTimer && mcastgrp->reportTimer*10 <= maxresptime)
return;
// Randomize the response timer
maxresptime = XnetRandScaled(maxresptime) / 10;
if ((mcastgrp->reportTimer = maxresptime) == 0) {
IgmpSendReport(ifp, mcastgrp);
}
}
PRIVATE VOID
IgmpProcessMessage(
IfInfo* ifp,
IgmpMessage* igmpmsg,
IPADDR dstaddr
)
/*++
Routine Description:
Process a received IGMP message
Arguments:
ifp - Points to the interface structure
igmpmsg - Points to the received IGMP message
dstaddr - Destination group the message is addressed to
Return Value:
NONE
Note:
This function will only be called when the interface
belongs to the message's destination address group.
--*/
#define LOCATE_MCASTGROUP() \
while (count--) { \
if (mcastgrp->mcastaddr == dstaddr) break; \
mcastgrp++; \
}
{
IfMcastData* ifmcast = ifp->mcastData;
IfMcastGroup* mcastgrp = ifmcast->mcastGroups;
UINT count = ifmcast->groupCount;
IPADDR grpaddr = igmpmsg->groupaddr;
switch (igmpmsg->type) {
case IGMPTYPE_MEMBER_QUERY:
if (grpaddr == 0) {
UINT maxresptime;
// General query must be directed to all-hosts address
if (dstaddr != IPADDR_ALLHOSTS) return;
if (igmpmsg->maxresptime == 0) {
ifmcast->hasV1Querier = TRUE;
ifmcast->v1QuerierTimer = IGMP_V1_QUERIER_TIMER;
maxresptime = IGMP_V1_QUERY_RESPONSE*10;
} else
maxresptime = igmpmsg->maxresptime;
while (count--) {
IgmpSetQueryReportTimer(ifp, mcastgrp, maxresptime);
mcastgrp++;
}
} else {
// Group-specific query must directed to that group address
if (dstaddr != grpaddr) return;
LOCATE_MCASTGROUP();
IgmpSetQueryReportTimer(ifp, mcastgrp, igmpmsg->maxresptime);
}
break;
case IGMPTYPE_MEMBER_REPORT_1:
case IGMPTYPE_MEMBER_REPORT_2:
// Membership report must be sent to the specific group
if (dstaddr != grpaddr) return;
LOCATE_MCASTGROUP();
mcastgrp->reportTimer = 0;
mcastgrp->sentLastReport = FALSE;
break;
}
}
VOID
IgmpReceivePacket(
Packet* pkt
)
/*++
Routine Description:
Receive an IGMP packet
Arguments:
pkt - Points to the received IGMP message
Return Value:
NONE
--*/
{
RUNS_AT_DISPATCH_LEVEL
// Verify packet length and checksum
if (pkt->datalen < IGMPHDRLEN ||
tcpipxsum(0, pkt->data, pkt->datalen) != 0xffff) {
XnetCompletePacket(pkt, NETERR_DISCARDED);
return;
}
// We're only interested in packets addressed
// to the all-host multicast group here.
if (pkt->recvifp->mcastData) {
IgmpProcessMessage(
pkt->recvifp,
GETPKTDATA(pkt, IgmpMessage),
GETPKTIPHDR(pkt)->dstaddr);
}
// Pass the packet upstream for further processing
RawReceivePacket(pkt);
}
VOID
IgmpTimerProc(
IfInfo* ifp
)
/*++
Routine Description:
IGMP timer procedure
Arguments:
ifp - Points to the interface structure
Return Value:
NONE
--*/
{
IfMcastData* ifmcast = ifp->mcastData;
IfMcastGroup* mcastgrp;
UINT count;
ASSERT(ifmcast != NULL);
if (ifmcast->v1QuerierTimer && --(ifmcast->v1QuerierTimer) == 0)
ifmcast->hasV1Querier = FALSE;
mcastgrp = ifmcast->mcastGroups;
count = ifmcast->groupCount;
while (count--) {
if (mcastgrp->reportTimer && --(mcastgrp->reportTimer) == 0) {
IgmpSendReport(ifp, mcastgrp);
}
mcastgrp++;
}
}