Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

685 lines
18 KiB

/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
mcap.c
Abstract:
ARP1394 MCAP protocol code.
Revision History:
Who When What
-------- -------- ----------------------------------------------
josephj 10-01-99 Created
Notes:
--*/
#include <precomp.h>
//
// File-specific debugging defaults.
//
#define TM_CURRENT TM_MCAP
//=========================================================================
// L O C A L P R O T O T Y P E S
//=========================================================================
NDIS_STATUS
arpParseMcapPkt(
IN PIP1394_MCAP_PKT pMcapPkt,
IN UINT cbBufferSize,
OUT PIP1394_MCAP_PKT_INFO pPktInfo
);
VOID
arpProcessMcapAdvertise(
PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
PIP1394_MCAP_PKT_INFO pPktInfo,
PRM_STACK_RECORD pSR
);
VOID
arpProcessMcapSolicit(
PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
PIP1394_MCAP_PKT_INFO pPktInfo,
PRM_STACK_RECORD pSR
);
VOID
arpUpdateMcapInfo(
IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
IN PIP1394_MCAP_PKT_INFO pPktInfo,
PRM_STACK_RECORD pSR
);
NDIS_STATUS
arpParseMcapPkt(
IN PIP1394_MCAP_PKT pMcapPkt,
IN UINT cbBufferSize,
OUT PIP1394_MCAP_PKT_INFO pPktInfo
);
NDIS_STATUS
arpParseMcapPkt(
IN PIP1394_MCAP_PKT pMcapPkt,
IN UINT cbBufferSize,
OUT PIP1394_MCAP_PKT_INFO pPktInfo
)
/*++
Routine Description:
Parse the contents of IP/1394 MCAP packet data starting at
pMcapPkt. Place the results into pPktInfo.
Arguments:
pMcapPkt - Contains the unaligned contents of an ip/1394 MCAP Pkt.
pPktInfo - Unitialized structure to be filled with the parsed contents of the
pkt.
Return Value:
NDIS_STATUS_FAILURE if the parse failed (typically because of invalid pkt
contents.)
NDIS_STATUS_SUCCESS on successful parsing.
--*/
{
ENTER("arpParseMcapPkt", 0x95175d5a)
NDIS_STATUS Status;
DBGSTMT(CHAR *szError = "General failure";)
Status = NDIS_STATUS_FAILURE;
do
{
UINT OpCode; // MCAP op code (solicit/advertise)
UINT Length; // Length of valid part of packet, including the encap header.
UINT NumGds; // Number of group_descriptors;
// Minimum size.
//
if (cbBufferSize < FIELD_OFFSET(IP1394_MCAP_PKT, group_descriptors))
{
DBGSTMT(szError = "Packet too small";)
break;
}
// Ethertype
//
if (pMcapPkt->header.EtherType != H2N_USHORT(NIC1394_ETHERTYPE_MCAP))
{
DBGSTMT(szError = "header.EtherType!=MCAP";)
break;
}
// length
//
{
// pMcapPkt->length is the length of packet excluding the unfragmented
// header.
//
Length = (ULONG) N2H_USHORT(pMcapPkt->length) + sizeof(pMcapPkt->header);
if (Length > cbBufferSize)
{
DBGSTMT(szError = "Length field too large";)
break;
}
// Note: it's valid to have zero group descriptors.
//
if (Length < FIELD_OFFSET(IP1394_MCAP_PKT, group_descriptors))
{
DBGSTMT(szError = "Length field too small";)
break;
}
}
// reserved field
//
if (pMcapPkt->reserved != 0)
{
DBGSTMT(szError = "reserved != 0";)
break;
}
// Opcode
//
{
OpCode = N2H_USHORT(pMcapPkt->opcode);
if ( OpCode != IP1394_MCAP_OP_ADVERTISE
&& OpCode != IP1394_MCAP_OP_SOLICIT)
{
DBGSTMT(szError = "Invalid opcode";)
break;
}
}
// Now we check the descriptors
//
{
PIP1394_MCAP_GD pGd;
DBGSTMT(PIP1394_MCAP_GD pGdEnd;)
UINT u;
// Note: we've already verified that Length is large enough.
//
NumGds = (Length - FIELD_OFFSET(IP1394_MCAP_PKT, group_descriptors))
/ sizeof(IP1394_MCAP_GD);
pGd = pMcapPkt->group_descriptors;
DBGSTMT(pGdEnd = (PIP1394_MCAP_GD) (((PUCHAR) pMcapPkt) + cbBufferSize);)
for (u=NumGds; u>0; u--, pGd++)
{
IP1394_MCAP_GD Gd;
ASSERT(pGd < pGdEnd);
Gd = *pGd; // Unaligned struct copy.
if (Gd.length != sizeof(Gd))
{
// bad length
//
DBGSTMT(szError = "Bad GD: bad length";)
break;
}
if (Gd.type != IP1394_MCAP_GD_TYPE_V1)
{
// bad type
//
DBGSTMT(szError = "Bad GD: bad type";)
break;
}
if (Gd.reserved != 0)
{
// bad reserved
//
DBGSTMT(szError = "Bad GD: bad reserved";)
break;
}
if (Gd.channel > 63)
{
// bad channel
//
DBGSTMT(szError = "Bad GD: bad channel";)
break;
}
// We don't check speed code to interop with unknown speeds.
// (we map unknown speeds to the highest speed code we know about.
if (Gd.reserved2 != 0)
{
// bad reserved2
//
DBGSTMT(szError = "Bad GD: bad reserved2";)
break;
}
if (Gd.bandwidth != 0)
{
// bad bandwidth
//
DBGSTMT(szError = "Bad GD: bad bandwidth";)
break;
}
{
UINT Addr = H2N_ULONG(Gd.group_address);
if ( (Addr & 0xf0000000) != 0xe0000000)
{
// Address is not class D
//
DBGSTMT(szError = "Bad GD: address not class D";)
break;
}
if (Addr == 0xe0000001 || Addr == 0xe0000002)
{
// 224.0.0.1 and 224.0.0.2 must be sent on the broadcast
// channel
//
DBGSTMT(szError = "Bad GD: Address 224.0.0.1 or 2";)
break;
}
}
}
if (u!=0)
{
break;
}
}
//
// Pkt appears valid, let's fill out the parsed information....
//
ARP_ZEROSTRUCT(pPktInfo);
pPktInfo->NumGroups = NumGds;
pPktInfo->SenderNodeID = N2H_USHORT(pMcapPkt->header.NodeId);
pPktInfo->OpCode = OpCode;
// Parse the group descriptors...
// If required, dynamically allocate space for the descriptors,
// otherwise we use pPktInfo->GdSpace;
//
{
PIP1394_MCAP_GD pGd;
PIP1394_MCAP_GD_INFO pGdi;
UINT cb = NumGds * sizeof(*pGdi);
UINT u;
if (cb <= sizeof(pPktInfo->GdiSpace))
{
pGdi = pPktInfo->GdiSpace;
}
else
{
NdisAllocateMemoryWithTag(&pGdi, cb, MTAG_MCAP_GD);
if (pGdi == NULL)
{
DBGSTMT(szError = "Allocation Failure";)
Status = NDIS_STATUS_RESOURCES;
break;
}
}
pPktInfo->pGdis = pGdi;
// Now parse...
//
pGd = pMcapPkt->group_descriptors;
for (u=NumGds; u>0; u--, pGd++, pGdi++)
{
pGdi->Expiration = pGd->expiration;
pGdi->Channel = pGd->channel;
pGdi->SpeedCode = pGd->speed;
pGdi->GroupAddress = pGd->group_address; // Leave in Network order
if (pGdi->Channel >= ARP_NUM_CHANNELS)
{
TR_INFO(("Bad channel in GD 0x%p\n", pGdi));
continue;
}
//
// Although RFC doesn't stipulate a max expiry time, we
// cap it ourselves, in case this is a rogue packet.
//
#define MAX_EXPIRATION 120
if (pGdi->Expiration >= MAX_EXPIRATION)
{
TR_INFO(("Capping expiry time to %d sec\n", MAX_EXPIRATION));
pGdi->Expiration = MAX_EXPIRATION;
continue;
}
if (pGdi->SpeedCode > SCODE_3200_RATE)
{
//
// This is either a bad value, or a rate higher than we know
// about. We can't distinguish between the two, so we just set
// the speed to the highest we know about.
//
pGdi->SpeedCode = SCODE_3200_RATE;
}
}
}
Status = NDIS_STATUS_SUCCESS;
} while (FALSE);
if (FAIL(Status))
{
TR_WARN(("Bad mcap pkt data at 0x%p (%s)\n", pMcapPkt, szError));
}
else
{
#if DBG
UINT Addr = 0;
UINT Channel = 0;
UINT Exp = 0;
PUCHAR pc = (PUCHAR) &Addr;
if (pPktInfo->NumGroups!=0)
{
Addr = pPktInfo->pGdis[0].GroupAddress;
Channel = pPktInfo->pGdis[0].Channel;
Exp = pPktInfo->pGdis[0].Expiration;
}
#endif // DBG
TR_WARN(("Received MCAP PKT. NodeId=0x%04lx NumGrps=%lu."
" 1st=(Grp=%lu.%lu.%lu.%lu, Ch=%lu, TTL=%lu)\n",
pPktInfo->SenderNodeID,
pPktInfo->NumGroups,
pc[0], pc[1], pc[2], pc[3],
Channel,
Exp
));
}
EXIT()
return Status;
}
NDIS_STATUS
arpCreateMcapPkt(
IN PARP1394_INTERFACE pIF,
IN PIP1394_MCAP_PKT_INFO pPktInfo,
OUT PNDIS_PACKET *ppNdisPacket,
PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Use information in pPktInfo to allocate and initialize an mcap packet.
Arguments:
pPktInfo - Parsed version of the arp request/response packet.
ppNdisPacket - Points to a place to store a pointer to the allocated packet.
Return Value:
NDIS_STATUS_RESOURCES - If we couldn't allocate the packet.
NDIS_STATUS_SUCCESS - on success.
--*/
{
UINT NumGroups;
UINT Length;
NDIS_STATUS Status;
PIP1394_MCAP_PKT pPktData;
PIP1394_MCAP_GD pGd;
NumGroups = pPktInfo->NumGroups;
Length = FIELD_OFFSET(IP1394_MCAP_PKT, group_descriptors);
Length += NumGroups * sizeof(IP1394_MCAP_GD);
Status = arpAllocateControlPacket(
pIF,
Length,
ARP1394_PACKET_FLAGS_MCAP,
ppNdisPacket,
&pPktData,
pSR
);
if (FAIL(Status)) return Status; // ***** EARLY RETURN ******
// Can't use ARP_ZEROSTRUCT because NumGroups may be zero.
//
NdisZeroMemory(pPktData, Length);
pPktData->header.EtherType = H2N_USHORT(NIC1394_ETHERTYPE_MCAP);
pPktData->opcode = (UCHAR)pPktInfo->OpCode;
Length -= sizeof(pPktData->header); // Skip the header.
pPktData->length = H2N_USHORT(Length);
// Construct the group descriptors.
//
if (NumGroups)
{
PIP1394_MCAP_GD_INFO pGdi = pPktInfo->pGdis;
PIP1394_MCAP_GD pGd = pPktData->group_descriptors;
for(;NumGroups; pGdi++, pGd++, NumGroups--)
{
ARP_ZEROSTRUCT(pGd);
pGd->length = (UCHAR) sizeof(*pGd);
pGd->expiration = (UCHAR) pGdi->Expiration;
pGd->channel = (UCHAR) pGdi->Channel;
pGd->speed = (UCHAR) pGdi->SpeedCode;
pGd->group_address = pGdi->GroupAddress;
}
}
return NDIS_STATUS_SUCCESS;
}
#if 0
// Parsed version of the IP/1394 MCAP Group Descriptor
//
typedef struct
{
UINT Expiration;
UINT Channel;
UINT SpeedCode;
IP_ADDRESS GroupAddress;
} IP1394_MCAP_GD_INFO, * PIP1394_MCAP_GD_INFO;
// Parsed version of an IP/1394 MCAP packet.
//
typedef struct
{
UINT SenderNodeID;
UINT OpCode;
UINT NumGroups;
PIP1394_MCAP_GD_INFO pGdis;
// Space for storing up-to 4 GD_INFOs
//
IP1394_MCAP_GD_INFO GdiSpace[4];
} IP1394_MCAP_PKT_INFO, *PIP1394_MCAP_PKT_INFO;
#endif // 0
VOID
arpUpdateMcapInfo(
IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
IN PIP1394_MCAP_PKT_INFO pPktInfo,
PRM_STACK_RECORD pSR
)
{
ENTER("arpUpdateMcapInfo", 0xcac15343)
PIP1394_MCAP_GD_INFO pGdi;
UINT NumGroups;
UINT Current;
UINT NodeId;
RM_DECLARE_STACK_RECORD(sr)
RM_ASSERT_OBJUNLOCKED(&pIF->Hdr, pSR);
// Get the current time (in seconds).
//
Current = arpGetSystemTime();
//
// Go through the group discriptors, updating our database.
//
NumGroups = pPktInfo->NumGroups;
pGdi = pPktInfo->pGdis;
NodeId = pPktInfo->SenderNodeID;
for(;NumGroups; pGdi++, NumGroups--)
{
UINT Expiration = pGdi->Expiration;
UINT Channel = pGdi->Channel;
IP_ADDRESS GroupAddress = pGdi->GroupAddress;
PMCAP_CHANNEL_INFO pMci;
//
// Process this group descriptor.
//
if (Channel >= ARP_NUM_CHANNELS)
{
ASSERT(FALSE); // we should have already screened this value.
continue;
}
LOCKOBJ(pIF, &sr);
pMci = &pIF->mcapinfo.rgChannelInfo[Channel];
pMci->Channel = Channel;
pMci->GroupAddress = GroupAddress;
pMci->UpdateTime = Current;
pMci->ExpieryTime = Current + Expiration; // Expiration is in seconds.
pMci->Flags = 0; // Reset flags.
pMci->NodeId = NodeId; // TODO: check if existing node id is higher?
UNLOCKOBJ(pIF, &sr);
}
RM_ASSERT_OBJUNLOCKED(&pIF->Hdr, pSR);
}
VOID
arpProcessMcapPkt(
PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
PIP1394_MCAP_PKT pMcapPkt,
UINT cbBufferSize
)
{
NDIS_STATUS Status;
IP1394_MCAP_PKT_INFO PktInfo;
ENTER("arpProcessMcapPkt", 0xc5ba8005)
RM_DECLARE_STACK_RECORD(sr)
DBGMARK(0x3cfaf454);
Status = arpParseMcapPkt(
pMcapPkt,
cbBufferSize,
&PktInfo
);
if (!FAIL(Status))
{
if (PktInfo.OpCode == IP1394_MCAP_OP_ADVERTISE)
{
arpProcessMcapAdvertise(pIF, &PktInfo, &sr);
}
else
{
ASSERT(PktInfo.OpCode == IP1394_MCAP_OP_SOLICIT);
arpProcessMcapSolicit(pIF, &PktInfo, &sr);
}
}
RM_ASSERT_CLEAR(&sr);
EXIT()
}
VOID
arpProcessMcapAdvertise(
PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
PIP1394_MCAP_PKT_INFO pPktInfo,
PRM_STACK_RECORD pSR
)
{
//
// Update our database.
//
arpUpdateMcapInfo(
pIF, // NOLOCKIN NOLOCKOUT
pPktInfo,
pSR
);
}
VOID
arpProcessMcapSolicit(
PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
PIP1394_MCAP_PKT_INFO pPktInfo,
PRM_STACK_RECORD pSR
)
{
//
// We ignore solicit messages.
//
//
}
MYBOOL
arpIsActiveMcapChannel(
PMCAP_CHANNEL_INFO pMci,
UINT CurrentTime
)
{
ENTER("IsActiveMcapChannel", 0x0)
MYBOOL fOk = TRUE;
// Check update time.
//
#define ARP_MAX_MCAP_UPDATE_INTERVAL 60
if ((pMci->UpdateTime+ARP_MAX_MCAP_UPDATE_INTERVAL) < CurrentTime)
{
TR_WARN(("McapDB: channel %lu update time crossed.\n",
pMci->Channel
));
fOk = FALSE;
}
// Check expire time.
//
if (pMci->ExpieryTime <= CurrentTime)
{
TR_WARN(("McapDB: channel %lu time expired.\n",
pMci->Channel
));
fOk = FALSE;
}
return fOk;
}
VOID
arpLocallyUpdateMcapInfo(
PARP1394_INTERFACE pIF,
UINT Channel,
UINT GroupAddress,
UINT CurrentTime,
PRM_STACK_RECORD pSR
)
{
ENTER("arpLocallyUpdateMcapInfo", 0x0)
PMCAP_CHANNEL_INFO pMci;
LOCKOBJ(pIF, pSR);
pMci = &pIF->mcapinfo.rgChannelInfo[Channel];
pMci->Channel = Channel;
pMci->GroupAddress = GroupAddress;
pMci->UpdateTime = CurrentTime;
pMci->ExpieryTime = CurrentTime + 60; // Expiration is in seconds.
pMci->Flags = 0; // Reset flags.
pMci->NodeId = 0; // NodeId; // TODO: get real node id.
UNLOCKOBJ(pIF, pSR);
}