|
|
/*++
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;
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); }
|