5131 lines
142 KiB
C
5131 lines
142 KiB
C
/*++
|
|
|
|
Copyright (c) 1998-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ip.c
|
|
|
|
Abstract:
|
|
|
|
ARP1394 IP-related handlers.
|
|
|
|
Revision History:
|
|
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
josephj 01-06-98 Created (adapted from atmarpc.sys, arpif.c)
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
#include <precomp.h>
|
|
|
|
//
|
|
// File-specific debugging defaults.
|
|
//
|
|
#define TM_CURRENT TM_IP
|
|
|
|
#define CLASSA_MASK 0x000000ff
|
|
#define CLASSB_MASK 0x0000ffff
|
|
#define CLASSC_MASK 0x00ffffff
|
|
#define CLASSD_MASK 0x000000e0
|
|
#define CLASSE_MASK 0xffffffff
|
|
|
|
|
|
|
|
|
|
//=========================================================================
|
|
// L O C A L P R O T O T Y P E S
|
|
//=========================================================================
|
|
|
|
ULONG ArpSendCompletes = 0;
|
|
ULONG ArpSends = 0;
|
|
ULONG ArpSendFailure = 0;
|
|
|
|
|
|
#define LOGSTATS_SendFifoCounts(_pIF, _pNdisPacket, _Status) \
|
|
arpLogSendFifoCounts(_pIF, _pNdisPacket, _Status)
|
|
#define LOGSTATS_SendChannelCounts(_pIF, _pNdisPacket, _Status) \
|
|
arpLogSendChannelCounts(_pIF, _pNdisPacket, _Status)
|
|
#define LOGSTATS_TotalArpCacheLookups(_pIF, _Status) \
|
|
NdisInterlockedIncrement(&((_pIF)->stats.arpcache.TotalLookups))
|
|
|
|
const
|
|
NIC1394_ENCAPSULATION_HEADER
|
|
Arp1394_IpEncapHeader =
|
|
{
|
|
0x0000, // Reserved
|
|
H2N_USHORT(NIC1394_ETHERTYPE_IP)
|
|
};
|
|
|
|
//
|
|
// ZZZ This is a little-endian specific check.
|
|
//
|
|
#define ETH_IS_MULTICAST(Address) \
|
|
(BOOLEAN)(((PUCHAR)(Address))[0] & ((UCHAR)0x01))
|
|
|
|
|
|
//
|
|
// Check whether an address is broadcast.
|
|
//
|
|
#define ETH_IS_BROADCAST(Address) \
|
|
((((PUCHAR)(Address))[0] == ((UCHAR)0xff)) && (((PUCHAR)(Address))[1] == ((UCHAR)0xff)))
|
|
|
|
VOID
|
|
arpReStartInterface(
|
|
IN PNDIS_WORK_ITEM pWorkItem,
|
|
IN PVOID IfContext
|
|
);
|
|
|
|
VOID
|
|
arpInitializeLocalIp(
|
|
IN ARPCB_LOCAL_IP * pLocalIp, // LOCKIN NOLOCKOUT
|
|
IN UINT AddressType,
|
|
IN IP_ADDRESS IpAddress,
|
|
IN IP_MASK Mask,
|
|
IN PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
VOID
|
|
arpUnloadLocalIp(
|
|
IN ARPCB_LOCAL_IP * pLocalIp, // LOCKIN NOLOCKOUT
|
|
IN PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
INT
|
|
arpQueryIpEntityId(
|
|
ARP1394_INTERFACE * pIF,
|
|
IN UINT EntityType,
|
|
IN PNDIS_BUFFER pNdisBuffer,
|
|
IN OUT PUINT pBufferSize,
|
|
PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
VOID
|
|
nicGetMacAddressFromEuid (
|
|
UINT64 *pEuid,
|
|
ENetAddr *pMacAddr
|
|
);
|
|
|
|
INT
|
|
arpQueryIpAddrXlatInfo(
|
|
ARP1394_INTERFACE * pIF,
|
|
IN PNDIS_BUFFER pNdisBuffer,
|
|
IN OUT PUINT pBufferSize,
|
|
PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
INT
|
|
arpQueryIpAddrXlatEntries(
|
|
ARP1394_INTERFACE * pIF,
|
|
IN PNDIS_BUFFER pNdisBuffer,
|
|
IN OUT PUINT pBufferSize,
|
|
IN PVOID QueryContext,
|
|
PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
INT
|
|
arpQueryIpMibStats(
|
|
ARP1394_INTERFACE * pIF,
|
|
IN PNDIS_BUFFER pNdisBuffer,
|
|
IN OUT PUINT pBufferSize,
|
|
PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
PNDIS_BUFFER
|
|
arpCopyToNdisBuffer(
|
|
IN PNDIS_BUFFER pDestBuffer,
|
|
IN PUCHAR pDataSrc,
|
|
IN UINT LenToCopy,
|
|
IN OUT PUINT pOffsetInBuffer
|
|
);
|
|
|
|
VOID
|
|
arpSendIpPkt(
|
|
IN ARP1394_INTERFACE * pIF, // LOCKIN NOLOCKOUT (IF send lk)
|
|
IN PARPCB_DEST pDest,
|
|
IN PNDIS_PACKET pNdisPacket
|
|
);
|
|
|
|
VOID
|
|
arpAddRce(
|
|
IN ARPCB_REMOTE_IP *pRemoteIp,
|
|
IN RouteCacheEntry *pRCE,
|
|
IN PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
VOID
|
|
arpDelRce(
|
|
IN RouteCacheEntry *pRce, // IF send lock WRITELOCKIN WRITELOCKOUTD
|
|
IN PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
NDIS_STATUS
|
|
arpTaskSendPktsOnRemoteIp(
|
|
IN struct _RM_TASK * pTask,
|
|
IN RM_TASK_OPERATION Code,
|
|
IN UINT_PTR UserParam, // Unused
|
|
IN PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
VOID
|
|
arpTryResumeSuspendedCleanupTask(
|
|
IN ARP1394_INTERFACE * pIF,
|
|
IN ARPCB_DEST * pDest
|
|
);
|
|
|
|
VOID
|
|
arpQueuePktOnRemoteIp(
|
|
IN ARPCB_REMOTE_IP * pRemoteIp, // LOCKIN LOCKOUT
|
|
IN PNDIS_PACKET pNdisPacket,
|
|
IN PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
VOID
|
|
arpSendPktsQueuedOnRemoteIp(
|
|
IN ARP1394_INTERFACE * pIF, // NOLOCKIN NOLOCKOUT
|
|
IN ARPCB_REMOTE_IP * pRemoteIp, // NOLOCKIN NOLOCKOUT
|
|
IN PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
MYBOOL
|
|
arpIsNonUnicastIpAddress(
|
|
IN PARP1394_INTERFACE pIF, // LOCKIN LOCKOUT
|
|
IN IP_ADDRESS Addr,
|
|
IN PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
MYBOOL
|
|
arpIsNonUnicastEthAddress (
|
|
IN PARP1394_INTERFACE pIF, // LOCKIN LOCKOUT
|
|
IN ENetAddr* pAddr,
|
|
IN PRM_STACK_RECORD pSR
|
|
);
|
|
|
|
VOID
|
|
arpLoopbackNdisPacket(
|
|
IN PARP1394_INTERFACE pIF,
|
|
IN PARPCB_DEST pBroadcastDest,
|
|
IN PNDIS_PACKET pOldPacket
|
|
);
|
|
|
|
|
|
|
|
//=========================================================================
|
|
// I P H A N D L E R S
|
|
//=========================================================================
|
|
|
|
|
|
INT
|
|
ArpIpDynRegister(
|
|
IN PNDIS_STRING pAdapterString,
|
|
IN PVOID IpContext,
|
|
IN struct _IP_HANDLERS * pIpHandlers,
|
|
IN struct LLIPBindInfo * pBindInfo,
|
|
IN UINT InterfaceNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called from the IP layer when it wants to tell us,
|
|
the ARP module, about its handlers for an Interface.
|
|
|
|
Arguments:
|
|
|
|
pAdapterString - Name of the logical adapter for this interface
|
|
IpContext - IP's context for this interface
|
|
pIpHandlers - Points to struct containing the IP handlers
|
|
pBindInfo - Pointer to bind info with our information
|
|
InterfaceNumber - ID for this interface
|
|
|
|
Return Value:
|
|
|
|
TRUE always.
|
|
|
|
--*/
|
|
{
|
|
ENTER("IfDynRegister", 0xc1b569b9)
|
|
ARP1394_INTERFACE* pIF;
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
pIF = (ARP1394_INTERFACE*)(pBindInfo->lip_context);
|
|
|
|
TR_INFO(("pIF 0x%p\n", pIF));
|
|
ASSERT(pIF->Hdr.Sig == MTAG_INTERFACE);
|
|
|
|
LOCKOBJ(pIF, &sr);
|
|
|
|
//
|
|
// TODO: fail if we're not in a position to do this -- such as when shutting
|
|
// down.
|
|
//
|
|
|
|
pIF->ip.Context = IpContext;
|
|
pIF->ip.RcvHandler = pIpHandlers->IpRcvHandler;
|
|
pIF->ip.TxCmpltHandler = pIpHandlers->IpTxCompleteHandler;
|
|
pIF->ip.StatusHandler = pIpHandlers->IpStatusHandler;
|
|
pIF->ip.TDCmpltHandler = pIpHandlers->IpTransferCompleteHandler;
|
|
pIF->ip.RcvCmpltHandler = pIpHandlers->IpRcvCompleteHandler;
|
|
pIF->ip.PnPEventHandler = pIpHandlers->IpPnPHandler;
|
|
pIF->ip.RcvPktHandler = pIpHandlers->IpRcvPktHandler;
|
|
pIF->ip.IFIndex = InterfaceNumber;
|
|
|
|
UNLOCKOBJ(pIF, &sr);
|
|
//
|
|
RM_ASSERT_CLEAR(&sr);
|
|
EXIT()
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpIpOpen(
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when IP is ready to use this interface.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a pointer to our ARP394_INTERFACE structure
|
|
|
|
--*/
|
|
{
|
|
ARP1394_INTERFACE* pIF;
|
|
ENTER("ArpIpOpen", 0x7cae1e55)
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
TR_INFO(("Enter. pContext = 0x%p\n", Context));
|
|
|
|
pIF = (ARP1394_INTERFACE*) Context;
|
|
|
|
// Validate context.
|
|
//
|
|
ASSERT(pIF->Hdr.Sig == MTAG_INTERFACE);
|
|
|
|
LOCKOBJ(pIF, &sr);
|
|
|
|
// Get the local HW address if we don't have it yet
|
|
//
|
|
{
|
|
// TODO (this is from ip/atm -- I think in our case we can assume we have
|
|
// it?)
|
|
}
|
|
|
|
// Mark interface as open.
|
|
//
|
|
{
|
|
ASSERT(CHECK_IF_IP_STATE(pIF, ARPIF_IPS_CLOSED));
|
|
SET_IF_IP_STATE(pIF, ARPIF_IPS_OPEN);
|
|
pIF->stats.LastChangeTime = GetTimeTicks();
|
|
|
|
}
|
|
|
|
#if ARP_WMI
|
|
//
|
|
// Register interface with WMI
|
|
//
|
|
// TODO
|
|
#endif // ARP_WMI
|
|
|
|
// Record the fact that we're open, to verify that the IF is closed before
|
|
// the IF block is deallocated.
|
|
//
|
|
DBG_ADDASSOC(&pIF->Hdr, NULL, NULL, ARPASSOC_IP_OPEN, " IP IF Open\n", &sr);
|
|
|
|
UNLOCKOBJ(pIF, &sr);
|
|
|
|
RM_ASSERT_CLEAR(&sr);
|
|
EXIT()
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
ArpIpClose(
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IP wants to stop using this Interface.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a pointer to our ARP1394_INTERFACE structure
|
|
|
|
--*/
|
|
{
|
|
ARP1394_INTERFACE * pIF = (ARP1394_INTERFACE*) Context;
|
|
PRM_TASK pTask;
|
|
BOOLEAN fResumeTask = FALSE;
|
|
ENTER("ArpIpClose", 0xdb8c8216)
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
TR_INFO(("Enter. pContext = 0x%p\n", Context));
|
|
ASSERT(pIF->Hdr.Sig == MTAG_INTERFACE);
|
|
|
|
LOCKOBJ(pIF, &sr);
|
|
|
|
//
|
|
//Set state to closed.
|
|
//
|
|
|
|
SET_IF_IP_STATE(pIF, ARPIF_IPS_CLOSED);
|
|
pIF->stats.LastChangeTime= GetTimeTicks();
|
|
|
|
|
|
// (delete "ARPASSOC_IP_OPEN" association added in arpIpOpen)
|
|
//
|
|
DBG_DELASSOC(&pIF->Hdr, NULL, NULL, ARPASSOC_IP_OPEN, &sr);
|
|
|
|
// If there is a shutdown task pending, we notify it
|
|
// Note: a task is protected by it's parent object's lock, which is
|
|
// pIF in the case of the init and shutdown-interface tasks.
|
|
//
|
|
pTask = pIF->pActDeactTask;
|
|
if (pTask && pTask->pfnHandler == arpTaskDeactivateInterface)
|
|
{
|
|
TASK_DEACTIVATE_IF *pShutdownTask =
|
|
(TASK_DEACTIVATE_IF *) pTask;
|
|
if (pShutdownTask->fPendingOnIpClose)
|
|
{
|
|
ASSERT(pIF->ip.Context == NULL);
|
|
RmTmpReferenceObject(&pTask->Hdr, &sr);
|
|
fResumeTask = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Hmm... unsolicited IpClose. We don't expect this currently.
|
|
//
|
|
ASSERT(FALSE);
|
|
pIF->ip.Context = NULL;
|
|
}
|
|
}
|
|
|
|
UNLOCKOBJ(pIF, &sr);
|
|
|
|
if (fResumeTask)
|
|
{
|
|
RmResumeTask(pTask, (UINT_PTR) 0, &sr);
|
|
RmTmpDereferenceObject(&pTask->Hdr, &sr);
|
|
}
|
|
|
|
RM_ASSERT_CLEAR(&sr);
|
|
EXIT()
|
|
}
|
|
|
|
|
|
UINT
|
|
ArpIpAddAddress(
|
|
IN PVOID Context,
|
|
IN UINT AddressType,
|
|
IN IP_ADDRESS IpAddress,
|
|
IN IP_MASK Mask,
|
|
IN PVOID Context2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The IP layer calls this when a new IP address (or block of IP addresses,
|
|
as determined by AddressType) needs to be added to an Interface.
|
|
|
|
We could see any of four address types: Local, Multicast, Broadcast
|
|
and Proxy ARP. In the case of Proxy ARP, the address along with the mask
|
|
can specify a block of contiguous IP addresses for which this host acts
|
|
as a proxy. Currently, we only support the "Local", "Broadcast", and
|
|
"Multicast" types.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a pointer to our structure
|
|
AddressType - Type of address(es) being added.
|
|
IpAddress - Address to be added.
|
|
Mask - For the above.
|
|
Context2 - Additional context (We ignore this)
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
ARP1394_INTERFACE * pIF = (ARP1394_INTERFACE*) Context;
|
|
ENTER("ArpIpAddAddress", 0xd6630961)
|
|
INT fCreated = FALSE;
|
|
ARPCB_LOCAL_IP *pLocalIp = NULL;
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
TR_INFO(("Enter. pIF = 0x%p\n", pIF));
|
|
ASSERT(pIF->Hdr.Sig == MTAG_INTERFACE);
|
|
|
|
#if OBSOLETE // Instead, we grab IF lock and don't specify the RM_LOCK flag.
|
|
// See notes.txt entry "03/05/1999 More corny locking problems"
|
|
//
|
|
// WARNING: We SHOULD NOT grab the IF lock, because we request that
|
|
// the pLocalIp's lock be grabbed in RmLookupObjectInGroup below,
|
|
// AND the pLocalIp's lock is actually the same as the IF lock.
|
|
// (This is asserted later on below).
|
|
// So obviously we can't get the IF lock here! (And we don't need to either).
|
|
//
|
|
#endif
|
|
LOCKOBJ(pIF, &sr);
|
|
|
|
// We're not yet in the open state -- we're "opening", so we don't assert...
|
|
// ASSERT(!CHECK_IF_OPEN_STATE(pIF, ARPIF_CLOSED));
|
|
|
|
do
|
|
{
|
|
//
|
|
// Note: we could just as well have done the initialiation as part of
|
|
// the creation of the LocalIpObject itself, by passing in all the
|
|
// required initialization params in the pvCreateParams arg to
|
|
// RmLookupObjectInGroup. Instead we choose to do the initialization
|
|
// ourselves. Things are more explicit this way.
|
|
//
|
|
|
|
// Unfortunately, to do this we must first validate the args...
|
|
//
|
|
if (AddressType != LLIP_ADDR_BCAST &&
|
|
AddressType != LLIP_ADDR_MCAST &&
|
|
AddressType != LLIP_ADDR_LOCAL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Status = RmLookupObjectInGroup(
|
|
&pIF->LocalIpGroup,
|
|
RM_CREATE,
|
|
(PVOID) ULongToPtr (IpAddress), // pKey
|
|
(PVOID) ULongToPtr (IpAddress), // pvCreateParams
|
|
&(PRM_OBJECT_HEADER)pLocalIp,
|
|
&fCreated,
|
|
&sr
|
|
);
|
|
if (FAIL(Status)) break;
|
|
|
|
//
|
|
// NOTE: we already have claimed the pIF lock, which
|
|
// which is the same as the pIF lock.
|
|
//
|
|
RM_ASSERT_SAME_LOCK_AS_PARENT(pLocalIp);
|
|
|
|
// (Dbg only) Change lock scope from pIF to pLocalIp.
|
|
//
|
|
RmDbgChangeLockScope(
|
|
&pIF->Hdr,
|
|
&pLocalIp->Hdr,
|
|
0x9cbc0b52, // LocID
|
|
&sr
|
|
);
|
|
|
|
if (fCreated)
|
|
{
|
|
|
|
if (AddressType == LLIP_ADDR_BCAST)
|
|
{
|
|
// Update the interface's broadcast address...
|
|
//
|
|
pIF->ip.BroadcastAddress = IpAddress;
|
|
}
|
|
else if (AddressType == LLIP_ADDR_LOCAL)
|
|
{
|
|
// Update the interface's default local IP address.
|
|
// TODO: need to find another one if this address is removed.
|
|
//
|
|
pIF->ip.DefaultLocalAddress = IpAddress;
|
|
}
|
|
|
|
|
|
|
|
arpInitializeLocalIp(
|
|
pLocalIp,
|
|
AddressType,
|
|
IpAddress,
|
|
Mask,
|
|
&sr
|
|
);
|
|
//
|
|
// pLocalIp's lock is released above (which is actually the IF lock).
|
|
//
|
|
RM_ASSERT_NOLOCKS(&sr);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Hmm... this IP address already existed. Apparently it's possible for
|
|
// MCAST addreses (IP/ATM arp module dealt with this for the MCAST case).
|
|
// We don't special-case LOCAL/BCAST/MCAST addresses at this stage,
|
|
// so we support multiple adds for all types of local IP addresses.
|
|
//
|
|
ASSERTEX(pLocalIp->AddAddressCount>0, pLocalIp);
|
|
pLocalIp->AddAddressCount++;
|
|
}
|
|
|
|
RmTmpDereferenceObject(&pLocalIp->Hdr, &sr);
|
|
|
|
} while (FALSE);
|
|
|
|
TR_INFO((
|
|
"IF 0x%p, Type %d, Addr %d.%d.%d.%d, Mask 0x%p, pLocIp 0x%p, Ret %d\n",
|
|
pIF,
|
|
AddressType,
|
|
((PUCHAR)(&IpAddress))[0],
|
|
((PUCHAR)(&IpAddress))[1],
|
|
((PUCHAR)(&IpAddress))[2],
|
|
((PUCHAR)(&IpAddress))[3],
|
|
Mask, pLocalIp, !FAIL(Status)));
|
|
|
|
RmUnlockAll(&sr);
|
|
|
|
RM_ASSERT_CLEAR(&sr);
|
|
EXIT()
|
|
|
|
return !FAIL(Status);
|
|
|
|
}
|
|
|
|
|
|
UINT
|
|
ArpIpDelAddress(
|
|
IN PVOID Context,
|
|
IN UINT AddressType,
|
|
IN IP_ADDRESS IpAddress,
|
|
IN IP_MASK Mask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called from the IP layer when an address added via ArpIpAddAddress
|
|
is to be deleted.
|
|
|
|
Assumption: the given address was successfully added earlier.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a pointer to our Interface structure
|
|
AddressType - Type of address(es) being deleted.
|
|
IpAddress - Address to be deleted.
|
|
Mask - For the above.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
ARP1394_INTERFACE * pIF = (ARP1394_INTERFACE*) Context;
|
|
ENTER("ArpIpDelAddress", 0xd6630961)
|
|
ARPCB_LOCAL_IP *pLocalIp = NULL;
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
TR_INFO(("Enter. pIF = 0x%p\n", Context));
|
|
ASSERT(pIF->Hdr.Sig == MTAG_INTERFACE);
|
|
|
|
#if OBSOLETE // See ArpIpAddAddress
|
|
//
|
|
// WARNING: We SHOULD NOT grab the IF lock, because we request that
|
|
// the pLocalIp's lock be grabbed in RmLookupObjectInGroup below,
|
|
// AND the pLocalIp's lock is actually the same as the IF lock.
|
|
// (This is asserted later on below).
|
|
// So obviously we can't get the IF lock here! (And we don't need to either).
|
|
//
|
|
#endif // OBSOLETE
|
|
|
|
LOCKOBJ(pIF, &sr);
|
|
|
|
ASSERT(!CHECK_IF_IP_STATE(pIF, ARPIF_IPS_CLOSED));
|
|
|
|
do
|
|
{
|
|
|
|
Status = RmLookupObjectInGroup(
|
|
&pIF->LocalIpGroup,
|
|
0, // Flags
|
|
(PVOID) ULongToPtr (IpAddress), // pKey
|
|
NULL, // pvCreateParams
|
|
&(PRM_OBJECT_HEADER)pLocalIp,
|
|
NULL, // pfCreated
|
|
&sr
|
|
);
|
|
if (FAIL(Status))
|
|
{
|
|
UNLOCKOBJ(pIF, &sr);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// NOTE: we have the pLocalIp lock, which is the same as the pIF lock.
|
|
//
|
|
RM_ASSERT_SAME_LOCK_AS_PARENT(pLocalIp);
|
|
|
|
// (Dbg only) Change lock scope from pIF to pLocalIp.
|
|
//
|
|
RmDbgChangeLockScope(
|
|
&pIF->Hdr,
|
|
&pLocalIp->Hdr,
|
|
0x188ed5b3, // LocID
|
|
&sr
|
|
);
|
|
|
|
if (pLocalIp->AddAddressCount <= 1)
|
|
{
|
|
ASSERTEX(pLocalIp->AddAddressCount == 1, pLocalIp);
|
|
|
|
arpUnloadLocalIp(
|
|
pLocalIp,
|
|
&sr
|
|
);
|
|
//
|
|
// pLocalIp's lock is released above.
|
|
//
|
|
RM_ASSERT_NOLOCKS(&sr);
|
|
}
|
|
else
|
|
{
|
|
pLocalIp->AddAddressCount--;
|
|
UNLOCKOBJ(pLocalIp, &sr);
|
|
}
|
|
|
|
RmTmpDereferenceObject(&pLocalIp->Hdr, &sr);
|
|
|
|
} while (FALSE);
|
|
|
|
TR_INFO((
|
|
"IF 0x%p, Type %d, Addr %d.%d.%d.%d, Mask 0x%p, pLocIp 0x%p, Ret %d\n",
|
|
pIF,
|
|
AddressType,
|
|
((PUCHAR)(&IpAddress))[0],
|
|
((PUCHAR)(&IpAddress))[1],
|
|
((PUCHAR)(&IpAddress))[2],
|
|
((PUCHAR)(&IpAddress))[3],
|
|
Mask, pLocalIp, !FAIL(Status)));
|
|
|
|
RM_ASSERT_CLEAR(&sr);
|
|
EXIT()
|
|
return !FAIL(Status);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ArpIpMultiTransmit(
|
|
IN PVOID Context,
|
|
IN PNDIS_PACKET * pNdisPacketArray,
|
|
IN UINT NumberOfPackets,
|
|
IN IP_ADDRESS Destination,
|
|
IN RouteCacheEntry * pRCE OPTIONAL,
|
|
IN void * ArpCtxt
|
|
)
|
|
/*++
|
|
|
|
TODO: implement send array-of-packets. Currenty we just call
|
|
ArpIpTransmit multiple times. We'll gain a few cycles by processing
|
|
all at once, although it's not going to be a big gain, because we're pretty
|
|
fast with the single-packet case, provided the RCE is valid.
|
|
|
|
Routine Description:
|
|
|
|
This is called from the IP layer when it has a sequence of datagrams,
|
|
each in the form of an NDIS buffer chain, to send over an Interface.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a pointer to our Interface structure
|
|
pNdisPacketArray - Array of Packets to be sent on this Interface
|
|
NumberOfPackets - Length of array
|
|
Destination - IP address of next hop for this packet
|
|
pRCE - Optional pointer to Route Cache Entry structure.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_PENDING if all packets were queued for transmission.
|
|
If one or more packets "failed", we set the packet status to reflect
|
|
what happened to each, and return NDIS_STATUS_FAILURE.
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
PNDIS_PACKET * ppNdisPacket;
|
|
|
|
for (ppNdisPacket = pNdisPacketArray;
|
|
NumberOfPackets > 0;
|
|
NumberOfPackets--, ppNdisPacket++)
|
|
{
|
|
PNDIS_PACKET pNdisPacket;
|
|
|
|
pNdisPacket = *ppNdisPacket;
|
|
NDIS_SET_PACKET_STATUS(pNdisPacket, NDIS_STATUS_PENDING);
|
|
ASSERTEX(pNdisPacket->Private.Head != NULL, pNdisPacket);
|
|
|
|
Status = ArpIpTransmit(
|
|
Context,
|
|
*ppNdisPacket,
|
|
Destination,
|
|
pRCE
|
|
,NULL
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NDIS_SET_PACKET_STATUS(*ppNdisPacket, Status);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ArpIpTransmit(
|
|
IN PVOID Context,
|
|
IN PNDIS_PACKET pNdisPacket,
|
|
IN IP_ADDRESS Destination,
|
|
IN RouteCacheEntry * pRCE OPTIONAL,
|
|
IN void * ArpCtxt
|
|
)
|
|
/*++
|
|
|
|
HOT PATH
|
|
|
|
Routine Description:
|
|
|
|
This is called from the IP layer when it has a datagram (in the form of
|
|
an NDIS buffer chain) to send over an Interface.
|
|
|
|
The destination IP address is passed to us in this routine, which may
|
|
or may not be the final destination for the packet.
|
|
|
|
The Route Cache Entry is created by the IP layer, and is used to speed
|
|
up our lookups. An RCE, if specified, uniquely identifies atleast the
|
|
IP destination for this packet. The RCE contains space for the ARP layer
|
|
to keep context information about this destination. When the first packet
|
|
goes out to a Destination, our context info in the RCE will be NULL, and
|
|
we search the ARP Table for the matching IP Entry. However, we then fill
|
|
our context info (pointer to IP Entry) in the RCE, so that subsequent
|
|
transmits aren't slowed down by an IP address lookup.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a pointer to our Interface structure
|
|
pNdisPacket - Packet to be sent on this Interface
|
|
Destination - IP address of next hop for this packet
|
|
pRCE - Optional pointer to Route Cache Entry structure.
|
|
|
|
Return Value:
|
|
|
|
Status of the transmit: NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING, or
|
|
a failure.
|
|
|
|
--*/
|
|
{
|
|
ARP1394_INTERFACE * pIF = (ARP1394_INTERFACE*) Context;
|
|
ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) RM_PARENT_OBJECT(pIF );
|
|
NDIS_STATUS Status;
|
|
REMOTE_DEST_KEY DestinationKey;
|
|
ARP_INIT_REENTRANCY_COUNT()
|
|
ENTER("IfTransmit", 0x46f1973e)
|
|
|
|
ARP_INC_REENTRANCY();
|
|
ASSERT_VALID_INTERFACE(pIF);
|
|
|
|
// IP does sometimes call this function before we set our state to OPEN,
|
|
// so this is an incorrect assert...
|
|
// ASSERT(!CHECK_IF_IP_STATE(pIF, ARPIF_IPS_CLOSED));
|
|
|
|
TR_INFO((
|
|
"pIf 0x%p, Pkt 0x%p, Dst 0x%p, pRCE 0x%p\n",
|
|
pIF, pNdisPacket, Destination, pRCE));
|
|
|
|
DBGMARK(0xf87d7fff);
|
|
NdisInterlockedIncrement (&ArpSends);
|
|
|
|
// Since we don't hold any locks, this check is approximate, but it should
|
|
// prevent lots of useless activity while we're trying to shutdown.
|
|
//
|
|
// Check for not Inited Or Low Power
|
|
if (!CHECK_IF_PRIMARY_STATE(pIF, ARPIF_PS_INITED) ||
|
|
(! CHECK_POWER_STATE(pAdapter, ARPAD_POWER_NORMAL) ))
|
|
|
|
{
|
|
TR_INFO(("Failing ArpIpTransmit because pIF 0x%p is closing.\n", pIF));
|
|
|
|
ARP_DEC_REENTRANCY();
|
|
NdisInterlockedIncrement (&ArpSendCompletes);
|
|
NdisInterlockedIncrement (&ArpSendFailure);
|
|
return NDIS_STATUS_FAILURE; // EARLY_RETURN
|
|
}
|
|
|
|
#define LOGSTATS_TotSends(_pIF, _pNdisPacket) \
|
|
NdisInterlockedIncrement(&((_pIF)->stats.sendpkts.TotSends))
|
|
|
|
#define LOGSTATS_SetPktTimestamp(_pIF, _pNdisPacket) \
|
|
{ \
|
|
LARGE_INTEGER liTemp = KeQueryPerformanceCounter(NULL); \
|
|
*(PULONG) ((_pNdisPacket)->WrapperReservedEx) = liTemp.LowPart; \
|
|
}
|
|
|
|
LOGSTATS_TotSends(pIF, pNdisPacket);
|
|
LOGSTATS_SetPktTimestamp(pIF, pNdisPacket);
|
|
|
|
//
|
|
// If there is a RCE, we'll try to quickly get all the information we need
|
|
// and send off the packet. If we can't do this, we resort to the
|
|
// "slow send path" (call arpIpSlowtransmit)...
|
|
//
|
|
if (pRCE != NULL)
|
|
{
|
|
ARP_RCE_CONTEXT * pArpRceContext;
|
|
ARPCB_REMOTE_IP * pRemoteIp;
|
|
|
|
pArpRceContext = ARP_OUR_CTXT_FROM_RCE(pRCE);
|
|
|
|
ARP_FASTREADLOCK_IF_SEND_LOCK(pIF);
|
|
|
|
pRemoteIp = pArpRceContext->pRemoteIp;
|
|
|
|
//
|
|
// Validate the Remote Ip. If it not meant for this packet
|
|
// fall back to the slow path
|
|
//
|
|
if (pRemoteIp != NULL && pRemoteIp->IpAddress == Destination)
|
|
{
|
|
ARPCB_DEST * pDest;
|
|
|
|
pDest = pRemoteIp->pDest;
|
|
if (pDest != NULL )
|
|
{
|
|
//
|
|
// Note: pDest->sendinfo is protected by the IF send lock.
|
|
//
|
|
if (ARP_CAN_SEND_ON_DEST(pDest))
|
|
{
|
|
|
|
#define LOGSTATS_FastSends(_pIF, _pNdisPacket) \
|
|
NdisInterlockedIncrement(&((_pIF)->stats.sendpkts.FastSends))
|
|
|
|
LOGSTATS_FastSends(pIF, pNdisPacket);
|
|
|
|
arpSendIpPkt(pIF, pDest, pNdisPacket);
|
|
//
|
|
// IF Send lock released above.
|
|
|
|
ARP_DEC_REENTRANCY();
|
|
return NDIS_STATUS_PENDING; // EARLY RETURN
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if we have a mismatched RCE , then the RCE should be ignored
|
|
// i,e. not be propagated to the SlowIpTransmit.
|
|
//
|
|
if (pRemoteIp != NULL && pRemoteIp->IpAddress != Destination)
|
|
{
|
|
pRCE = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If we get here, it's on to slow path...
|
|
//
|
|
ARP_FASTUNLOCK_IF_SEND_LOCK(pIF);
|
|
|
|
}
|
|
|
|
// The slow path...
|
|
//
|
|
REMOTE_DEST_KEY_INIT(&DestinationKey);
|
|
DestinationKey.IpAddress = Destination;
|
|
Status = arpSlowIpTransmit(
|
|
pIF,
|
|
pNdisPacket,
|
|
DestinationKey,
|
|
pRCE
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
LOGSTATS_SendFifoCounts(pIF, pNdisPacket, Status);
|
|
}
|
|
|
|
ARP_DEC_REENTRANCY();
|
|
EXIT()
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ArpIpTransfer(
|
|
IN PVOID Context,
|
|
IN NDIS_HANDLE Context1,
|
|
IN UINT ArpHdrOffset,
|
|
IN UINT ProtoOffset,
|
|
IN UINT BytesWanted,
|
|
IN PNDIS_PACKET pNdisPacket,
|
|
OUT PUINT pTransferCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called from the IP layer in order to copy in the
|
|
contents of a received packet that we indicated up earlier. The
|
|
context we had passed up in the receive indication is given back to
|
|
us, so that we can identify what it was that we passed up.
|
|
|
|
We simply call NDIS to do the transfer.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a pointer to our Interface structure
|
|
Context1 - Packet context we had passed up (pointer to NDIS packet)
|
|
ArpHdrOffset - Offset we had passed up in the receive indicate
|
|
ProtoOffset - The offset into higher layer protocol data to start copy from
|
|
BytesWanted - The amount of data to be copied
|
|
pNdisPacket - The packet to be copied into
|
|
pTransferCount - Where we return the actual #bytes copied
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS always.
|
|
|
|
--*/
|
|
{
|
|
ENTER("IfTransfer", 0xa084562c)
|
|
|
|
TR_INFO((
|
|
"Ctx 0x%p, Ctx1 0x%p, HdrOff %d, ProtOff %d, Wanted %d, Pkt 0x%p\n",
|
|
Context,
|
|
Context1,
|
|
ArpHdrOffset,
|
|
ProtoOffset,
|
|
BytesWanted,
|
|
pNdisPacket));
|
|
|
|
NdisCopyFromPacketToPacket(
|
|
pNdisPacket,
|
|
0,
|
|
BytesWanted,
|
|
(PNDIS_PACKET)Context1,
|
|
ArpHdrOffset+ProtoOffset,
|
|
pTransferCount
|
|
);
|
|
|
|
EXIT()
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpIpInvalidate(
|
|
IN PVOID Context,
|
|
IN RouteCacheEntry * pRCE
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called from the IP layer to invalidate a Route Cache
|
|
Entry. If this RCE is associated with one of our IP Entries, unlink
|
|
it from the list of RCE's pointing to that IP entry.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a pointer to our Interface structure
|
|
pRCE - Pointer to Route Cache Entry being invalidated.
|
|
|
|
--*/
|
|
{
|
|
ARP1394_INTERFACE * pIF = (ARP1394_INTERFACE*) Context;
|
|
ENTER("ArpIpInvalidate", 0xee77fb09)
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
TR_INFO(("Enter. pIF = 0x%p pRCE=0x%p\n", pIF, pRCE));
|
|
|
|
ASSERT_VALID_INTERFACE(pIF);
|
|
ASSERT(pRCE != NULL);
|
|
|
|
DBGMARK(0xe35c780d);
|
|
|
|
ARP_WRITELOCK_IF_SEND_LOCK(pIF, &sr);
|
|
arpDelRce(pRCE, &sr);
|
|
ARP_UNLOCK_IF_SEND_LOCK(pIF, &sr);
|
|
|
|
RM_ASSERT_CLEAR(&sr);
|
|
EXIT()
|
|
|
|
|
|
}
|
|
|
|
|
|
INT
|
|
ArpIpQueryInfo(
|
|
IN PVOID Context,
|
|
IN TDIObjectID * pID,
|
|
IN PNDIS_BUFFER pNdisBuffer,
|
|
IN OUT PUINT pBufferSize,
|
|
IN PVOID QueryContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called from the IP layer to query for statistics or other
|
|
information about an interface.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a pointer to our Interface
|
|
pID - Describes the object being queried
|
|
pNdisBuffer - Space for returning information
|
|
pBufferSize - Pointer to size of above. On return, we fill
|
|
it with the actual bytes copied.
|
|
QueryContext - Context value pertaining to the query.
|
|
|
|
Return Value:
|
|
|
|
TDI Status code.
|
|
|
|
--*/
|
|
{
|
|
UINT EntityType;
|
|
UINT Instance;
|
|
INT ReturnStatus;
|
|
ARP1394_INTERFACE * pIF = (ARP1394_INTERFACE*) Context;
|
|
ENTER("ArpIpQueryInfo", 0x15059be1)
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
|
|
EntityType = pID->toi_entity.tei_entity;
|
|
Instance = pID->toi_entity.tei_instance;
|
|
|
|
|
|
TR_VERB((
|
|
"IfQueryInfo: pIf 0x%p, pID 0x%p, pBuf 0x%p, Size %d, Ent %d, Inst %d\n",
|
|
pIF, pID, pNdisBuffer, *pBufferSize, EntityType, Instance));
|
|
ASSERT(pIF->Hdr.Sig == MTAG_INTERFACE);
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
ReturnStatus = TDI_INVALID_PARAMETER;
|
|
|
|
LOCKOBJ(pIF, &sr);
|
|
|
|
do
|
|
{
|
|
if (!CHECK_IF_PRIMARY_STATE(pIF, ARPIF_PS_INITED))
|
|
{
|
|
if (!CHECK_IF_ACTIVE_STATE(pIF, ARPIF_AS_ACTIVATING))
|
|
{
|
|
ReturnStatus = TDI_INVALID_REQUEST;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check the Entity and Instance values.
|
|
//
|
|
|
|
if ((EntityType != AT_ENTITY || Instance != pIF->ip.ATInstance) &&
|
|
(EntityType != IF_ENTITY || Instance != pIF->ip.IFInstance))
|
|
{
|
|
TR_INFO(
|
|
("Mismatch: Entity %d, AT_ENTITY %d, Inst %d, IF AT Inst %d, IF_ENTITY %d, IF IF Inst %d\n",
|
|
EntityType,
|
|
AT_ENTITY,
|
|
Instance,
|
|
pIF->ip.ATInstance,
|
|
IF_ENTITY,
|
|
pIF->ip.IFInstance
|
|
));
|
|
|
|
ReturnStatus = TDI_INVALID_REQUEST;
|
|
break;
|
|
}
|
|
|
|
|
|
TR_VERB(("QueryInfo: pID 0x%p, toi_type %d, toi_class %d, toi_id %d\n",
|
|
pID, pID->toi_type, pID->toi_class, pID->toi_id));
|
|
|
|
|
|
if (pID->toi_type != INFO_TYPE_PROVIDER)
|
|
{
|
|
TR_INFO(("toi_type %d != PROVIDER (%d)\n",
|
|
pID->toi_type,
|
|
INFO_TYPE_PROVIDER));
|
|
|
|
break;
|
|
}
|
|
|
|
if (pID->toi_class == INFO_CLASS_GENERIC)
|
|
{
|
|
if (pID->toi_id == ENTITY_TYPE_ID)
|
|
{
|
|
ReturnStatus = arpQueryIpEntityId(
|
|
pIF,
|
|
EntityType,
|
|
pNdisBuffer,
|
|
pBufferSize,
|
|
&sr
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (EntityType == AT_ENTITY)
|
|
{
|
|
//
|
|
// This query is for an Address Translation Object.
|
|
//
|
|
if (pID->toi_id == AT_MIB_ADDRXLAT_INFO_ID)
|
|
{
|
|
ReturnStatus = arpQueryIpAddrXlatInfo(
|
|
pIF,
|
|
pNdisBuffer,
|
|
pBufferSize,
|
|
&sr
|
|
);
|
|
}
|
|
else if (pID->toi_id == AT_MIB_ADDRXLAT_ENTRY_ID)
|
|
{
|
|
ReturnStatus = arpQueryIpAddrXlatEntries(
|
|
pIF,
|
|
pNdisBuffer,
|
|
pBufferSize,
|
|
QueryContext,
|
|
&sr
|
|
);
|
|
}
|
|
else
|
|
{
|
|
ReturnStatus = TDI_INVALID_PARAMETER;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ( pID->toi_class == INFO_CLASS_PROTOCOL
|
|
&& pID->toi_id == IF_MIB_STATS_ID)
|
|
{
|
|
ReturnStatus = arpQueryIpMibStats(
|
|
pIF,
|
|
pNdisBuffer,
|
|
pBufferSize,
|
|
&sr
|
|
);
|
|
}
|
|
}
|
|
while (FALSE);
|
|
|
|
if ( ReturnStatus != TDI_SUCCESS
|
|
&& ReturnStatus != TDI_BUFFER_OVERFLOW
|
|
&& ReturnStatus != TDI_INVALID_REQUEST)
|
|
{
|
|
//
|
|
// This again preserves the semantics of QueryInfo from atmarpc.sys...
|
|
//
|
|
*pBufferSize = 0;
|
|
}
|
|
|
|
TR_VERB(("Returning 0x%p (%s), BufferSize %d\n",
|
|
ReturnStatus,
|
|
((ReturnStatus == TDI_SUCCESS)? "SUCCESS": "FAILURE"),
|
|
*pBufferSize
|
|
));
|
|
|
|
UNLOCKOBJ(pIF, &sr);
|
|
RM_ASSERT_CLEAR(&sr);
|
|
EXIT()
|
|
|
|
return (ReturnStatus);
|
|
}
|
|
|
|
|
|
INT
|
|
ArpIpSetInfo(
|
|
IN PVOID Context,
|
|
IN TDIObjectID * pID,
|
|
IN PVOID pBuffer,
|
|
IN UINT BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called from the IP layer to set the value of an object
|
|
for an interface.
|
|
|
|
Arguments:
|
|
Context - Actually a pointer to our Interface
|
|
pID - Describes the object being set
|
|
pBuffer - Value for the object
|
|
BufferSize - Size of above
|
|
|
|
Return Value:
|
|
|
|
TDI Status code.
|
|
|
|
--*/
|
|
{
|
|
ARP1394_INTERFACE *pIF = (ARP1394_INTERFACE*) Context;
|
|
UINT Entity, Instance;
|
|
IFEntry *pIFE = (IFEntry *) pBuffer;
|
|
NTSTATUS ReturnStatus = TDI_INVALID_REQUEST;
|
|
IPNetToMediaEntry *IPNME = NULL;
|
|
|
|
ENTER("IpSetInfo", 0x05dabea3)
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
//
|
|
// This code is taken from the tcpip Arp module with some changes to adjust
|
|
// it to arp1394's internal structures
|
|
//
|
|
// This code only supports deleting Arp Entries
|
|
//
|
|
|
|
Entity = pID->toi_entity.tei_entity;
|
|
Instance = pID->toi_entity.tei_instance;
|
|
|
|
|
|
do
|
|
{
|
|
|
|
// First, make sure it's possibly an ID we can handle.
|
|
if (Entity != AT_ENTITY || Instance != pIF->ip.ATInstance)
|
|
{
|
|
TR_INFO(
|
|
("Mismatch: Entity %d, AT_ENTITY %d, Inst %d, IF AT Inst %d, IF_ENTITY %d, IF IF Inst %d\n",
|
|
Entity,
|
|
AT_ENTITY,
|
|
Instance,
|
|
pIF->ip.ATInstance,
|
|
IF_ENTITY,
|
|
pIF->ip.IFInstance
|
|
));
|
|
|
|
ReturnStatus = TDI_INVALID_REQUEST;
|
|
break;
|
|
}
|
|
|
|
|
|
if (pID->toi_type != INFO_TYPE_PROVIDER) {
|
|
ReturnStatus = TDI_INVALID_REQUEST;
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
if (pID->toi_id != AT_MIB_ADDRXLAT_ENTRY_ID ||
|
|
BufferSize < sizeof(IPNetToMediaEntry))
|
|
{
|
|
ReturnStatus = TDI_INVALID_REQUEST;
|
|
break;
|
|
}
|
|
|
|
// He does want to set an ARP table entry. See if he's trying to
|
|
// create or delete one.
|
|
|
|
IPNME = (IPNetToMediaEntry *) pBuffer;
|
|
|
|
if (IPNME->inme_type != INME_TYPE_INVALID)
|
|
{
|
|
|
|
ReturnStatus = TDI_INVALID_REQUEST;
|
|
break;
|
|
|
|
}
|
|
|
|
// We need to delete the IP address passed in the ipnme struct
|
|
|
|
ReturnStatus = arpDelArpEntry (pIF, IPNME->inme_addr, &sr);
|
|
|
|
|
|
}while (FALSE);
|
|
|
|
|
|
|
|
return ReturnStatus; // TBD: support Sets.
|
|
EXIT();
|
|
|
|
}
|
|
|
|
|
|
|
|
INT
|
|
ArpIpGetEList(
|
|
IN PVOID Context,
|
|
IN TDIEntityID * pEntityList,
|
|
IN OUT PUINT pEntityListSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when the interface starts up, in order to
|
|
assign all relevant Entity Instance numbers for an interface.
|
|
The ARP1394 module belongs to the "AT" and "IF" types. The entity
|
|
list is a list of <Entity type, Instance number> tuples that have
|
|
been filled in by other modules.
|
|
|
|
For each of the entity types we support, we find the largest
|
|
instance number in use (by walking thru the Entity list), and
|
|
assign to ourselves the next larger number in each case. Using
|
|
these numbers, we append our tuples to the end of the Entity list,
|
|
if there is enough space.
|
|
|
|
W2K: we may find that our entries are already present, in which
|
|
case we don't create new entries.
|
|
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a pointer to our ARP1394_INTERFACE
|
|
pEntityList - Pointer to TDI Entity list
|
|
pEntityListSize - Pointer to length of above list. We update
|
|
this if we add our entries to the list.
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
ARP1394_INTERFACE * pIF = (ARP1394_INTERFACE*) Context;
|
|
UINT EntityCount; // Total elements in Entity list
|
|
UINT i; // Iteration counter
|
|
UINT MyATInstance; // "AT" Instance number we assign to ourselves
|
|
UINT MyIFInstance; // "IF" Instance number we assign to ourselves
|
|
INT ReturnValue;
|
|
TDIEntityID * pATEntity; // Points to our AT entry
|
|
TDIEntityID * pIFEntity; // Points to our IF entry
|
|
ENTER("ArpIpGetEList", 0x8b5190e5)
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
ASSERT(pIF->Hdr.Sig == MTAG_INTERFACE);
|
|
EntityCount = *pEntityListSize;
|
|
pATEntity = NULL;
|
|
pIFEntity = NULL;
|
|
MyATInstance = MyIFInstance = 0;
|
|
|
|
TR_INFO(("IfGetEList: pIf 0x%p, &pIF.ip 0x%p pList 0x%p, Cnt %d\n",
|
|
pIF, &pIF->ip, pEntityList, EntityCount));
|
|
|
|
LOCKOBJ(pIF, &sr);
|
|
|
|
do
|
|
{
|
|
//
|
|
// Walk down the list, looking for AT/IF entries matching our
|
|
// instance values. Also remember the largest AT and IF instance
|
|
// values we see, so that we can allocate the next larger values
|
|
// for ourselves, in case we don't have instance values assigned.
|
|
//
|
|
for (i = 0; i < EntityCount; i++, pEntityList++)
|
|
{
|
|
//
|
|
// Skip invalid entries.
|
|
//
|
|
if (pEntityList->tei_instance == INVALID_ENTITY_INSTANCE)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (pEntityList->tei_entity == AT_ENTITY)
|
|
{
|
|
if (pEntityList->tei_instance == pIF->ip.ATInstance)
|
|
{
|
|
//
|
|
// This is our AT entry.
|
|
//
|
|
pATEntity = pEntityList;
|
|
}
|
|
else
|
|
{
|
|
if (MyATInstance < (pEntityList->tei_instance + 1))
|
|
{
|
|
MyATInstance = pEntityList->tei_instance + 1;
|
|
}
|
|
}
|
|
}
|
|
else if (pEntityList->tei_entity == IF_ENTITY)
|
|
{
|
|
if (pEntityList->tei_instance == pIF->ip.IFInstance)
|
|
{
|
|
//
|
|
// This is our IF entry.
|
|
//
|
|
pIFEntity = pEntityList;
|
|
}
|
|
else
|
|
{
|
|
if (MyIFInstance < (pEntityList->tei_instance + 1))
|
|
{
|
|
MyIFInstance = pEntityList->tei_instance + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ReturnValue = TRUE;
|
|
|
|
// WARNING: The following check is subtle -- we MUST set the instance
|
|
// values to INVALID_ENTITY_INSTANCE when the interface is being
|
|
// deactivated, but we MUST NOT do this if the interface is just opened
|
|
// (ArpIpOpen called) -- otherwise we could mess up the caller's state
|
|
// to such an extent that a reboot is required. Basically our behaviour
|
|
// here is what results in the proper acquiring AND release of instance IDs.
|
|
//
|
|
// So don't replace the following check by checking for
|
|
// ARPIF_PS_INITED or ARPIF_IPS_OPEN or even ARPIF_PS_DEINITING.
|
|
// The latter check (ARPIF_PS_DEINITING) would have been ok except for the
|
|
// fact that the IF is deactivated/reactivated during ARPIF_PS_REINITING
|
|
// as well, so the correct check is basically the one below...
|
|
//
|
|
//
|
|
if(CHECK_IF_ACTIVE_STATE(pIF, ARPIF_AS_DEACTIVATING))
|
|
{
|
|
//
|
|
// We're deactivating the interface, set values to invalid and
|
|
// get out of here...
|
|
//
|
|
|
|
if (pATEntity)
|
|
{
|
|
pATEntity->tei_instance = INVALID_ENTITY_INSTANCE;
|
|
}
|
|
|
|
if (pIFEntity)
|
|
{
|
|
pIFEntity->tei_instance = INVALID_ENTITY_INSTANCE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Update or create our Address Translation entry.
|
|
//
|
|
if (pATEntity)
|
|
{
|
|
//
|
|
// We found our entry, nothing to do...
|
|
//
|
|
TR_INFO(("YOWZA: Found existing AT entry.\n"));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Grab an entry for ourselves...
|
|
//
|
|
TR_INFO(("YOWZA: Grabbing new AT entry 0x%lu.\n", MyATInstance));
|
|
|
|
if (EntityCount >= MAX_TDI_ENTITIES)
|
|
{
|
|
ReturnValue = FALSE;
|
|
break;
|
|
}
|
|
|
|
pEntityList->tei_entity = AT_ENTITY;
|
|
pEntityList->tei_instance = MyATInstance;
|
|
pIF->ip.ATInstance = MyATInstance;
|
|
|
|
pEntityList++;
|
|
(*pEntityListSize)++;
|
|
EntityCount++;
|
|
}
|
|
|
|
//
|
|
// Update or create or IF entry.
|
|
//
|
|
if (pIFEntity)
|
|
{
|
|
//
|
|
// We found our entry, nothing to do...
|
|
//
|
|
TR_INFO(("YOWZA: Found existing IF entry.\n"));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Grab an entry for ourselves.
|
|
//
|
|
TR_INFO(("YOWZA: Grabbing new IF entry 0x%lu.\n", MyIFInstance));
|
|
|
|
if (EntityCount >= MAX_TDI_ENTITIES)
|
|
{
|
|
ReturnValue = FALSE;
|
|
break;
|
|
}
|
|
|
|
pEntityList->tei_entity = IF_ENTITY;
|
|
pEntityList->tei_instance = MyIFInstance;
|
|
pIF->ip.IFInstance = MyIFInstance;
|
|
|
|
pEntityList++;
|
|
(*pEntityListSize)++;
|
|
EntityCount++;
|
|
}
|
|
}
|
|
while (FALSE);
|
|
|
|
|
|
TR_INFO(
|
|
("IfGetEList: returning %d, MyAT %d, MyIF %d, pList 0x%p, Size %d\n",
|
|
ReturnValue, MyATInstance, MyIFInstance, pEntityList, *pEntityListSize));
|
|
|
|
UNLOCKOBJ(pIF, &sr);
|
|
RM_ASSERT_CLEAR(&sr);
|
|
EXIT()
|
|
return (ReturnValue);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
ArpIpPnPComplete(
|
|
IN PVOID Context,
|
|
IN NDIS_STATUS Status,
|
|
IN PNET_PNP_EVENT pNetPnPEvent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by IP when it completes a previous call
|
|
we made to its PnP event handler. We complete the
|
|
NDIS PNP notification that lead to this.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a pointer to our ATMARP Interface
|
|
Status - Completion status from IP
|
|
pNetPnPEvent - The PNP event
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ENTER("ArpIpPnPComplete", 0x23b1941e)
|
|
PARP1394_INTERFACE pIF;
|
|
|
|
pIF = (PARP1394_INTERFACE) Context;
|
|
|
|
TR_INFO(("IfPnPComplete: IF 0x%p, Status 0x%p, Event 0x%p\n",
|
|
pIF, Status, pNetPnPEvent));
|
|
|
|
if (pIF == NULL)
|
|
{
|
|
NdisCompletePnPEvent(
|
|
Status,
|
|
NULL,
|
|
pNetPnPEvent
|
|
);
|
|
}
|
|
else
|
|
{
|
|
PARP1394_ADAPTER pAdapter;
|
|
ASSERT_VALID_INTERFACE(pIF);
|
|
pAdapter = (PARP1394_ADAPTER) RM_PARENT_OBJECT(pIF);
|
|
NdisCompletePnPEvent(
|
|
Status,
|
|
pAdapter->bind.AdapterHandle,
|
|
pNetPnPEvent
|
|
);
|
|
}
|
|
|
|
EXIT()
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#ifdef PROMIS
|
|
EXTERN
|
|
NDIS_STATUS
|
|
ArpIpSetNdisRequest(
|
|
IN PVOID Context,
|
|
IN NDIS_OID Oid,
|
|
IN UINT On
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ARP Ndisrequest handler.
|
|
Called by the upper driver to set the packet filter for the interface.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a pointer to our ATMARP Interface
|
|
OID - Object ID to set/unset
|
|
On - Set_if, clear_if or clear_card
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
return NDIS_STATUS_FAILURE;
|
|
#if 0
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
PATMARP_INTERFACE pInterface = (PATMARP_INTERFACE)Context;
|
|
|
|
AADEBUGP(AAD_INFO,("IfSetNdisRequest: pIF =0x%p; Oid=0x%p; On=%u\n",
|
|
pInterface,
|
|
Oid,
|
|
On
|
|
));
|
|
|
|
do
|
|
{
|
|
//
|
|
// We set IPAddress and mask to span the entire mcast address range...
|
|
//
|
|
IP_ADDRESS IPAddress = IP_CLASSD_MIN;
|
|
IP_MASK Mask = IP_CLASSD_MASK;
|
|
UINT ReturnStatus = TRUE;
|
|
NDIS_OID PrevOidValue;
|
|
|
|
if (Oid != NDIS_PACKET_TYPE_ALL_MULTICAST)
|
|
{
|
|
Status = NDIS_STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
PrevOidValue = pInterface->EnabledIPFilters & NDIS_PACKET_TYPE_ALL_MULTICAST;
|
|
|
|
if (On)
|
|
{
|
|
if (PrevOidValue == 0)
|
|
{
|
|
pInterface->EnabledIPFilters |= NDIS_PACKET_TYPE_ALL_MULTICAST;
|
|
|
|
ReturnStatus = AtmArpMcAddAddress(pInterface, IPAddress, Mask);
|
|
//
|
|
// IF lock released above
|
|
//
|
|
}
|
|
else
|
|
{
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (PrevOidValue != 0)
|
|
{
|
|
pInterface->EnabledIPFilters &= ~NDIS_PACKET_TYPE_ALL_MULTICAST;
|
|
|
|
ReturnStatus = AtmArpMcDelAddress(pInterface, IPAddress, Mask);
|
|
//
|
|
// IF lock released above
|
|
//
|
|
}
|
|
else
|
|
{
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
}
|
|
|
|
if (ReturnStatus != TRUE)
|
|
{
|
|
//
|
|
// We've got to restore EnabledIPFilters to it's original value.
|
|
//
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
pInterface->EnabledIPFilters &= ~NDIS_PACKET_TYPE_ALL_MULTICAST;
|
|
pInterface->EnabledIPFilters |= PrevOidValue;
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
AADEBUGP(AAD_INFO, ("IfSetNdisRequest(pIF =0x%p) returns 0x%p\n",
|
|
pInterface,
|
|
Status
|
|
));
|
|
|
|
return Status;
|
|
#endif // 0
|
|
}
|
|
#endif // PROMIS
|
|
|
|
|
|
VOID
|
|
arpInitializeLocalIp(
|
|
IN ARPCB_LOCAL_IP * pLocalIp, // LOCKIN NOLOCKOUT
|
|
IN UINT AddressType,
|
|
IN IP_ADDRESS IpAddress,
|
|
IN IP_MASK Mask,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the specified local ip object. This includines starting
|
|
address registration for the object.
|
|
|
|
Arguments:
|
|
|
|
pLocalIp - The object to be initialized.
|
|
AddressType - One of the LLIP_ADDR_* constants.
|
|
IpAddress - The IP address of the object.
|
|
Mask - The mask associated with the IP address.
|
|
|
|
--*/
|
|
{
|
|
ENTER("InitailizeLocalIp", 0x8a0ff47c)
|
|
|
|
|
|
RM_DBG_ASSERT_LOCKED(&pLocalIp->Hdr, pSR);
|
|
|
|
pLocalIp->IpAddress = IpAddress;
|
|
pLocalIp->IpMask = Mask;
|
|
pLocalIp->IpAddressType = AddressType;
|
|
pLocalIp->AddAddressCount = 1;
|
|
|
|
if (arpCanTryMcap(IpAddress))
|
|
{
|
|
SET_LOCALIP_MCAP(pLocalIp, ARPLOCALIP_MCAP_CAPABLE);
|
|
}
|
|
|
|
UNLOCKOBJ(pLocalIp, pSR);
|
|
|
|
EXIT()
|
|
}
|
|
|
|
|
|
VOID
|
|
arpUnloadLocalIp(
|
|
IN ARPCB_LOCAL_IP * pLocalIp, // LOCKIN NOLOCKOUT
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Starts a task to unload pLocalIp.
|
|
The actual unload could happen asynchronously.
|
|
|
|
Arguments:
|
|
|
|
pLocalIp - The object to be unloaded.
|
|
|
|
--*/
|
|
{
|
|
ARP1394_INTERFACE * pIF = (ARP1394_INTERFACE*) pLocalIp->Hdr.pParentObject;
|
|
ENTER("arpDeinitializeLocalIp", 0x1db1015e)
|
|
PRM_TASK pTask;
|
|
NDIS_STATUS Status;
|
|
|
|
TR_INFO(("Enter. pLocalIp = 0x%p\n", pLocalIp));
|
|
|
|
RM_DBG_ASSERT_LOCKED(&pLocalIp->Hdr, pSR);
|
|
|
|
#if TODO // if it can be synchronously unloaded, no need to start a task
|
|
// (on the other hand, I'm not sure we should bother)
|
|
if (arpLocalIpReadyForSyncDeinit(pLocalIp, pSR))
|
|
{
|
|
arpSyncDeinitLocalIp(pLocalIp, pSR); // Lock released on exit.
|
|
}
|
|
#endif // TODO
|
|
|
|
UNLOCKOBJ(pLocalIp, pSR);
|
|
|
|
//
|
|
// Allocate and start a task to unload pLocalIp;
|
|
//
|
|
|
|
Status = arpAllocateTask(
|
|
&pLocalIp->Hdr, // pParentObject
|
|
arpTaskUnloadLocalIp, // pfnHandler
|
|
0, // Timeout
|
|
"Task: unload LocalIp", // szDescription
|
|
&pTask,
|
|
pSR
|
|
);
|
|
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
// TODO Need special allocation mechanism for unload-related tasks
|
|
// that will block until a free task becomes available.
|
|
// See notes.txt 03/09/1999 entry "Special allocator for unload-related
|
|
// tasks
|
|
//
|
|
TR_FATAL(("FATAL: couldn't alloc unload-local-ip task!\n"));
|
|
}
|
|
else
|
|
{
|
|
(void)RmStartTask(
|
|
pTask,
|
|
0, // UserParam (unused)
|
|
pSR
|
|
);
|
|
}
|
|
|
|
EXIT()
|
|
}
|
|
|
|
|
|
INT
|
|
arpQueryIpEntityId(
|
|
ARP1394_INTERFACE * pIF, // LOCKIN LOCKOUT
|
|
IN UINT EntityType,
|
|
IN PNDIS_BUFFER pNdisBuffer,
|
|
IN OUT PUINT pBufferSize,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the entity ID for the specified EntityType.
|
|
|
|
Arguments:
|
|
|
|
pIF - Interface
|
|
EntityType - QueryInfo entity type (AT_*)
|
|
pNdisBuffer - Space for returning information
|
|
pBufferSize - Pointer to size of above. On return, we fill
|
|
it with the actual bytes copied.
|
|
Return Value:
|
|
|
|
TDI Status code.
|
|
|
|
--*/
|
|
{
|
|
ENTER("arpQueryIpEntityId", 0x1ada17cb)
|
|
UINT ReturnStatus;
|
|
|
|
RM_DBG_ASSERT_LOCKED(&pIF->Hdr, pSR);
|
|
|
|
if (*pBufferSize >= sizeof(UINT))
|
|
{
|
|
UINT EntityId;
|
|
UINT ByteOffset = 0;
|
|
TR_VERB(
|
|
("INFO GENERIC, ENTITY TYPE, BufferSize %d\n", *pBufferSize));
|
|
|
|
EntityId = ((EntityType == AT_ENTITY) ? AT_ARP: IF_MIB);
|
|
arpCopyToNdisBuffer(
|
|
pNdisBuffer,
|
|
(PUCHAR)&EntityId,
|
|
sizeof(EntityId),
|
|
&ByteOffset);
|
|
|
|
// *pBufferSize = sizeof(UINT); << This was commented-out in atmarpc.sys
|
|
*pBufferSize = 0; // To keep the same behavior as atmarpc.sys
|
|
ReturnStatus = TDI_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
ReturnStatus = TDI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
|
|
INT
|
|
arpQueryIpAddrXlatInfo(
|
|
ARP1394_INTERFACE * pIF, // LOCKIN LOCKOUT
|
|
IN PNDIS_BUFFER pNdisBuffer,
|
|
IN OUT PUINT pBufferSize,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Request for the number of entries in the address translation
|
|
table, and the IF index.
|
|
|
|
Arguments:
|
|
|
|
pIF - Interface
|
|
pNdisBuffer - Space for returning information
|
|
pBufferSize - Pointer to size of above. On return, we fill
|
|
it with the actual bytes copied.
|
|
QueryContext - Context value pertaining to the query.
|
|
|
|
Return Value:
|
|
|
|
TDI Status code.
|
|
|
|
--*/
|
|
{
|
|
UINT ReturnStatus;
|
|
AddrXlatInfo Info;
|
|
ENTER("arpQueryIpXlatInfo", 0xd320b55a)
|
|
|
|
RM_DBG_ASSERT_LOCKED(&pIF->Hdr, pSR);
|
|
|
|
TR_INFO(("QueryInfo: AT Entity, for IF index, ATE size\n"));
|
|
|
|
if (*pBufferSize >= sizeof(Info))
|
|
{
|
|
UINT ByteOffset = 0;
|
|
|
|
ARP_ZEROSTRUCT(&Info);
|
|
*pBufferSize = sizeof(Info);
|
|
|
|
Info.axi_count = RM_NUM_ITEMS_IN_GROUP(&pIF->RemoteIpGroup);
|
|
Info.axi_index = pIF->ip.IFIndex;
|
|
|
|
arpCopyToNdisBuffer(
|
|
pNdisBuffer,
|
|
(PUCHAR)&Info,
|
|
sizeof(Info),
|
|
&ByteOffset);
|
|
|
|
ReturnStatus = TDI_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
ReturnStatus = TDI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
EXIT()
|
|
return ReturnStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
arpCopyDestInfoIntoInmeInfo (
|
|
PUCHAR pinme_physaddr,
|
|
PARPCB_DEST pDest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy the correct destination address to the location provided
|
|
In the Fifo Send case, we need to report the Fake Mac Address
|
|
In all other cases, we'll report the first six bytes of the destination
|
|
|
|
Arguments:
|
|
pinme_physaddr - Location we need to fill up.
|
|
pdest
|
|
|
|
Return Value:
|
|
|
|
TDI Status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNIC1394_DESTINATION pNicDest = &pDest->Params.HwAddr;
|
|
ENetAddr FakeEnetAddress = {0,0,0,0,0,0};
|
|
PUCHAR pDestAddr = NULL;
|
|
|
|
|
|
//
|
|
// This assertion is important for this function to work.
|
|
// If it is changed, then we can no longer use FakeMac Addresses
|
|
// to identify remote nodes. We will have to revert back to using Unique IDs
|
|
//
|
|
ASSERT (sizeof(ENetAddr) == ARP1394_IP_PHYSADDR_LEN);
|
|
|
|
|
|
if (NIC1394AddressType_FIFO == pNicDest->AddressType &&
|
|
pDest->Params.ReceiveOnly== FALSE)
|
|
{
|
|
|
|
//
|
|
// We are translating an entry that describes a SendFifo Destination
|
|
//
|
|
|
|
|
|
//
|
|
// Use the same algorithm as nic1394 uses to get a
|
|
// MAC address to report back to IP
|
|
//
|
|
if (pNicDest->FifoAddress.UniqueID != 0)
|
|
{
|
|
nicGetMacAddressFromEuid(&pNicDest->FifoAddress.UniqueID, &FakeEnetAddress);
|
|
}
|
|
|
|
pDestAddr = (PUCHAR) &FakeEnetAddress;
|
|
|
|
}
|
|
else
|
|
{
|
|
// We'll use the first six bytes of the NIC1394_DESTINATION
|
|
//
|
|
|
|
|
|
// We copy the 1st ARP1394_IP_PHYSADDR_LEN bytes of the address...
|
|
// (In the case of a channel, only the 1st 4 bytes (UINT Channel)
|
|
// are significant; The rest will be all zeros.)
|
|
//
|
|
pDestAddr = (PUCHAR)pNicDest;
|
|
|
|
}
|
|
|
|
|
|
NdisMoveMemory (pinme_physaddr, pDestAddr, ARP1394_IP_PHYSADDR_LEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
arpQueryIpAddrXlatEntries(
|
|
ARP1394_INTERFACE * pIF, // LOCKIN LOCKOUT
|
|
IN PNDIS_BUFFER pNdisBuffer,
|
|
IN OUT PUINT pBufferSize,
|
|
IN PVOID QueryContext,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return as many AddrXlat entries (aka arp entries) as will fit
|
|
into the specified buffer.
|
|
|
|
|
|
Arguments:
|
|
|
|
pIF - Interface
|
|
pNdisBuffer - Space for returning information
|
|
pBufferSize - Pointer to size of above. On return, we fill
|
|
it with the actual bytes copied.
|
|
QueryContext - Context value pertaining to the query.
|
|
|
|
Return Value:
|
|
|
|
TDI Status code.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Our context structure is laid out as follows
|
|
//
|
|
typedef struct
|
|
{
|
|
IP_ADDRESS IpAddr;
|
|
|
|
// UINT TableSize; << TODO To deal with dynamic changes in table-size.
|
|
|
|
} OUR_QUERY_CONTEXT;
|
|
|
|
OUR_QUERY_CONTEXT * pOurCtxt;
|
|
UINT ReturnStatus;
|
|
UINT ByteOffset;
|
|
UINT BytesCopied;
|
|
UINT BufferSize;
|
|
ARPCB_REMOTE_IP * pRemoteIp;
|
|
NDIS_STATUS Status;
|
|
ENTER("arpQueryIpXlatEntries", 0x61c86684)
|
|
|
|
TR_INFO(("QueryInfo: AT Entity, for reading ATE\n"));
|
|
RM_DBG_ASSERT_LOCKED(&pIF->Hdr, pSR);
|
|
|
|
// See notes.txt entry ..
|
|
// 03/04/1999 JosephJ Size of the context passed in ArpIpQueryInfo.
|
|
//
|
|
ASSERT(sizeof(OUR_QUERY_CONTEXT) <= 16);
|
|
|
|
BufferSize = *pBufferSize;
|
|
*pBufferSize = 0;
|
|
BytesCopied = 0;
|
|
ByteOffset = 0;
|
|
pOurCtxt = (OUR_QUERY_CONTEXT*) QueryContext;
|
|
pRemoteIp = NULL;
|
|
|
|
ReturnStatus = TDI_SUCCESS;
|
|
|
|
//
|
|
// Our context structure is supposed to be initialized with Zeros the 1st time
|
|
// it's called.
|
|
//
|
|
if (pOurCtxt->IpAddr == 0)
|
|
{
|
|
//
|
|
// This is a brand new context. So we get the 1st entry.
|
|
//
|
|
Status = RmGetNextObjectInGroup(
|
|
&pIF->RemoteIpGroup,
|
|
NULL,
|
|
&(PRM_OBJECT_HEADER)pRemoteIp,
|
|
pSR
|
|
);
|
|
if (FAIL(Status))
|
|
{
|
|
// Presumably there are no entries.
|
|
pRemoteIp = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is an ongoing context. Let's look up this IP address, which is
|
|
// supposed to be the IP address of the next item in the arp table.
|
|
//
|
|
Status = RmLookupObjectInGroup(
|
|
&pIF->RemoteIpGroup,
|
|
0, // Flags
|
|
(PVOID) ULongToPtr (pOurCtxt->IpAddr), // pKey
|
|
NULL, // pvCreateParams
|
|
&(PRM_OBJECT_HEADER)pRemoteIp,
|
|
NULL, // pfCreated
|
|
pSR
|
|
);
|
|
if (FAIL(Status))
|
|
{
|
|
//
|
|
// Ah well, things have changed since the last time we were called,
|
|
// and now this entry is no longer around.
|
|
//
|
|
pRemoteIp = NULL;
|
|
}
|
|
}
|
|
|
|
while (pRemoteIp != NULL)
|
|
{
|
|
ARPCB_REMOTE_IP * pNextRemoteIp = NULL;
|
|
IPNetToMediaEntry ArpEntry;
|
|
|
|
if (((INT)BufferSize - (INT)BytesCopied) < sizeof(ArpEntry))
|
|
{
|
|
//
|
|
// out of space; Update the context, and set special return value.
|
|
//
|
|
ARP_ZEROSTRUCT(pOurCtxt);
|
|
pOurCtxt->IpAddr = pRemoteIp->IpAddress;
|
|
|
|
|
|
ReturnStatus = TDI_BUFFER_OVERFLOW;
|
|
RmTmpDereferenceObject(&pRemoteIp->Hdr, pSR);
|
|
pRemoteIp = NULL;
|
|
break;
|
|
}
|
|
|
|
// Prepare the XlatEntry in ArpEntry.
|
|
//
|
|
{
|
|
ARP_ZEROSTRUCT(&ArpEntry);
|
|
|
|
ArpEntry.inme_index = pIF->ip.IFIndex;
|
|
ArpEntry.inme_addr = pRemoteIp->IpAddress;
|
|
if (CHECK_REMOTEIP_RESOLVE_STATE(pRemoteIp, ARPREMOTEIP_RESOLVED))
|
|
{
|
|
ARPCB_DEST *pDest = pRemoteIp->pDest;
|
|
|
|
TR_INFO(("ReadNext: found Remote IP Entry 0x%x, Addr %d.%d.%d.%d\n",
|
|
pRemoteIp,
|
|
((PUCHAR)(&(pRemoteIp->IpAddress)))[0],
|
|
((PUCHAR)(&(pRemoteIp->IpAddress)))[1],
|
|
((PUCHAR)(&(pRemoteIp->IpAddress)))[2],
|
|
((PUCHAR)(&(pRemoteIp->IpAddress)))[3]
|
|
));
|
|
|
|
// We assert that
|
|
// IF lock is the same as pRemoteIp's and pDest's lock,
|
|
// and that lock is locked.
|
|
// We implicitly assert that pDest is non-NULl as well.
|
|
//
|
|
ASSERTEX(pRemoteIp->Hdr.pLock == pDest->Hdr.pLock, pRemoteIp);
|
|
RM_DBG_ASSERT_LOCKED(&pRemoteIp->Hdr, pSR);
|
|
|
|
ArpEntry.inme_physaddrlen = ARP1394_IP_PHYSADDR_LEN;
|
|
|
|
// We copy the 1st ARP1394_IP_PHYSADDR_LEN bytes of the address...
|
|
// (In the case of a channel, only the 1st 4 bytes (UINT Channel)
|
|
// are significant; The rest will be all zeros.)
|
|
//
|
|
ASSERT(sizeof(pDest->Params.HwAddr)>=ARP1394_IP_PHYSADDR_LEN);
|
|
|
|
arpCopyDestInfoIntoInmeInfo (ArpEntry.inme_physaddr,pDest);
|
|
|
|
if (CHECK_REMOTEIP_SDTYPE(pRemoteIp, ARPREMOTEIP_STATIC))
|
|
{
|
|
ArpEntry.inme_type = INME_TYPE_STATIC;
|
|
}
|
|
else
|
|
{
|
|
ArpEntry.inme_type = INME_TYPE_DYNAMIC;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ArpEntry.inme_physaddrlen = 0;
|
|
ArpEntry.inme_type = INME_TYPE_INVALID;
|
|
}
|
|
}
|
|
|
|
// Copy into the supplied ndis buffer.
|
|
//
|
|
BytesCopied += sizeof(ArpEntry);
|
|
pNdisBuffer = arpCopyToNdisBuffer(
|
|
pNdisBuffer,
|
|
(PUCHAR)&ArpEntry,
|
|
sizeof(ArpEntry),
|
|
&ByteOffset
|
|
);
|
|
|
|
// Lookup next entry's IP address and save it in our context.
|
|
//
|
|
Status = RmGetNextObjectInGroup(
|
|
&pIF->RemoteIpGroup,
|
|
&pRemoteIp->Hdr,
|
|
&(PRM_OBJECT_HEADER)pNextRemoteIp,
|
|
pSR
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
//
|
|
// we're presumably done.
|
|
//
|
|
pNextRemoteIp = NULL;
|
|
}
|
|
|
|
// TmpDeref pRemoteIp and move on to the next one.
|
|
//
|
|
RmTmpDereferenceObject(&pRemoteIp->Hdr, pSR);
|
|
pRemoteIp = pNextRemoteIp;
|
|
|
|
}
|
|
|
|
ASSERT(pRemoteIp == NULL);
|
|
|
|
*pBufferSize = BytesCopied;
|
|
|
|
|
|
EXIT()
|
|
return ReturnStatus;
|
|
}
|
|
|
|
|
|
arpQueryIpMibStats(
|
|
ARP1394_INTERFACE * pIF, // LOCKIN LOCKOUT
|
|
IN PNDIS_BUFFER pNdisBuffer,
|
|
IN OUT PUINT pBufferSize,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fill out Interface-level statistics.
|
|
|
|
Arguments:
|
|
|
|
pIF - Interface
|
|
pNdisBuffer - Space for returning information
|
|
pBufferSize - Pointer to size of above. On return, we fill
|
|
it with the actual bytes copied.
|
|
|
|
Return Value:
|
|
|
|
TDI Status code.
|
|
|
|
--*/
|
|
{
|
|
ENTER("arpQueryIpMibStatus", 0xc5bc364f)
|
|
UINT ReturnStatus;
|
|
UINT BufferSize;
|
|
|
|
TR_VERB(("QueryInfo: MIB statistics\n"));
|
|
RM_DBG_ASSERT_LOCKED(&pIF->Hdr, pSR);
|
|
|
|
BufferSize = *pBufferSize;
|
|
*pBufferSize = 0;
|
|
|
|
do
|
|
{
|
|
IFEntry ife;
|
|
ARP1394_ADAPTER * pAdapter;
|
|
UINT ByteOffset;
|
|
UINT BytesCopied;
|
|
|
|
//
|
|
// Check if we have enough space.
|
|
//
|
|
if (BufferSize < IFE_FIXED_SIZE)
|
|
{
|
|
ReturnStatus = TDI_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
ARP_ZEROSTRUCT(&ife);
|
|
pAdapter = (ARP1394_ADAPTER*) RM_PARENT_OBJECT(pIF);
|
|
BytesCopied = 0;
|
|
ByteOffset = 0;
|
|
|
|
//
|
|
// Fill out mib info...
|
|
//
|
|
|
|
ife.if_index = pIF->ip.IFIndex;
|
|
ife.if_mtu = pIF->ip.MTU;
|
|
ife.if_type = IF_TYPE_IEEE1394;
|
|
ife.if_speed = pAdapter->info.Speed;
|
|
|
|
// Set adminstatus and operstatus (computed from pIF->Hdr.State)
|
|
//
|
|
ife.if_adminstatus = IF_STATUS_UP;
|
|
ife.if_operstatus = IF_OPER_STATUS_OPERATIONAL;
|
|
|
|
if (CHECK_IF_PRIMARY_STATE(pIF, ARPIF_PS_DEINITING))
|
|
{
|
|
ife.if_adminstatus = IF_STATUS_DOWN;
|
|
}
|
|
if (!CHECK_IF_IP_STATE(pIF, ARPIF_IPS_OPEN))
|
|
{
|
|
ife.if_operstatus = IF_OPER_STATUS_NON_OPERATIONAL;
|
|
}
|
|
|
|
// Stats...
|
|
//
|
|
ife.if_lastchange = pIF->stats.LastChangeTime;
|
|
ife.if_inoctets = pIF->stats.InOctets;
|
|
ife.if_inucastpkts = pIF->stats.InUnicastPkts;
|
|
ife.if_innucastpkts = pIF->stats.InNonUnicastPkts;
|
|
ife.if_indiscards = pIF->stats.InDiscards;
|
|
ife.if_inerrors = pIF->stats.InErrors;
|
|
ife.if_inunknownprotos = pIF->stats.UnknownProtos;
|
|
ife.if_outoctets = pIF->stats.OutOctets;
|
|
ife.if_outucastpkts = pIF->stats.OutUnicastPkts;
|
|
ife.if_outnucastpkts = pIF->stats.OutNonUnicastPkts;
|
|
ife.if_outdiscards = pIF->stats.OutDiscards;
|
|
ife.if_outerrors = pIF->stats.OutErrors;
|
|
ife.if_outqlen = pIF->stats.OutQlen;
|
|
|
|
ife.if_descrlen = pAdapter->info.DescriptionLength;
|
|
|
|
|
|
ASSERT(ARP1394_IP_PHYSADDR_LEN <= sizeof(pAdapter->info.EthernetMacAddress));
|
|
ife.if_physaddrlen = ARP1394_IP_PHYSADDR_LEN;
|
|
|
|
#if 1 // MILLEN
|
|
//
|
|
// Win98: winipcfg doesn't like more than 6 bytes repored here.
|
|
//
|
|
if (ife.if_physaddrlen > 6)
|
|
{
|
|
ife.if_physaddrlen = 6;
|
|
}
|
|
#endif// MILLEN
|
|
|
|
|
|
//
|
|
// Tell TCPIP that the Ethernet Address is the real physical address.
|
|
// This helps us because now we have the same 'MAC' address whether
|
|
// we are in a network which is bridged to Ethernet or not.
|
|
//
|
|
NdisMoveMemory(
|
|
ife.if_physaddr,
|
|
&(pAdapter->info.EthernetMacAddress),
|
|
ife.if_physaddrlen
|
|
);
|
|
|
|
arpCopyToNdisBuffer(
|
|
pNdisBuffer,
|
|
(PUCHAR)&ife,
|
|
IFE_FIXED_SIZE,
|
|
&ByteOffset);
|
|
|
|
if (BufferSize >= (IFE_FIXED_SIZE + ife.if_descrlen))
|
|
{
|
|
if (ife.if_descrlen != 0)
|
|
{
|
|
arpCopyToNdisBuffer(
|
|
pNdisBuffer,
|
|
pAdapter->info.szDescription,
|
|
ife.if_descrlen,
|
|
&ByteOffset);
|
|
}
|
|
*pBufferSize = IFE_FIXED_SIZE + ife.if_descrlen;
|
|
ReturnStatus = TDI_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
*pBufferSize = IFE_FIXED_SIZE;
|
|
ReturnStatus = TDI_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
EXIT()
|
|
return ReturnStatus;
|
|
}
|
|
|
|
|
|
PNDIS_BUFFER
|
|
arpCopyToNdisBuffer(
|
|
IN PNDIS_BUFFER pDestBuffer,
|
|
IN PUCHAR pDataSrc,
|
|
IN UINT LenToCopy,
|
|
IN OUT PUINT pOffsetInBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy data into an NDIS buffer chain. Use up as much of the given
|
|
NDIS chain as needed for "LenToCopy" bytes. After copying is over,
|
|
return a pointer to the first NDIS buffer that has space for writing
|
|
into (for the next Copy operation), and the offset within this from
|
|
which to start writing.
|
|
|
|
Arguments:
|
|
|
|
pDestBuffer - First NDIS buffer in a chain of buffers
|
|
pDataSrc - Where to copy data from
|
|
LenToCopy - How much data to copy
|
|
pOffsetInBuffer - Offset in pDestBuffer where we can start copying into.
|
|
|
|
Return Value:
|
|
|
|
The NDIS buffer in the chain where the next Copy can be done. We also
|
|
set *pOffsetInBuffer to the write offset in the returned NDIS buffer.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Size and destination for individual (contiguous) copy operations
|
|
//
|
|
UINT CopySize;
|
|
PUCHAR pDataDst;
|
|
|
|
//
|
|
// Start Virtual address for each NDIS buffer in chain.
|
|
//
|
|
PUCHAR VirtualAddress;
|
|
|
|
//
|
|
// Offset within pDestBuffer
|
|
//
|
|
UINT OffsetInBuffer = *pOffsetInBuffer;
|
|
|
|
//
|
|
// Bytes remaining in current buffer
|
|
//
|
|
UINT DestSize;
|
|
|
|
//
|
|
// Total Buffer Length
|
|
//
|
|
UINT BufferLength;
|
|
|
|
|
|
ASSERT(pDestBuffer != (PNDIS_BUFFER)NULL);
|
|
ASSERT(pDataSrc != NULL);
|
|
|
|
#if MILLEN
|
|
NdisQueryBuffer(
|
|
pDestBuffer,
|
|
&VirtualAddress,
|
|
&BufferLength
|
|
);
|
|
#else
|
|
NdisQueryBufferSafe(
|
|
pDestBuffer,
|
|
&VirtualAddress,
|
|
&BufferLength,
|
|
NormalPagePriority
|
|
);
|
|
|
|
if (VirtualAddress == NULL)
|
|
{
|
|
return (NULL);
|
|
}
|
|
#endif
|
|
|
|
ASSERT(BufferLength >= OffsetInBuffer);
|
|
|
|
pDataDst = VirtualAddress + OffsetInBuffer;
|
|
DestSize = BufferLength - OffsetInBuffer;
|
|
|
|
for (;;)
|
|
{
|
|
CopySize = LenToCopy;
|
|
if (CopySize > DestSize)
|
|
{
|
|
CopySize = DestSize;
|
|
}
|
|
|
|
NdisMoveMemory(pDataDst, pDataSrc, CopySize);
|
|
|
|
pDataDst += CopySize;
|
|
pDataSrc += CopySize;
|
|
|
|
LenToCopy -= CopySize;
|
|
if (LenToCopy == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
DestSize -= CopySize;
|
|
|
|
if (DestSize == 0)
|
|
{
|
|
//
|
|
// Out of space in the current buffer. Move to the next.
|
|
//
|
|
pDestBuffer = NDIS_BUFFER_LINKAGE(pDestBuffer);
|
|
|
|
if (pDestBuffer == NULL)
|
|
{
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
#if MILLEN
|
|
NdisQueryBuffer(
|
|
pDestBuffer,
|
|
&VirtualAddress,
|
|
&BufferLength
|
|
);
|
|
#else // !MILLEN
|
|
NdisQueryBufferSafe(
|
|
pDestBuffer,
|
|
&VirtualAddress,
|
|
&BufferLength,
|
|
NormalPagePriority
|
|
);
|
|
|
|
if (VirtualAddress == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
#endif // !MILLEN
|
|
pDataDst = VirtualAddress;
|
|
DestSize = BufferLength;
|
|
}
|
|
}
|
|
}
|
|
|
|
*pOffsetInBuffer = (UINT) (pDataDst - VirtualAddress);
|
|
|
|
return (pDestBuffer);
|
|
}
|
|
|
|
|
|
VOID
|
|
arpSendIpPkt(
|
|
IN ARP1394_INTERFACE * pIF, // LOCKIN NOLOCKOUT (IF send lk)
|
|
IN PARPCB_DEST pDest,
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
/*++
|
|
|
|
HOT PATH
|
|
|
|
Routine Description:
|
|
|
|
Send a packet to the FIFO/channel associated with destination object pDest.
|
|
|
|
Arguments:
|
|
|
|
pIF - Our interface object
|
|
pDest - Destination object on which to send packet
|
|
pNdisPacket - Packet to send
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
MYBOOL fRet;
|
|
ARP1394_ADAPTER * pAdapter =
|
|
(ARP1394_ADAPTER*) RM_PARENT_OBJECT(pIF);
|
|
MYBOOL fBridgeMode = ARP_BRIDGE_ENABLED(pAdapter);
|
|
|
|
DBGMARK(0xdaab68c3);
|
|
|
|
//
|
|
// If we can't send now, we immediately call IP's send complete handler.
|
|
//
|
|
if (!ARP_CAN_SEND_ON_DEST(pDest))
|
|
{
|
|
ARP_FASTUNLOCK_IF_SEND_LOCK(pIF);
|
|
|
|
if (ARP_DEST_IS_FIFO(pDest))
|
|
{
|
|
LOGSTATS_SendFifoCounts(pIF, pNdisPacket, NDIS_STATUS_FAILURE);
|
|
}
|
|
else
|
|
{
|
|
LOGSTATS_SendChannelCounts(pIF, pNdisPacket, NDIS_STATUS_FAILURE);
|
|
}
|
|
#if MILLEN
|
|
ASSERT_PASSIVE();
|
|
#endif // MILLEN
|
|
NdisInterlockedIncrement (&ArpSendCompletes);
|
|
NdisInterlockedIncrement (&ArpSendFailure);
|
|
|
|
|
|
if (fBridgeMode)
|
|
{
|
|
// In bridge (ethernet emulation) mode, we created the
|
|
// packets ourselves, so we delete them here, instead
|
|
// of calling Ip's completion handler, which in fact
|
|
// is NULL.
|
|
//
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
arpFreeControlPacket(
|
|
pIF,
|
|
pNdisPacket,
|
|
&sr
|
|
);
|
|
}
|
|
else
|
|
{
|
|
(*(pIF->ip.TxCmpltHandler))(
|
|
pIF->ip.Context,
|
|
pNdisPacket,
|
|
NDIS_STATUS_FAILURE
|
|
);
|
|
}
|
|
return; // EARLY RETURN
|
|
}
|
|
|
|
arpRefSendPkt( pNdisPacket, pDest);
|
|
|
|
// Release the IF send lock.
|
|
//
|
|
ARP_FASTUNLOCK_IF_SEND_LOCK(pIF);
|
|
|
|
|
|
// NOW (with IF send lock released), we prepare the IP packet for sending....
|
|
//
|
|
// We do this only if not in ethernet emulation (bridge) mode,
|
|
// because all IP packets in bridge mode already have the
|
|
// proper 1394 header on them.
|
|
//
|
|
if (!fBridgeMode)
|
|
{
|
|
PNDIS_BUFFER pNdisBuffer; // First buffer in the IP packet
|
|
|
|
// TODO: is this safe? How about a check for the size by which this is possible!
|
|
#if !MILLEN
|
|
#define ARP_BACK_FILL_POSSIBLE(_pBuf) \
|
|
(((_pBuf)->MdlFlags & MDL_NETWORK_HEADER) != 0)
|
|
#else // MILLEN
|
|
#define ARP_BACK_FILL_POSSIBLE(_pBuf) (0)
|
|
#endif // MILLEN
|
|
|
|
//
|
|
// We look at the first buffer in the IP packet, to see whether
|
|
// it has space reserved for low-layer headers. If so, we just
|
|
// use it up. Otherwise, we allocate a header buffer of our own.
|
|
//
|
|
NdisQueryPacket(pNdisPacket, NULL, NULL, &pNdisBuffer, NULL);
|
|
ASSERTEX(pNdisBuffer != NULL, pNdisPacket);
|
|
if (ARP_BACK_FILL_POSSIBLE(pNdisBuffer))
|
|
{
|
|
const ULONG EncapLength = sizeof(Arp1394_IpEncapHeader);
|
|
|
|
#if MILLEN
|
|
|
|
ASSERT(!"We shouldn't be here -- check ARP_BACK_FILL_POSSIBLE()");
|
|
|
|
#else // !MILLEN
|
|
|
|
(PUCHAR)pNdisBuffer->MappedSystemVa -= EncapLength;
|
|
pNdisBuffer->ByteOffset -= EncapLength;
|
|
pNdisBuffer->ByteCount += EncapLength;
|
|
NdisMoveMemory(
|
|
pNdisBuffer->MappedSystemVa,
|
|
&Arp1394_IpEncapHeader,
|
|
EncapLength
|
|
);
|
|
|
|
|
|
#define LOGSTATS_BackFills(_pIF, _pNdisPacket) \
|
|
NdisInterlockedIncrement(&((_pIF)->stats.sendpkts.BackFills))
|
|
|
|
LOGSTATS_BackFills(pIF, pNdisPacket);
|
|
|
|
#endif // !MILLEN
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Backfill wasn't possible for this packet. Let's try to allocate
|
|
// an encapsulation header buffer from the IF pool...
|
|
//
|
|
|
|
pNdisBuffer = arpAllocateConstBuffer(&pIF->sendinfo.HeaderPool);
|
|
|
|
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
// Our send complete handler relies on this assertion to decide
|
|
// whether backfill happened or not.
|
|
//
|
|
ASSERT(!ARP_BACK_FILL_POSSIBLE(pNdisBuffer));
|
|
|
|
NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Oops, we couldn't allocate an encapsulation buffer!
|
|
// We've already referenced the destination for sends.
|
|
//
|
|
|
|
//
|
|
// Cop out for now (we haven't implemented all the queuing
|
|
// code for now) by calling our own send complete handler with
|
|
// status failure.
|
|
//
|
|
// We use the special return value NDIS_STATUS_NOT_RESETTABLE
|
|
// to indicate that we haven't inserted our own buffer,
|
|
// (and so the packet shouldn't be "reset"). Ok this is a bit
|
|
// hacky, but it works.
|
|
//
|
|
arpCompleteSentPkt(
|
|
NDIS_STATUS_NOT_RESETTABLE,
|
|
pIF,
|
|
pDest,
|
|
pNdisPacket
|
|
);
|
|
|
|
return; // EARLY RETURN
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// Actually send the packet
|
|
//
|
|
#if ARPDBG_FAKE_SEND
|
|
arpDbgFakeNdisCoSendPackets(
|
|
pDest->VcHdr.NdisVcHandle,
|
|
&pNdisPacket,
|
|
1,
|
|
&pDest->Hdr,
|
|
&pDest->VcHdr
|
|
);
|
|
#else // !ARPDBG_FAKE_SEND
|
|
NdisCoSendPackets(
|
|
pDest->VcHdr.NdisVcHandle,
|
|
&pNdisPacket,
|
|
1
|
|
);
|
|
#endif // !ARPDBG_FAKE_SEND
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
arpSlowIpTransmit(
|
|
IN ARP1394_INTERFACE * pIF,
|
|
IN PNDIS_PACKET pNdisPacket,
|
|
IN REMOTE_DEST_KEY Destination,
|
|
IN RouteCacheEntry * pRCE OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the path taken (hopefully only for a small fraction of the packets)
|
|
when something has prevented the packet from being immediately sent down to
|
|
the miniport. Typically we're here for one of the following reasons:
|
|
1. IP Address is not resolved yet.
|
|
2. RCE entry has not been initialized yet.
|
|
3. Couldn't allocate an encapsulation-header buffer.
|
|
4. The Vc to the destination doesn't exist or is not ready for sending yet.
|
|
|
|
|
|
Arguments:
|
|
|
|
pIF - Our interface object
|
|
pNdisPacket - Packet to send
|
|
Destination - IP address of destination
|
|
pRCE - (OPTIONAL) Route Cache Entry associated with this
|
|
destination
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS on synchronous success.
|
|
NDIS_STATUS_PENDING if completion is asynchronous
|
|
Other ndis status code on other kinds of failure.
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) RM_PARENT_OBJECT(pIF);
|
|
ENTER("arpSlowIpTransmit", 0xe635299c)
|
|
BOOLEAN fBridgeMode = ARP_BRIDGE_ENABLED(pAdapter);
|
|
ULONG LookupFlags = 0;
|
|
UINT fRemoteIpCreated = FALSE;
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
DBGMARK(0x30b6f7e2);
|
|
|
|
do
|
|
{
|
|
ARP_RCE_CONTEXT * pArpRceContext = NULL;
|
|
ARPCB_REMOTE_IP * pRemoteIp = NULL;
|
|
ARPCB_DEST * pDest = NULL;
|
|
|
|
#define LOGSTATS_SlowSends(_pIF, _pNdisPacket) \
|
|
NdisInterlockedIncrement(&((_pIF)->stats.sendpkts.SlowSends))
|
|
#define LOGSTATS_MediumSends(_pIF, _pNdisPacket) \
|
|
NdisInterlockedIncrement(&((_pIF)->stats.sendpkts.MediumSends))
|
|
|
|
//
|
|
// If there is a RCE, we try to get the pRemoteIp from it If not
|
|
// successful, we'll need to actually lookup/create the pRemoteIp from the
|
|
// IF RemoteIpGroup.
|
|
//
|
|
|
|
if (pRCE != NULL)
|
|
{
|
|
pArpRceContext = ARP_OUR_CTXT_FROM_RCE(pRCE);
|
|
|
|
// All RCE linkages are protected by the IF send lock.
|
|
//
|
|
ARP_READLOCK_IF_SEND_LOCK(pIF, &sr);
|
|
pRemoteIp = pArpRceContext->pRemoteIp;
|
|
if (pRemoteIp != NULL)
|
|
{
|
|
RmTmpReferenceObject(&pRemoteIp->Hdr, &sr);
|
|
}
|
|
ARP_UNLOCK_IF_SEND_LOCK(pIF, &sr);
|
|
}
|
|
|
|
if (pRemoteIp == NULL)
|
|
{
|
|
//
|
|
// Either there was no RCE or it was uninitialized.
|
|
// We'll lookup/create the pRemoteIp based on the destination
|
|
// IP address...
|
|
//
|
|
|
|
RM_ASSERT_NOLOCKS(&sr);
|
|
|
|
//
|
|
// Create the destination, this will cause us to resolve IP Addresses, etc/
|
|
//
|
|
LookupFlags = RM_CREATE;
|
|
|
|
|
|
if (fBridgeMode == TRUE)
|
|
{
|
|
//
|
|
// do not create a remote IP struct, only look it up
|
|
//
|
|
LookupFlags = 0;
|
|
}
|
|
// if in bridge mode
|
|
// set flags to zero , else RM_CREATE
|
|
|
|
Status = RmLookupObjectInGroup(
|
|
&pIF->RemoteIpGroup,
|
|
LookupFlags,
|
|
(PVOID) &Destination,
|
|
(PVOID) (&Destination), // pCreateParams
|
|
(RM_OBJECT_HEADER**) &pRemoteIp,
|
|
&fRemoteIpCreated, // pfCreated (unused)
|
|
&sr
|
|
);
|
|
LOGSTATS_TotalArpCacheLookups(pIF, Status);
|
|
if (FAIL(Status))
|
|
{
|
|
OBJLOG1(
|
|
pIF,
|
|
"Couldn't lookup/create localIp entry with addr 0x%lx\n",
|
|
Destination.IpAddress
|
|
);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// if we are in bridge mode, then we add the Destination Ip address to
|
|
// the RemoteIP structure.
|
|
//
|
|
if (fBridgeMode && fRemoteIpCreated)
|
|
{
|
|
Status = arpAddIpAddressToRemoteIp (pRemoteIp, pNdisPacket);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
OBJLOG1(
|
|
pIF,
|
|
"Couldn't Add Dest Ip addr to Remote Ip addr 0x%lx\n",
|
|
Destination.IpAddress
|
|
);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If there is a RCE, we make it point to pRemoteIp.
|
|
//
|
|
if (pRCE != NULL)
|
|
{
|
|
|
|
// All RCE linkages are protected by the IF send lock.
|
|
//
|
|
ARP_WRITELOCK_IF_SEND_LOCK(pIF, &sr);
|
|
|
|
if (pArpRceContext->pRemoteIp != NULL)
|
|
{
|
|
if (pArpRceContext->pRemoteIp != pRemoteIp)
|
|
{
|
|
ARPCB_REMOTE_IP * pStaleRemoteIp;
|
|
//
|
|
// We've got a wierd situation here: initially
|
|
// pRCE didn't point to any pRemoteIp, so we looked up
|
|
// a pRemoteIp ourselves. Now that we've got the IF send
|
|
// lock, we find that pRCE is pointing to a different
|
|
// pRemoteIp than the one we looked up!
|
|
//
|
|
// What to do? We ignore pRemoteIp (the one we looked up)
|
|
// and instead use pArpRceContext->pRemoteIp...
|
|
//
|
|
ASSERTEX(!"RCE pRemoteIp mismatch", pArpRceContext);
|
|
pStaleRemoteIp = pRemoteIp;
|
|
pRemoteIp = pArpRceContext->pRemoteIp;
|
|
RmTmpReferenceObject(&pRemoteIp->Hdr, &sr);
|
|
ARP_UNLOCK_IF_SEND_LOCK(pIF, &sr);
|
|
RM_ASSERT_NOLOCKS(&sr);
|
|
RmTmpDereferenceObject(&pStaleRemoteIp->Hdr, &sr);
|
|
ARP_WRITELOCK_IF_SEND_LOCK(pIF, &sr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Add the association between pRCE and pRemoteIp...
|
|
//
|
|
arpAddRce(pRemoteIp, pRCE, &sr); // LOCKIN LOCKOUT (IF send lk)
|
|
}
|
|
|
|
ARP_UNLOCK_IF_SEND_LOCK(pIF, &sr);
|
|
}
|
|
}
|
|
|
|
//
|
|
// At this point, we should have a pRemoteIp, with a tmpref on it,
|
|
// and no locks held.
|
|
//
|
|
ASSERT_VALID_REMOTE_IP(pRemoteIp);
|
|
RM_ASSERT_NOLOCKS(&sr);
|
|
|
|
//
|
|
// Queue the packet on pRemoteIp's send pkt queue, and start the
|
|
// SendPkts task on this pRemoteIp if required.
|
|
//
|
|
{
|
|
|
|
LOCKOBJ(pRemoteIp, &sr);
|
|
|
|
// NOTE: This field is not always modified with the lock held -- in
|
|
// the fast send path, it's simply set to true.
|
|
// This field is used in garbage collecting pRemoteIps.
|
|
//
|
|
pRemoteIp->sendinfo.TimeLastChecked = 0;
|
|
|
|
//
|
|
// Stats.
|
|
// TODO -- we need to directly deal with "medium sends"
|
|
// instead of starting up a task just because the RCEs are NULL
|
|
// -- mcast and udp pkts have null RCEs, it turns out.
|
|
//
|
|
|
|
if ( pRemoteIp->pDest != NULL
|
|
&& ARP_CAN_SEND_ON_DEST(pRemoteIp->pDest))
|
|
{
|
|
LOGSTATS_MediumSends(pIF, pNdisPacket);
|
|
}
|
|
else
|
|
{
|
|
LOGSTATS_SlowSends(pIF, pNdisPacket);
|
|
}
|
|
|
|
|
|
if (pRemoteIp->pSendPktsTask == NULL)
|
|
{
|
|
PRM_TASK pTask;
|
|
|
|
// There is no send-pkts task. Let's try to alloc and start one..
|
|
Status = arpAllocateTask(
|
|
&pRemoteIp->Hdr, // pParentObject
|
|
arpTaskSendPktsOnRemoteIp, // pfnHandler
|
|
0, // Timeout
|
|
"Task: SendPktsOnRemoteIp", // szDescription
|
|
&pTask,
|
|
&sr
|
|
);
|
|
if (FAIL(Status))
|
|
{
|
|
// Oops, couldn't allocate task. We fail with STATUS_RESOURCES
|
|
UNLOCKOBJ(pRemoteIp, &sr);
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Queue the pkt first, THEN start the task. This makes sure that
|
|
// the packet WILL be taken care of.
|
|
// TODO: Currently, it's possible that the RemoteIp's unload
|
|
// task will not wait for send pkts to be cleared up IF it checks
|
|
// BEFORE the task before is started. This hole needs
|
|
// to be fixed.
|
|
//
|
|
arpQueuePktOnRemoteIp(
|
|
pRemoteIp, // LOCKIN LOCKOUT
|
|
pNdisPacket,
|
|
&sr
|
|
);
|
|
|
|
UNLOCKOBJ(pRemoteIp, &sr);
|
|
|
|
(VOID) RmStartTask( pTask, 0, &sr);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There is already a send-pkts task. Simply queue the pkt.
|
|
//
|
|
arpQueuePktOnRemoteIp(
|
|
pRemoteIp, // LOCKIN LOCKOUT
|
|
pNdisPacket,
|
|
&sr
|
|
);
|
|
UNLOCKOBJ(pRemoteIp, &sr);
|
|
}
|
|
|
|
// We're done!
|
|
// Remove the tmp reference on pRemoteIp, and set status to PENDING.
|
|
//
|
|
RM_ASSERT_NOLOCKS(&sr);
|
|
RmTmpDereferenceObject(&pRemoteIp->Hdr, &sr);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
RM_ASSERT_CLEAR(&sr)
|
|
|
|
EXIT()
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
arpAddRce(
|
|
IN ARPCB_REMOTE_IP *pRemoteIp, // IF send lock WRITELOCKIN WRITELOCKOUT
|
|
IN RouteCacheEntry *pRce,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Link the RCE pRce with the remote ip object pRemoteIp.
|
|
--*/
|
|
{
|
|
ARP_RCE_CONTEXT * pArpRceContext;
|
|
MYBOOL fDoRef;
|
|
|
|
pArpRceContext = ARP_OUR_CTXT_FROM_RCE(pRce);
|
|
fDoRef = (pRemoteIp->sendinfo.pRceList == NULL);
|
|
|
|
ASSERT(pArpRceContext->pRemoteIp == NULL);
|
|
|
|
// Add pRce to pRemoteIP's list of RCEs.
|
|
//
|
|
pArpRceContext->pNextRce = pRemoteIp->sendinfo.pRceList;
|
|
pRemoteIp->sendinfo.pRceList = pRce;
|
|
|
|
// Add pointer from pRce to pRemoteIp
|
|
//
|
|
pArpRceContext->pRemoteIp = pRemoteIp;
|
|
|
|
|
|
// The following macros are just so that we can make the proper debug association
|
|
// depending on how closely we are tracking outstanding send packets.
|
|
//
|
|
#if ARPDBG_REF_EVERY_RCE
|
|
fDoRef = TRUE;
|
|
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) pRce)
|
|
#define szARPSSOC_EXTLINK_RIP_TO_RCE_FORMAT " Linked to pRce 0x%p\n"
|
|
#else // !ARPDBG_REF_EVERY_RCE
|
|
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) &pRemoteIp->sendinfo)
|
|
#define szARPSSOC_EXTLINK_RIP_TO_RCE_FORMAT " Outstanding RCEs exist. &si=0x%p\n"
|
|
#endif // !ARPDBG_REF_EVERY_RCE
|
|
|
|
|
|
if (fDoRef)
|
|
{
|
|
//
|
|
// If ARPDBG_REF_EVERY_RCE
|
|
// We add an "external" link for EVERY RCE. We'll later remove this
|
|
// reference when the RCE is invalidated.
|
|
// else
|
|
// Only a transition from zero to non-zero RCEs, we
|
|
// add an "external" link. We'll later remove this link when the
|
|
// transition from non-zero to zero happens.
|
|
//
|
|
|
|
#if RM_EXTRA_CHECKING
|
|
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
RmLinkToExternalEx(
|
|
&pRemoteIp->Hdr, // pHdr
|
|
0x22224c96, // LUID
|
|
OUR_EXTERNAL_ENTITY, // External entity
|
|
ARPASSOC_EXTLINK_RIP_TO_RCE, // AssocID
|
|
szARPSSOC_EXTLINK_RIP_TO_RCE_FORMAT,
|
|
&sr
|
|
);
|
|
|
|
#else // !RM_EXTRA_CHECKING
|
|
|
|
RmLinkToExternalFast(&pRemoteIp->Hdr);
|
|
|
|
#endif // !RM_EXTRA_CHECKING
|
|
|
|
}
|
|
|
|
#undef OUR_EXTERNAL_ENTITY
|
|
#undef szARPSSOC_EXTLINK_RIP_TO_RCE
|
|
}
|
|
|
|
|
|
VOID
|
|
arpDelRce(
|
|
IN RouteCacheEntry *pRce, // IF send lock WRITELOCKIN WRITELOCKOUTD
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unlink RCE pRce from remote ip object pRemoteIp.
|
|
|
|
--*/
|
|
{
|
|
ARPCB_REMOTE_IP * pRemoteIp;
|
|
ARP_RCE_CONTEXT * pArpRceContext;
|
|
MYBOOL fDoDeref;
|
|
RouteCacheEntry ** ppRce;
|
|
|
|
pArpRceContext = ARP_OUR_CTXT_FROM_RCE(pRce);
|
|
pRemoteIp = pArpRceContext->pRemoteIp;
|
|
|
|
if (pRemoteIp == NULL)
|
|
{
|
|
// We haven't initialized this RCE yet. Nothing to do...
|
|
//
|
|
return; // EARLY RETURN
|
|
}
|
|
|
|
|
|
if (VALID_REMOTE_IP(pRemoteIp)== FALSE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Remove pRce from pRemoteIP's list of RCEs.
|
|
//
|
|
for(
|
|
ppRce = &pRemoteIp->sendinfo.pRceList;
|
|
*ppRce != NULL;
|
|
ppRce = &(ARP_OUR_CTXT_FROM_RCE(*ppRce)->pNextRce))
|
|
{
|
|
if (*ppRce == pRce) break;
|
|
|
|
}
|
|
if (*ppRce == pRce)
|
|
{
|
|
*ppRce = pArpRceContext->pNextRce;
|
|
}
|
|
else
|
|
{
|
|
ASSERTEX(!"RCE Not in pRemoteIp's list!", pRce);
|
|
}
|
|
ARP_ZEROSTRUCT(pArpRceContext);
|
|
|
|
fDoDeref = (pRemoteIp->sendinfo.pRceList == NULL);
|
|
|
|
// The following macros are just so that we can make the proper debug association
|
|
// depending on how closely we are tracking outstanding send packets.
|
|
//
|
|
#if ARPDBG_REF_EVERY_RCE
|
|
fDoDeref = TRUE;
|
|
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) pRce)
|
|
#else // !ARPDBG_REF_EVERY_RCE
|
|
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) &pRemoteIp->sendinfo)
|
|
#endif // !ARPDBG_REF_EVERY_RCE
|
|
|
|
if (fDoDeref)
|
|
{
|
|
//
|
|
// If ARPDBG_REF_EVERY_RCE
|
|
// We add an "external" link for EVERY RCE. We'll later remove this
|
|
// reference when the RCE is invalidated.
|
|
// else
|
|
// Only a transition from zero to non-zero RCEs, we
|
|
// add an "external" link. We'll later remove this link when the
|
|
// transition from non-zero to zero happens.
|
|
//
|
|
|
|
#if RM_EXTRA_CHECKING
|
|
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
RmUnlinkFromExternalEx(
|
|
&pRemoteIp->Hdr, // pHdr
|
|
0x940df668, // LUID
|
|
OUR_EXTERNAL_ENTITY, // External entity
|
|
ARPASSOC_EXTLINK_RIP_TO_RCE, // AssocID
|
|
&sr
|
|
);
|
|
|
|
#else // !RM_EXTRA_CHECKING
|
|
|
|
RmUnlinkFromExternalFast(&pRemoteIp->Hdr);
|
|
|
|
#endif // !RM_EXTRA_CHECKING
|
|
|
|
}
|
|
|
|
#undef OUR_EXTERNAL_ENTITY
|
|
}
|
|
|
|
|
|
VOID
|
|
arpDelRceList(
|
|
IN PARPCB_REMOTE_IP pRemoteIp, // IF send lock WRITELOCKIN WRITELOCKOUTD
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Walks the RCE List, deleting each RoutCache Entry
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
RouteCacheEntry * pRce = pRemoteIp->sendinfo.pRceList;
|
|
|
|
//
|
|
// Delete all the Rce present on this remote Ip
|
|
//
|
|
|
|
while (pRce!= NULL)
|
|
{
|
|
//
|
|
// Delete the Rce and reduce the Ref
|
|
//
|
|
arpDelRce (pRce, pSR);
|
|
|
|
//
|
|
// Get the next RCE
|
|
//
|
|
pRce = pRemoteIp->sendinfo.pRceList;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
arpTaskSendPktsOnRemoteIp(
|
|
IN struct _RM_TASK * pTask,
|
|
IN RM_TASK_OPERATION Code,
|
|
IN UINT_PTR UserParam, // Unused
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Task handler responsible for sending queued packets on the pRemoteIp which
|
|
is its parent object. If required it must start the registration task and/or
|
|
the make-call task on the destination object.
|
|
|
|
Arguments:
|
|
|
|
UserParam for (Code == RM_TASKOP_START) : unused
|
|
|
|
--*/
|
|
{
|
|
ENTER("TaskSendPktsOnRemoteIp", 0xbc285d98)
|
|
NDIS_STATUS Status;
|
|
ARPCB_REMOTE_IP* pRemoteIp;
|
|
ARP1394_INTERFACE * pIF;
|
|
ARPCB_DEST * pDest;
|
|
MYBOOL fMakeCallIfRequired;
|
|
PARP1394_ADAPTER pAdapter;
|
|
MYBOOL fBridgeMode;
|
|
|
|
// Following are the list of pending states for this task.
|
|
//
|
|
enum
|
|
{
|
|
PEND_AddressResolutionComplete,
|
|
PEND_MakeCallComplete
|
|
};
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
pRemoteIp = (ARPCB_REMOTE_IP*) RM_PARENT_OBJECT(pTask);
|
|
pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pRemoteIp);
|
|
pAdapter = (PARP1394_ADAPTER) RM_PARENT_OBJECT(pIF);
|
|
pDest = NULL;
|
|
fMakeCallIfRequired = FALSE;
|
|
fBridgeMode = ARP_BRIDGE_ENABLED(pAdapter);
|
|
|
|
|
|
|
|
ASSERT_VALID_INTERFACE(pIF);
|
|
ASSERT_VALID_REMOTE_IP(pRemoteIp);
|
|
|
|
DBGMARK(0x6f31a739);
|
|
|
|
switch(Code)
|
|
{
|
|
case RM_TASKOP_START:
|
|
{
|
|
LOCKOBJ(pRemoteIp, pSR);
|
|
|
|
// First check if pRemoteIp is still allocated, if not we go away.
|
|
//
|
|
if (RM_IS_ZOMBIE(pRemoteIp))
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
// pRemoteIp is allocated. Now check if there is already a
|
|
// send-pkts task attached to pRemoteIp.
|
|
//
|
|
if (pRemoteIp->pSendPktsTask != NULL)
|
|
{
|
|
//
|
|
// There is a sendpkts task. Nothing for us to do -- simply return.
|
|
//
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
// Now we check if there is an UnloadTask bound to pRemoteIP. This
|
|
// is an IMPORTANT check -- because the unload task expects that
|
|
// once it is bound to pRemoteIp, no new pSendPktsTasks will bind
|
|
// themselves to pRemoteIp -- see arpTaskUnloadRemoteIp.
|
|
//
|
|
if (pRemoteIp->pUnloadTask != NULL)
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// There is no sendpkts task going on. Let's
|
|
// make this task THE sendpkts task.
|
|
//
|
|
pRemoteIp->pSendPktsTask = pTask;
|
|
|
|
//
|
|
// Since we're THE sendpks task, add an association to pRemoteIp,
|
|
// which will only get cleared when the pRemoteIp->pSendPktsTask field
|
|
// above is cleared.
|
|
//
|
|
DBG_ADDASSOC(
|
|
&pRemoteIp->Hdr, // pObject
|
|
pTask, // Instance1
|
|
pTask->Hdr.szDescription, // Instance2
|
|
ARPASSOC_REMOTEIP_SENDPKTS_TASK, // AssociationID
|
|
" Official sendpkts task 0x%p (%s)\n", // szFormat
|
|
pSR
|
|
);
|
|
|
|
if (pRemoteIp->pDest == NULL)
|
|
{
|
|
MYBOOL bIsDestNonUnicastAddr = FALSE;
|
|
//
|
|
// There is no pDest associated with pRemoteIp.
|
|
// If this is an on-unicast address, we link the local ip
|
|
// object to the broadcast object and proceed.
|
|
// NOTE: arpIsNonUnicastIpAddress is not a trivial operation -- it
|
|
// actually enumerates all local IP addresses. Fortunately we only
|
|
// call it for the FIRST packet sent out to an unresolved address.
|
|
//
|
|
if (fBridgeMode)
|
|
{
|
|
bIsDestNonUnicastAddr = arpIsNonUnicastEthAddress (pIF,&pRemoteIp->Key.ENetAddress,pSR);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(IS_REMOTE_DEST_IP_ADDRESS(&pRemoteIp->Key) == TRUE);
|
|
|
|
bIsDestNonUnicastAddr = arpIsNonUnicastIpAddress(pIF, pRemoteIp->IpAddress, pSR);
|
|
}
|
|
|
|
if (bIsDestNonUnicastAddr == TRUE)
|
|
{
|
|
ASSERT(pIF->pBroadcastDest != NULL); // Don't really expect it.
|
|
|
|
if (pIF->pBroadcastDest != NULL)
|
|
{
|
|
//
|
|
// Note: arpLinkRemoteIpToDest expects the locks
|
|
// on both pRemoteIp and pIF->pBroadcastDest to be
|
|
// held. We know that this is the case because both
|
|
// share the same lock, which is the IF lock.
|
|
//
|
|
RM_DBG_ASSERT_LOCKED(&pIF->pBroadcastDest->Hdr, pSR);
|
|
arpLinkRemoteIpToDest(
|
|
pRemoteIp,
|
|
pIF->pBroadcastDest,
|
|
pSR
|
|
);
|
|
SET_REMOTEIP_FCTYPE(pRemoteIp, ARPREMOTEIP_CHANNEL);
|
|
SET_REMOTEIP_SDTYPE(pRemoteIp, ARPREMOTEIP_DYNAMIC);
|
|
#if 0
|
|
if (CHECK_REMOTEIP_MCAP(pRemoteIp, ARPREMOTEIP_MCAP_CAPABLE))
|
|
{
|
|
SET_REMOTEIP_SDTYPE(pRemoteIp, ARPREMOTEIP_DYNAMIC);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We don't age out broadcast addresses.
|
|
//
|
|
SET_REMOTEIP_SDTYPE(pRemoteIp, ARPREMOTEIP_STATIC);
|
|
}
|
|
#endif // 0
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If there is a resolution task going, we wait for it to complete.
|
|
//
|
|
if (pRemoteIp->pResolutionTask != NULL)
|
|
{
|
|
PRM_TASK pOtherTask = pRemoteIp->pResolutionTask;
|
|
TR_WARN(("Resolution task %p exists; pending on it.\n", pOtherTask));
|
|
RmTmpReferenceObject(&pOtherTask->Hdr, pSR);
|
|
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
RmPendTaskOnOtherTask(
|
|
pTask,
|
|
PEND_AddressResolutionComplete,
|
|
pOtherTask,
|
|
pSR
|
|
);
|
|
RmTmpDereferenceObject(&pOtherTask->Hdr, pSR);
|
|
Status = NDIS_STATUS_PENDING;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// There is no address resolution task. Let's see if the
|
|
// address has been resolved. If not, we need to start the address
|
|
// resolution task.
|
|
//
|
|
if (pRemoteIp->pDest == NULL)
|
|
{
|
|
//
|
|
// Let's start the address resolution task!
|
|
//
|
|
PRM_TASK pResolutionTask;
|
|
|
|
DBGMARK(0xd0da6726);
|
|
|
|
//
|
|
// Let's start a resolution task and pend on it.
|
|
//
|
|
Status = arpAllocateTask(
|
|
&pRemoteIp->Hdr, // pParentObject
|
|
arpTaskResolveIpAddress, // pfnHandler
|
|
0, // Timeout
|
|
"Task: ResolveIpAddress", // szDescription
|
|
&pResolutionTask,
|
|
pSR
|
|
);
|
|
if (FAIL(Status))
|
|
{
|
|
// Couldn't allocate task. We fail with STATUS_RESOURCES
|
|
//
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
RmPendTaskOnOtherTask(
|
|
pTask,
|
|
PEND_AddressResolutionComplete,
|
|
pResolutionTask,
|
|
pSR
|
|
);
|
|
|
|
(VOID)RmStartTask(
|
|
pResolutionTask,
|
|
0, // UserParam unused
|
|
pSR
|
|
);
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
break;
|
|
}
|
|
|
|
pDest = pRemoteIp->pDest;
|
|
|
|
//
|
|
// We do have a pDest. Now see if there is a make call task on that
|
|
// pDest, and if so, we pend on it.
|
|
fMakeCallIfRequired = TRUE;
|
|
|
|
|
|
//
|
|
// We're here because there is no more async work to be done.
|
|
// We simply return and finish synchronous work in the END
|
|
// handler for this task.
|
|
//
|
|
|
|
} // START
|
|
break;
|
|
|
|
case RM_TASKOP_PENDCOMPLETE:
|
|
{
|
|
switch(RM_PEND_CODE(pTask))
|
|
{
|
|
case PEND_AddressResolutionComplete:
|
|
{
|
|
//
|
|
// There was address-resolution going on, but how it's
|
|
// complete. We should be go on to try to make a call now...
|
|
//
|
|
// If we're here, that means we're THE official SendPkts
|
|
// task. Let's assert that fact.
|
|
// (no need to get the lock on the object).
|
|
//
|
|
LOCKOBJ(pRemoteIp, pSR);
|
|
ASSERT(pRemoteIp->pSendPktsTask == pTask);
|
|
|
|
// We ignore the status of address resolution -- instead
|
|
// we just check if there is a destination associated with
|
|
// pRemoteIp.
|
|
//
|
|
pDest = pRemoteIp->pDest;
|
|
if (pDest == NULL)
|
|
{
|
|
// Nope -- no pDest. We fail the packets.
|
|
Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
// Yup, there is a destination. Now check if we need
|
|
// to make a call, etc...
|
|
//
|
|
fMakeCallIfRequired = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PEND_MakeCallComplete:
|
|
{
|
|
LOCKOBJ(pRemoteIp, pSR);
|
|
//
|
|
// If we're here, that means we're THE official SendPkts
|
|
// task. Let's assert that fact.
|
|
// (no need to get the lock on the object).
|
|
//
|
|
ASSERT(pRemoteIp->pSendPktsTask == pTask);
|
|
|
|
//
|
|
// There was a make-call task going on, but how it's
|
|
// complete. We're done with async processing.
|
|
// We actually send/fail queued packets in our END handler...
|
|
//
|
|
Status = (NDIS_STATUS) UserParam;
|
|
ASSERT(!PEND(Status));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
ASSERTEX(!"Unknown pend op", pTask);
|
|
}
|
|
break;
|
|
|
|
|
|
} // end switch(RM_PEND_CODE(pTask))
|
|
|
|
} // case RM_TASKOP_PENDCOMPLETE
|
|
break;
|
|
|
|
case RM_TASKOP_END:
|
|
{
|
|
LOCKOBJ(pRemoteIp, pSR);
|
|
|
|
//
|
|
// We're done. There should be no async activities left to do.
|
|
// At this point, if we can't immediately send packets on the FIFO,
|
|
// we simply fail all the packets.
|
|
//
|
|
|
|
//
|
|
// We don't bother to look at the Status. Instead we go ahead and
|
|
// try to send any queued packets.
|
|
//
|
|
|
|
//
|
|
// If we're THE sentpkts task, we go on actually send the packets.
|
|
//
|
|
if (pRemoteIp->pSendPktsTask == pTask)
|
|
{
|
|
DBGMARK(0xc627713c);
|
|
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
arpSendPktsQueuedOnRemoteIp(
|
|
pIF,
|
|
pRemoteIp,
|
|
pSR
|
|
);
|
|
|
|
LOCKOBJ(pRemoteIp, pSR);
|
|
// Delete the association we added when we set
|
|
// pRemoteIp->pSendPktsTask to pTask.
|
|
//
|
|
ASSERT(pRemoteIp->pSendPktsTask == pTask);
|
|
DBG_DELASSOC(
|
|
&pRemoteIp->Hdr, // pObject
|
|
pTask, // Instance1
|
|
pTask->Hdr.szDescription, // Instance2
|
|
ARPASSOC_REMOTEIP_SENDPKTS_TASK, // AssociationID
|
|
pSR
|
|
);
|
|
pRemoteIp->pSendPktsTask = NULL;
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We weren't THE unload task, nothing left to do.
|
|
//
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
break; // RM_TASKOP_END:
|
|
|
|
default:
|
|
{
|
|
ASSERTEX(!"Unexpected task op", pTask);
|
|
}
|
|
break;
|
|
|
|
} // switch (Code)
|
|
|
|
if (fMakeCallIfRequired)
|
|
{
|
|
//
|
|
// If necessary, make a call. If a make-call is already in process, pend
|
|
// on it.
|
|
//
|
|
|
|
// We rely on the fact that
|
|
// we share the same lock as pDest, and therefore is locked...
|
|
//
|
|
RM_DBG_ASSERT_LOCKED(&pDest->Hdr, pSR);
|
|
|
|
Status = arpMakeCallOnDest(pRemoteIp,
|
|
pDest,
|
|
pTask,
|
|
PEND_MakeCallComplete,
|
|
pSR);
|
|
|
|
}
|
|
|
|
RmUnlockAll(pSR);
|
|
|
|
EXIT()
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
arpCompleteSentPkt(
|
|
IN NDIS_STATUS Status,
|
|
IN ARP1394_INTERFACE * pIF,
|
|
IN ARPCB_DEST * pDest,
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle the completion (by the miniport) of a packet sent on a FIFO or Channel VC.
|
|
We strip out the encapsulation header we had tacked on prior to sending the
|
|
packet. If the packet belongs to IP, we call IP's send complete handler, else
|
|
we return it to our packet pool.
|
|
|
|
Arguments:
|
|
|
|
Status - Status of the completed send.
|
|
pIF - Interface object
|
|
pDest - Destination object on which packet was sent
|
|
pNdisPacket - Ndis packet that was sent.
|
|
|
|
--*/
|
|
{
|
|
PacketContext *PC; // IP/ARP Info about this packet
|
|
PNDIS_BUFFER pNdisBuffer; // First Buffer in this packet
|
|
ENTER("CompleteSentPkt", 0xc2b623b6)
|
|
UINT TotalLength;
|
|
MYBOOL IsFifo;
|
|
MYBOOL IsControlPacket;
|
|
|
|
|
|
ASSERT(pNdisPacket->Private.Head != NULL);
|
|
|
|
NdisQueryPacket(
|
|
pNdisPacket,
|
|
NULL, // we don't need PhysicalBufferCount
|
|
NULL, // we don't need BufferCount
|
|
NULL, // we don't need FirstBuffer (yet)
|
|
&TotalLength
|
|
);
|
|
|
|
IsFifo = pDest->sendinfo.IsFifo;
|
|
|
|
// Update stats...
|
|
//
|
|
{
|
|
if (IsFifo)
|
|
{
|
|
LOGSTATS_SendFifoCounts(pIF, pNdisPacket, Status);
|
|
}
|
|
else
|
|
{
|
|
LOGSTATS_SendChannelCounts(pIF, pNdisPacket, Status);
|
|
}
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
ARP_IF_STAT_ADD(pIF, OutOctets, TotalLength);
|
|
|
|
if (IsFifo)
|
|
{
|
|
ARP_IF_STAT_INCR(pIF, OutUnicastPkts);
|
|
}
|
|
else
|
|
{
|
|
ARP_IF_STAT_INCR(pIF, OutNonUnicastPkts);
|
|
}
|
|
}
|
|
else if (Status == NDIS_STATUS_RESOURCES)
|
|
{
|
|
ARP_IF_STAT_INCR(pIF, OutDiscards);
|
|
}
|
|
else
|
|
{
|
|
ARP_IF_STAT_INCR(pIF, OutErrors);
|
|
}
|
|
}
|
|
|
|
PC = (PacketContext *)pNdisPacket->ProtocolReserved;
|
|
|
|
TR_INFO(
|
|
("[%s]: pDest 0x%x, Pkt 0x%x, Status 0x%x:\n",
|
|
((PC->pc_common.pc_owner != PACKET_OWNER_LINK)? "IP": "ARP"),
|
|
pDest, pNdisPacket, Status));
|
|
|
|
NdisQueryPacket(pNdisPacket, NULL, NULL, &pNdisBuffer, NULL);
|
|
ASSERT(pNdisBuffer != NULL);
|
|
|
|
// Delete association added when sending packets.
|
|
//
|
|
{
|
|
MYBOOL DoDeref;
|
|
|
|
DoDeref =(InterlockedDecrement(&pDest->sendinfo.NumOutstandingSends)==0);
|
|
|
|
if (DoDeref)
|
|
{
|
|
MYBOOL TryResumeSuspendedCleanupTask = FALSE;
|
|
|
|
// The count of outstanding sends has touched zero. Let's
|
|
// check if there is a CleanupCall task waiting for all outstanding
|
|
// sends to complete, and if it makes sense to do so, we
|
|
// will resume it.
|
|
//
|
|
ARP_FASTREADLOCK_IF_SEND_LOCK(pIF);
|
|
if (pDest->sendinfo.pSuspendedCleanupCallTask!=NULL)
|
|
{
|
|
// It's likely that we'll need to resume this task.
|
|
//
|
|
TryResumeSuspendedCleanupTask = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// We do not need to resume any task. Nothing more to do...
|
|
//
|
|
}
|
|
ARP_FASTUNLOCK_IF_SEND_LOCK(pIF);
|
|
|
|
if (TryResumeSuspendedCleanupTask)
|
|
{
|
|
arpTryResumeSuspendedCleanupTask(pIF, pDest);
|
|
}
|
|
}
|
|
|
|
// The following macros are just so that we can make the proper debug
|
|
// association depending on how closely we are tracking outstanding send
|
|
// packets.
|
|
//
|
|
#if ARPDBG_REF_EVERY_PACKET
|
|
DoDeref = TRUE;
|
|
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) pNdisPacket)
|
|
#else // !ARPDBG_REF_EVERY_PACKET
|
|
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) &pDest->sendinfo)
|
|
#endif // !ARPDBG_REF_EVERY_PACKET
|
|
|
|
|
|
if (DoDeref)
|
|
{
|
|
//
|
|
// If ARPDBG_REF_EVERY_PKT
|
|
// We remove the "external" link added for EVERY packet.
|
|
// else
|
|
// Only a transition from non-zero to zero outstanding sends, we
|
|
// remove the "external" link.
|
|
//
|
|
|
|
#if RM_EXTRA_CHECKING
|
|
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
RmUnlinkFromExternalEx(
|
|
&pDest->Hdr, // pHdr
|
|
0x753db96f, // LUID
|
|
OUR_EXTERNAL_ENTITY, // External entity
|
|
ARPASSOC_EXTLINK_DEST_TO_PKT, // AssocID
|
|
&sr
|
|
);
|
|
|
|
#else // !RM_EXTRA_CHECKING
|
|
|
|
RmUnlinkFromExternalFast(&pDest->Hdr);
|
|
|
|
#endif // !RM_EXTRA_CHECKING
|
|
|
|
}
|
|
#undef OUR_EXTERNAL_ENTITY
|
|
|
|
}
|
|
|
|
//
|
|
// Check who generated this packet.
|
|
//
|
|
IsControlPacket = FALSE;
|
|
|
|
if (PC->pc_common.pc_owner == PACKET_OWNER_LINK)
|
|
{
|
|
IsControlPacket = TRUE;
|
|
}
|
|
|
|
if (IsControlPacket)
|
|
{
|
|
arpHandleControlPktSendCompletion(pIF, pNdisPacket);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Belongs to IP.
|
|
//
|
|
|
|
DBGMARK(0x2c48c626);
|
|
|
|
//
|
|
// Now check if we had attached a header buffer or not.
|
|
// NOTE: We rely on the fact that if we DID attach a header buffer,
|
|
// ARP_BACK_FILL_POSSIBLE will be false for this buffer.
|
|
//
|
|
DBGMARK(0x2f3b96f3);
|
|
if (ARP_BACK_FILL_POSSIBLE(pNdisBuffer))
|
|
{
|
|
const UINT HeaderLength = sizeof(Arp1394_IpEncapHeader);
|
|
|
|
//
|
|
// We would have back-filled IP's buffer with the Ip encapsulation
|
|
// header.
|
|
// Remove the back-fill.
|
|
//
|
|
(PUCHAR)pNdisBuffer->MappedSystemVa += HeaderLength;
|
|
pNdisBuffer->ByteOffset += HeaderLength;
|
|
pNdisBuffer->ByteCount -= HeaderLength;
|
|
}
|
|
else if (Status != NDIS_STATUS_NOT_RESETTABLE)
|
|
{
|
|
//
|
|
// The first buffer is our header buffer. Remove
|
|
// it from the packet and return to our pool.
|
|
//
|
|
NdisUnchainBufferAtFront(pNdisPacket, &pNdisBuffer);
|
|
arpDeallocateConstBuffer(
|
|
&pIF->sendinfo.HeaderPool,
|
|
pNdisBuffer
|
|
);
|
|
}
|
|
|
|
// Inform IP of send completion.
|
|
// NOTE: we don't get here in bridge mode because we only use
|
|
// control packets in bridge mode.
|
|
//
|
|
#if MILLEN
|
|
ASSERT_PASSIVE();
|
|
#endif // MILLEN
|
|
(*(pIF->ip.TxCmpltHandler))(
|
|
pIF->ip.Context,
|
|
pNdisPacket,
|
|
Status
|
|
);
|
|
}
|
|
|
|
EXIT()
|
|
}
|
|
|
|
|
|
VOID
|
|
arpTryResumeSuspendedCleanupTask(
|
|
IN ARP1394_INTERFACE * pIF, // NOLOCKIN NOLOCKOUT
|
|
IN ARPCB_DEST * pDest // NOLOCKIN NOLOCKOUT
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If there is a cleanup task associated with destination oject pDest that
|
|
is suspended waiting for the outstanding send count to go to zero, AND
|
|
if the outstanding send count has gone to zero, we resume the task. Otherwise
|
|
we do nothing.
|
|
|
|
Arguments:
|
|
|
|
pIF - Interface object
|
|
pDest - Destination object.
|
|
|
|
--*/
|
|
{
|
|
PRM_TASK pTask;
|
|
ENTER("TryResumeSuspendedCleanupTask", 0x1eccb1aa)
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
ARP_WRITELOCK_IF_SEND_LOCK(pIF, &sr);
|
|
pTask = pDest->sendinfo.pSuspendedCleanupCallTask;
|
|
if (pTask != NULL)
|
|
{
|
|
ASSERT(!ARP_CAN_SEND_ON_DEST(pDest));
|
|
if (pDest->sendinfo.NumOutstandingSends==0)
|
|
{
|
|
// We need to resume this task...
|
|
//
|
|
pDest->sendinfo.pSuspendedCleanupCallTask = NULL;
|
|
|
|
// Clear the association added when pTask started waiting for
|
|
// outstanding sends to complete.
|
|
//
|
|
DBG_DELASSOC(
|
|
&pDest->Hdr, // pObject
|
|
pTask, // Instance1
|
|
pTask->Hdr.szDescription, // Instance2
|
|
ARPASSOC_DEST_CLEANUPCALLTASK_WAITING_ON_SENDS,
|
|
&sr
|
|
);
|
|
RmTmpReferenceObject(&pTask->Hdr, &sr);
|
|
}
|
|
else
|
|
{
|
|
// There are other outstanding sends now. No need to do anything...
|
|
//
|
|
pTask = NULL;
|
|
}
|
|
}
|
|
ARP_UNLOCK_IF_SEND_LOCK(pIF, &sr);
|
|
|
|
|
|
if (pTask != NULL)
|
|
{
|
|
// Resume the CleanupCall task...
|
|
//
|
|
RmResumeTask(pTask, NDIS_STATUS_SUCCESS, &sr);
|
|
RmTmpDereferenceObject(&pTask->Hdr, &sr);
|
|
}
|
|
|
|
RM_ASSERT_CLEAR(&sr);
|
|
EXIT()
|
|
}
|
|
|
|
|
|
VOID
|
|
arpQueuePktOnRemoteIp(
|
|
IN PARPCB_REMOTE_IP pRemoteIp, // LOCKIN LOCKOUT
|
|
IN PNDIS_PACKET pNdisPacket,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Appends pkt pNdisPacket on remote object pRemoteIp's queue.
|
|
|
|
--*/
|
|
{
|
|
ARP_SEND_PKT_MPR_INFO *pOurPktInfo =
|
|
ARP_OUR_CTXT_FROM_SEND_PACKET(pNdisPacket);
|
|
|
|
|
|
RM_DBG_ASSERT_LOCKED(&pRemoteIp->Hdr, pSR);
|
|
|
|
#if RM_EXTRA_CHECKING
|
|
{
|
|
//
|
|
// If ARPDBG_REF_EVERY_PKT
|
|
// We add an dbgassociation for EVERY packet. We'll later remove
|
|
// this association when the send completes for this packet.
|
|
// else
|
|
// Only a transition from zero to non-zero queued pkts, we
|
|
// add an dbg association. We'll later remove this association when
|
|
// the transition from non-zero to zero happens.
|
|
//
|
|
MYBOOL DoAssoc;
|
|
|
|
#if ARPDBG_REF_EVERY_PACKET
|
|
DoAssoc = TRUE;
|
|
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) pNdisPacket)
|
|
#define szARPSSOC_QUEUED_PKT_FORMAT " Queued pkt 0x%p\n"
|
|
#else // !ARPDBG_REF_EVERY_PACKET
|
|
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) &pDest->)
|
|
#define szARPSSOC_QUEUED_PKT_FORMAT " Outstanding pkts. &si=0x%p\n"
|
|
DoAssoc = IsListEmpty(&pRemoteIp->sendinfo.listSendPkts);
|
|
#endif // !ARPDBG_REF_EVERY_PACKET
|
|
|
|
if (DoAssoc)
|
|
{
|
|
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
RmDbgAddAssociation(
|
|
0x3c08a7f5, // LOCID
|
|
&pRemoteIp->Hdr, // pHdr
|
|
(UINT_PTR) OUR_EXTERNAL_ENTITY, // Entity1
|
|
0, // Entity2
|
|
ARPASSOC_PKTS_QUEUED_ON_REMOTEIP, // AssocID
|
|
szARPSSOC_QUEUED_PKT_FORMAT,
|
|
&sr
|
|
);
|
|
}
|
|
#undef OUR_EXTERNAL_ENTITY
|
|
#undef szARPSSOC_EXTLINK_DEST_TO_PKT_FORMAT
|
|
}
|
|
#endif // !RM_EXTRA_CHECKING
|
|
DBGMARK(0x007a0585);
|
|
|
|
InsertHeadList(
|
|
&pRemoteIp->sendinfo.listSendPkts,
|
|
&pOurPktInfo->linkQueue
|
|
);
|
|
}
|
|
|
|
|
|
VOID
|
|
arpSendPktsQueuedOnRemoteIp(
|
|
IN ARP1394_INTERFACE * pIF, // NOLOCKIN NOLOCKOUT
|
|
IN ARPCB_REMOTE_IP * pRemoteIp, // NOLOCKIN NOLOCKOUT
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send all packets queued on remote ip object pRemoteIp. If packets can't
|
|
be sent at this time for any reason, fail the sends.
|
|
|
|
ASSUMPTION: We expect pIF and pRemoteIp to be around while we're in this
|
|
function.
|
|
|
|
--*/
|
|
|
|
{
|
|
ENTER("SendPktsQueuedOnRemoteIp", 0x2b125d7f)
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
|
|
LOCKOBJ(pRemoteIp, pSR);
|
|
|
|
DBGMARK(0xe4950c47);
|
|
do
|
|
{
|
|
PARPCB_DEST pDest = NULL;
|
|
|
|
if(RM_IS_ZOMBIE(pRemoteIp))
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
pDest = pRemoteIp->pDest;
|
|
|
|
if (pDest != NULL)
|
|
{
|
|
RmTmpReferenceObject(&pDest->Hdr, pSR);
|
|
}
|
|
|
|
//
|
|
// Send or fail all packets in our queue.
|
|
// TODO: Implement send multiple pkts.
|
|
//
|
|
while (!IsListEmpty(&pRemoteIp->sendinfo.listSendPkts))
|
|
{
|
|
PLIST_ENTRY plinkPkt;
|
|
PNDIS_PACKET pNdisPacket;
|
|
ARP_SEND_PKT_MPR_INFO * pOurPktCtxt;
|
|
|
|
//
|
|
// Extract pkt from tail and send it on it's merry way...
|
|
//
|
|
|
|
plinkPkt = RemoveTailList(&pRemoteIp->sendinfo.listSendPkts);
|
|
|
|
// From link to our pkt context...
|
|
//
|
|
pOurPktCtxt = CONTAINING_RECORD(
|
|
plinkPkt,
|
|
ARP_SEND_PKT_MPR_INFO,
|
|
linkQueue
|
|
);
|
|
|
|
// From our pkt context to the ndis pkt.
|
|
//
|
|
pNdisPacket = ARP_SEND_PKT_FROM_OUR_CTXT(pOurPktCtxt);
|
|
|
|
|
|
#if RM_EXTRA_CHECKING
|
|
{
|
|
//
|
|
// If ARPDBG_REF_EVERY_PKT
|
|
// We delete thhe dbgassociation added for EVERY packet.
|
|
// else
|
|
// Only a transition from non-zero zero queued pkts, we
|
|
// delete the dbg association added when the
|
|
// transition from zero to non-zero happened.
|
|
//
|
|
MYBOOL DoDelAssoc;
|
|
|
|
#if ARPDBG_REF_EVERY_PACKET
|
|
DoDelAssoc = TRUE;
|
|
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) pNdisPacket)
|
|
#else // !ARPDBG_REF_EVERY_PACKET
|
|
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) &pDest->)
|
|
DoDelAssoc = IsListEmpty(&pRemoteIp->sendinfo.listSendPkts);
|
|
#endif // !ARPDBG_REF_EVERY_PACKET
|
|
|
|
if (DoDelAssoc)
|
|
{
|
|
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
RmDbgDeleteAssociation(
|
|
0x3c08a7f5, // LOCID
|
|
&pRemoteIp->Hdr, // pHdr
|
|
(UINT_PTR) OUR_EXTERNAL_ENTITY, // Entity1
|
|
0, // Entity2
|
|
ARPASSOC_PKTS_QUEUED_ON_REMOTEIP, // AssocID
|
|
&sr
|
|
);
|
|
}
|
|
#undef OUR_EXTERNAL_ENTITY
|
|
}
|
|
#endif // !RM_EXTRA_CHECKING
|
|
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
|
|
if (pDest == NULL
|
|
|| ( g_DiscardNonUnicastPackets
|
|
&& CHECK_REMOTEIP_FCTYPE( pRemoteIp, ARPREMOTEIP_CHANNEL)))
|
|
|
|
{
|
|
ARP1394_ADAPTER * pAdapter =
|
|
(ARP1394_ADAPTER*) RM_PARENT_OBJECT(pIF);
|
|
MYBOOL fBridgeMode = ARP_BRIDGE_ENABLED(pAdapter);
|
|
|
|
// Fail the packet right here...
|
|
//
|
|
// TODO: we current update the SendFifoCounts here, because
|
|
// all non-unicast bcasts resolve to the already existing
|
|
// broadcast channel. Once we have MCAP going, we need to keep
|
|
// a flag in pRemoteIp indicating whether or not this is a
|
|
// unicast address.
|
|
//
|
|
LOGSTATS_SendFifoCounts(pIF, pNdisPacket, NDIS_STATUS_FAILURE);
|
|
|
|
if (fBridgeMode)
|
|
{
|
|
// In bridge (ethernet emulation) mode, we created the
|
|
// packets ourselves, so we delete them here, instead
|
|
// of calling Ip's completion handler, which in fact
|
|
// is NULL.
|
|
//
|
|
arpFreeControlPacket(
|
|
pIF,
|
|
pNdisPacket,
|
|
pSR
|
|
);
|
|
}
|
|
else
|
|
{
|
|
#if MILLEN
|
|
ASSERT_PASSIVE();
|
|
#endif // MILLEN
|
|
|
|
NdisInterlockedIncrement (&ArpSendCompletes);
|
|
NdisInterlockedIncrement (&ArpSendFailure);
|
|
|
|
|
|
(*(pIF->ip.TxCmpltHandler))(
|
|
pIF->ip.Context,
|
|
pNdisPacket,
|
|
NDIS_STATUS_FAILURE
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Get IF send lock (fast version)
|
|
//
|
|
ARP_FASTREADLOCK_IF_SEND_LOCK(pIF);
|
|
|
|
arpSendIpPkt(
|
|
pIF, // IF send lock: LOCKING NOLOCKOUT
|
|
pDest,
|
|
pNdisPacket
|
|
);
|
|
|
|
// Note that we're locking pRemoteIp's lock, not the IF send lock
|
|
// here. pRemoteIp->sendinfo.listSendPkts is protected by the
|
|
// the following lock, not the IF send lock.
|
|
//
|
|
}
|
|
LOCKOBJ(pRemoteIp, pSR);
|
|
}
|
|
|
|
if (pDest != NULL)
|
|
{
|
|
RmTmpDereferenceObject(&pDest->Hdr, pSR);
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
UNLOCKOBJ(pRemoteIp, pSR);
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
EXIT()
|
|
}
|
|
|
|
|
|
VOID
|
|
arpLogSendFifoCounts(
|
|
IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
|
|
IN PNDIS_PACKET pNdisPacket,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
TODO: Very similar to arpLogSendChannelCounts, consider merging these two
|
|
functions.
|
|
--*/
|
|
{
|
|
PULONG pCount;
|
|
ULONG SizeBin, TimeBin;
|
|
|
|
arpGetPktCountBins(pIF, pNdisPacket, &SizeBin, &TimeBin);
|
|
|
|
//
|
|
// Increment the count
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pCount = &(pIF->stats.sendpkts.SendFifoCounts.GoodCounts[SizeBin][TimeBin]);
|
|
}
|
|
else
|
|
{
|
|
pCount = &(pIF->stats.sendpkts.SendFifoCounts.BadCounts[SizeBin][TimeBin]);
|
|
}
|
|
NdisInterlockedIncrement(pCount);
|
|
}
|
|
|
|
|
|
VOID
|
|
arpLogRecvFifoCounts(
|
|
IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
{
|
|
PULONG pCount;
|
|
ULONG SizeBin;
|
|
|
|
arpGetPktCountBins(pIF, pNdisPacket, &SizeBin, NULL);
|
|
|
|
//
|
|
// Increment the count
|
|
pCount = &(pIF->stats.recvpkts.RecvFifoCounts.GoodCounts[SizeBin][0]);
|
|
NdisInterlockedIncrement(pCount);
|
|
}
|
|
|
|
|
|
VOID
|
|
arpLogSendChannelCounts(
|
|
IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
|
|
IN PNDIS_PACKET pNdisPacket,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
{
|
|
PULONG pCount;
|
|
ULONG SizeBin, TimeBin;
|
|
|
|
arpGetPktCountBins(pIF, pNdisPacket, &SizeBin, &TimeBin);
|
|
|
|
//
|
|
// Increment the count
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pCount =&(pIF->stats.sendpkts.SendChannelCounts.GoodCounts[SizeBin][TimeBin]);
|
|
}
|
|
else
|
|
{
|
|
pCount =&(pIF->stats.sendpkts.SendChannelCounts.BadCounts[SizeBin][TimeBin]);
|
|
}
|
|
NdisInterlockedIncrement(pCount);
|
|
}
|
|
|
|
|
|
VOID
|
|
arpLogRecvChannelCounts(
|
|
IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
{
|
|
PULONG pCount;
|
|
ULONG SizeBin;
|
|
|
|
arpGetPktCountBins(pIF, pNdisPacket, &SizeBin, NULL);
|
|
|
|
//
|
|
// Increment the count
|
|
pCount = &(pIF->stats.recvpkts.RecvChannelCounts.GoodCounts[SizeBin][0]);
|
|
NdisInterlockedIncrement(pCount);
|
|
}
|
|
|
|
VOID
|
|
arpGetPktCountBins(
|
|
IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
|
|
IN PNDIS_PACKET pNdisPacket,
|
|
OUT PULONG pSizeBin,
|
|
OUT PULONG pTimeBin // OPTIONAL
|
|
)
|
|
{
|
|
ULONG Size;
|
|
ULONG SizeBin;
|
|
|
|
if (pTimeBin != NULL)
|
|
{
|
|
//
|
|
// Compute the packet send duration
|
|
//
|
|
|
|
ULONG StartSendTick, EndSendTick;
|
|
LARGE_INTEGER liTemp;
|
|
ULONG TimeDelta;
|
|
ULONG TimeBin;
|
|
|
|
liTemp = KeQueryPerformanceCounter(NULL);
|
|
EndSendTick = liTemp.LowPart;
|
|
StartSendTick = *(PULONG) ((pNdisPacket)->WrapperReservedEx);
|
|
if (EndSendTick > StartSendTick)
|
|
{
|
|
TimeDelta = EndSendTick - StartSendTick;
|
|
}
|
|
else
|
|
{
|
|
TimeDelta = (ULONG) (((ULONG) -1) - (StartSendTick - EndSendTick));
|
|
}
|
|
|
|
// Convert from ticks to microseconds.
|
|
// (Check that the frequence is non zero -- we could be in the middle
|
|
// of a stats-reset, and don't want to cause a devide-by-zero exception).
|
|
//
|
|
liTemp = pIF->stats.PerformanceFrequency;
|
|
if (liTemp.QuadPart != 0)
|
|
{
|
|
ULONGLONG ll;
|
|
ll = TimeDelta;
|
|
ll *= 1000000;
|
|
ll /= liTemp.QuadPart;
|
|
ASSERT(ll == (ULONG)ll);
|
|
TimeDelta = (ULONG) ll;
|
|
}
|
|
else
|
|
{
|
|
TimeDelta = 0; // bogus value.
|
|
}
|
|
|
|
//
|
|
// Compute the time bin based on the send duration
|
|
//
|
|
if (TimeDelta <= 100)
|
|
{
|
|
TimeBin = ARP1394_PKTTIME_100US;
|
|
}
|
|
else if (TimeDelta <= 1000)
|
|
{
|
|
TimeBin = ARP1394_PKTTIME_1MS;
|
|
}
|
|
else if (TimeDelta <= 10000)
|
|
{
|
|
TimeBin = ARP1394_PKTTIME_10MS;
|
|
}
|
|
else if (TimeDelta <= 100000)
|
|
{
|
|
TimeBin = ARP1394_PKTTIME_100MS;
|
|
}
|
|
else // (TimeDelta > 100000)
|
|
{
|
|
TimeBin = ARP1394_PKTTIME_G100MS;
|
|
}
|
|
|
|
*pTimeBin = TimeBin;
|
|
}
|
|
|
|
//
|
|
// Compute the packet size
|
|
NdisQueryPacket(
|
|
pNdisPacket,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Size
|
|
);
|
|
|
|
//
|
|
// Compute the size bin based on the packet size
|
|
if (Size <= 128)
|
|
{
|
|
SizeBin = ARP1394_PKTSIZE_128;
|
|
}
|
|
else if (Size <= 256)
|
|
{
|
|
SizeBin = ARP1394_PKTSIZE_256;
|
|
}
|
|
else if (Size <= 1024)
|
|
{
|
|
SizeBin = ARP1394_PKTSIZE_1K;
|
|
}
|
|
else if (Size <= 2048)
|
|
{
|
|
SizeBin = ARP1394_PKTSIZE_2K;
|
|
}
|
|
else // Size > 2048
|
|
{
|
|
SizeBin = ARP1394_PKTSIZE_G2K;
|
|
}
|
|
|
|
*pSizeBin = SizeBin;
|
|
|
|
}
|
|
|
|
// This table is used in the calculations to determine if a particular address is
|
|
// non-unicast.
|
|
// TODO: Make this and all other static data into const.
|
|
//
|
|
IP_MASK g_ArpIPMaskTable[] =
|
|
{
|
|
CLASSA_MASK,
|
|
CLASSA_MASK,
|
|
CLASSA_MASK,
|
|
CLASSA_MASK,
|
|
CLASSA_MASK,
|
|
CLASSA_MASK,
|
|
CLASSA_MASK,
|
|
CLASSA_MASK,
|
|
CLASSB_MASK,
|
|
CLASSB_MASK,
|
|
CLASSB_MASK,
|
|
CLASSB_MASK,
|
|
CLASSC_MASK,
|
|
CLASSC_MASK,
|
|
CLASSD_MASK,
|
|
CLASSE_MASK
|
|
};
|
|
|
|
|
|
#define ARP_IPNETMASK(a) g_ArpIPMaskTable[(*(uchar *)&(a)) >> 4]
|
|
|
|
|
|
// Context passed to the enum function for checking if a particular
|
|
// address is non-unicast.
|
|
//
|
|
typedef struct
|
|
{
|
|
IP_ADDRESS IpAddress;
|
|
IP_ADDRESS BroadcastAddress;
|
|
MYBOOL IsNonUnicast;
|
|
|
|
|
|
} ARP_NONUNICAST_CTXT, *PARP_NONUNICAST_CTXT;
|
|
|
|
|
|
// The enum function for the above operation.
|
|
//
|
|
INT
|
|
arpCheckForNonUnicastAddress(
|
|
PRM_OBJECT_HEADER pHdr,
|
|
PVOID pvContext,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
{
|
|
PARPCB_LOCAL_IP pLocalIp;
|
|
PARP_NONUNICAST_CTXT pOurCtxt;
|
|
IP_ADDRESS Addr;
|
|
IP_ADDRESS BCast;
|
|
IP_ADDRESS LocalAddr;
|
|
IP_MASK Mask;
|
|
|
|
pLocalIp = (PARPCB_LOCAL_IP) pHdr;
|
|
|
|
// If this local ip address is non-unicast, skip it.
|
|
//
|
|
if (pLocalIp->IpAddressType != LLIP_ADDR_LOCAL)
|
|
{
|
|
return TRUE; // *** EARLY RETURN *** (continue to enumerate)
|
|
}
|
|
|
|
pOurCtxt = (PARP_NONUNICAST_CTXT) pvContext;
|
|
Addr = pOurCtxt->IpAddress;
|
|
LocalAddr= pLocalIp->IpAddress;
|
|
BCast = pOurCtxt->BroadcastAddress;
|
|
|
|
// First check for subnet bcast.
|
|
//
|
|
Mask = pLocalIp->IpMask;
|
|
if (IP_ADDR_EQUAL((LocalAddr & Mask) | (BCast & ~Mask), Addr))
|
|
{
|
|
pOurCtxt->IsNonUnicast = TRUE;
|
|
return FALSE; // Stop enumerating
|
|
}
|
|
|
|
// Now check all nets broadcast.
|
|
Mask = ARP_IPNETMASK(LocalAddr);
|
|
if (IP_ADDR_EQUAL((LocalAddr & Mask) | (BCast & ~Mask), Addr))
|
|
{
|
|
pOurCtxt->IsNonUnicast = TRUE;
|
|
return FALSE; // Stop enumerating
|
|
}
|
|
|
|
return TRUE; // Continue to enumerate.
|
|
}
|
|
|
|
|
|
MYBOOL
|
|
arpIsNonUnicastEthAddress (
|
|
IN PARP1394_INTERFACE pIF, // LOCKIN LOCKOUT
|
|
IN ENetAddr* pAddr,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if the given IP address is a non-unicast (broadcast or multicast) address
|
|
for the interface.
|
|
|
|
Copied from IP/ATM module (atmarpc.sys)
|
|
|
|
Arguments:
|
|
|
|
Addr - The Eth Address to be checked
|
|
pInterface - Pointer to our Interface structure
|
|
|
|
Return Value:
|
|
|
|
TRUE if the address is a non-unicast address, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
MYBOOL fIsNonUnicastEthAddress = FALSE;
|
|
MYBOOL fIsMulticast = FALSE;
|
|
MYBOOL fIsBroadcast = FALSE;
|
|
|
|
fIsMulticast = ETH_IS_MULTICAST (pAddr);
|
|
|
|
fIsBroadcast = ETH_IS_BROADCAST (pAddr);
|
|
|
|
//
|
|
// if it is either a Multicast or a Unicast address than
|
|
// it is a non-unicast address
|
|
//
|
|
fIsNonUnicastEthAddress = (fIsMulticast || fIsBroadcast );
|
|
|
|
return (fIsNonUnicastEthAddress );
|
|
}
|
|
|
|
MYBOOL
|
|
arpIsNonUnicastIpAddress(
|
|
IN PARP1394_INTERFACE pIF, // LOCKIN LOCKOUT
|
|
IN IP_ADDRESS Addr,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if the given IP address is a non-unicast (broadcast or multicast) address
|
|
for the interface.
|
|
|
|
Copied from IP/ATM module (atmarpc.sys)
|
|
|
|
Arguments:
|
|
|
|
Addr - The IP Address to be checked
|
|
pInterface - Pointer to our Interface structure
|
|
|
|
Return Value:
|
|
|
|
TRUE if the address is a non-unicast address, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
IP_ADDRESS BCast;
|
|
IP_MASK Mask;
|
|
// PIP_ADDRESS_ENTRY pIpAddressEntry;
|
|
IP_ADDRESS LocalAddr;
|
|
|
|
// Get the interface broadcast address.
|
|
BCast = pIF->ip.BroadcastAddress;
|
|
|
|
// Check for global broadcast and multicast.
|
|
if (IP_ADDR_EQUAL(BCast, Addr) || CLASSD_ADDR(Addr))
|
|
return TRUE;
|
|
|
|
// Look through all our local ip addresses, checking for subnet and net
|
|
// broadcast addresses.
|
|
//
|
|
{
|
|
ARP_NONUNICAST_CTXT Ctxt;
|
|
Ctxt.IsNonUnicast = FALSE;
|
|
Ctxt.IpAddress = Addr;
|
|
Ctxt.BroadcastAddress = BCast;
|
|
|
|
RmEnumerateObjectsInGroup(
|
|
&pIF->LocalIpGroup,
|
|
arpCheckForNonUnicastAddress,
|
|
&Ctxt,
|
|
TRUE, // Choose strong enumeration
|
|
pSR
|
|
);
|
|
|
|
return Ctxt.IsNonUnicast;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
arpRefSendPkt(
|
|
PNDIS_PACKET pNdisPacket,
|
|
PARPCB_DEST pDest // LOCKIN LOCKOUT (readlock, IF Send lock)
|
|
)
|
|
{
|
|
MYBOOL DoRef;
|
|
|
|
// Note, we just have a READ lock on the IF send lock. So the following
|
|
// needs to be an interlocked operation ...
|
|
//
|
|
DoRef = (InterlockedIncrement(&pDest->sendinfo.NumOutstandingSends) == 1);
|
|
|
|
// The following macros are just so that we can make the proper debug association
|
|
// depending on how closely we are tracking outstanding send packets.
|
|
//
|
|
#if ARPDBG_REF_EVERY_PACKET
|
|
DoRef = TRUE;
|
|
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) pNdisPacket)
|
|
#define szARPSSOC_EXTLINK_DEST_TO_PKT_FORMAT " Outstanding send pkt 0x%p\n"
|
|
#else // !ARPDBG_REF_EVERY_PACKET
|
|
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) &pDest->sendinfo)
|
|
#define szARPSSOC_EXTLINK_DEST_TO_PKT_FORMAT " Outstanding pkts. &si=0x%p\n"
|
|
#endif // !ARPDBG_REF_EVERY_PACKET
|
|
|
|
|
|
if (DoRef)
|
|
{
|
|
//
|
|
// If ARPDBG_REF_EVERY_PKT
|
|
// We add an "external" link for EVERY packet. We'll later remove this
|
|
// reference when the send completes for this packet.
|
|
// else
|
|
// Only a transition from zero to non-zero outstanding sends, we
|
|
// add an "external" link. We'll later remove this link when the
|
|
// transition from non-zero to zero happens.
|
|
//
|
|
|
|
#if RM_EXTRA_CHECKING
|
|
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
RmLinkToExternalEx(
|
|
&pDest->Hdr, // pHdr
|
|
0x13f839b4, // LUID
|
|
OUR_EXTERNAL_ENTITY, // External entity
|
|
ARPASSOC_EXTLINK_DEST_TO_PKT, // AssocID
|
|
szARPSSOC_EXTLINK_DEST_TO_PKT_FORMAT,
|
|
&sr
|
|
);
|
|
|
|
#else // !RM_EXTRA_CHECKING
|
|
|
|
RmLinkToExternalFast(&pDest->Hdr);
|
|
|
|
#endif // !RM_EXTRA_CHECKING
|
|
|
|
}
|
|
#undef OUR_EXTERNAL_ENTITY
|
|
#undef szARPSSOC_EXTLINK_DEST_TO_PKT_FORMAT
|
|
}
|
|
|
|
VOID
|
|
arpHandleControlPktSendCompletion(
|
|
IN ARP1394_INTERFACE * pIF,
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
{
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
arpFreeControlPacket(
|
|
pIF,
|
|
pNdisPacket,
|
|
&sr
|
|
);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
arpCanTryMcap(
|
|
IP_ADDRESS IpAddress
|
|
)
|
|
/*++
|
|
Return TRUE IFF this is an MCAP compatible address.
|
|
|
|
For now that means that it's a class D address, but not
|
|
224.0.0.1 or 224.0.0.2
|
|
|
|
--*/
|
|
{
|
|
// 1st check if it's a multicast address.
|
|
//
|
|
if ( (IpAddress & 0xf0) == 0xe0)
|
|
{
|
|
//
|
|
// Then check for special multicast addresses 224.0.0.1 and 224.0.0.2
|
|
// The ip/1395 rfc states that these two addresses must be
|
|
// send on the broadcast channel.
|
|
//
|
|
if ( (IpAddress != 0x010000e0) && (IpAddress != 0x020000e0))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
arpLoopbackNdisPacket(
|
|
PARP1394_INTERFACE pIF,
|
|
PARPCB_DEST pBroadcastDest,
|
|
PNDIS_PACKET pOldPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
if this is being sent to a broadcast destination, then allocate a new
|
|
packet and loop it back up to the protocols.
|
|
|
|
Arguments:
|
|
|
|
pIF - Pointer to the Interface on which the packet is sent
|
|
pBroadcastDest - The Destination to which the packet is being sent.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the address is a non-unicast address, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PACKET pNewPkt = NULL;
|
|
const UINT MacHeaderLength = sizeof(NIC1394_ENCAPSULATION_HEADER);
|
|
PUCHAR pPayloadDataVa = NULL;
|
|
UINT TotalLength = 0;
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
UINT HeadBufferLength = 0;
|
|
PUCHAR pHeadBufferVa = NULL;
|
|
|
|
do
|
|
{
|
|
//Allocate the packet
|
|
|
|
|
|
NdisAllocatePacket(
|
|
&Status,
|
|
&pNewPkt,
|
|
pIF->arp.PacketPool
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS || pNewPkt == NULL)
|
|
{
|
|
pNewPkt = NULL;
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
// set up the head and tail
|
|
|
|
pNewPkt->Private.Head = pOldPacket->Private.Head;
|
|
pNewPkt->Private.Tail = pOldPacket->Private.Tail;
|
|
|
|
pNewPkt->Private.ValidCounts = FALSE;
|
|
|
|
|
|
// indicate the packet with a status of resources
|
|
|
|
NDIS_SET_PACKET_STATUS (pNewPkt, NDIS_STATUS_RESOURCES);
|
|
|
|
HeadBufferLength = NdisBufferLength (pNewPkt->Private.Head);
|
|
pHeadBufferVa = NdisBufferVirtualAddressSafe (pNewPkt->Private.Head, NormalPagePriority );
|
|
|
|
if (pHeadBufferVa ==NULL)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
if (HeadBufferLength <= MacHeaderLength)
|
|
{
|
|
// we need to go the next NdisBuffer to get the Start of data
|
|
//
|
|
pPayloadDataVa = NdisBufferVirtualAddressSafe (pNewPkt->Private.Head->Next, NormalPagePriority );
|
|
|
|
if (pPayloadDataVa == NULL)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
if (HeadBufferLength != MacHeaderLength)
|
|
{
|
|
pPayloadDataVa += (MacHeaderLength - HeadBufferLength);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The payload is within the Buffer
|
|
pPayloadDataVa += MacHeaderLength ;
|
|
|
|
}
|
|
|
|
if (pOldPacket->Private.ValidCounts == TRUE)
|
|
{
|
|
TotalLength = pOldPacket->Private.TotalLength;
|
|
|
|
}
|
|
else
|
|
{
|
|
NdisQueryPacket(pOldPacket, NULL, NULL, NULL, &TotalLength);
|
|
|
|
}
|
|
|
|
|
|
pIF->ip.RcvHandler(
|
|
pIF->ip.Context,
|
|
(PVOID)(pPayloadDataVa),
|
|
HeadBufferLength - MacHeaderLength,
|
|
TotalLength - MacHeaderLength,
|
|
(NDIS_HANDLE)pNewPkt,
|
|
MacHeaderLength,
|
|
TRUE, //IsChannel
|
|
NULL
|
|
);
|
|
|
|
|
|
}while (FALSE);
|
|
|
|
if (pNewPkt != NULL)
|
|
{
|
|
NdisFreePacket (pNewPkt);
|
|
pNewPkt = NULL;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
REMOTE_DEST_KEY
|
|
RemoteIPKeyFromIPAddress (
|
|
IPAddr IpAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Creates a RemoteIPKey structure from an IP Address
|
|
by tagging two constant bytes
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
New Remote Ip Key
|
|
|
|
--*/
|
|
{
|
|
REMOTE_DEST_KEY RemoteIpKey ={0,0,0,0,0,0} ;
|
|
|
|
ASSERT (sizeof (REMOTE_DEST_KEY)==sizeof(ENetAddr));
|
|
|
|
RemoteIpKey.IpAddress = IpAddress;
|
|
|
|
return RemoteIpKey;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
arpDelArpEntry(
|
|
PARP1394_INTERFACE pIF,
|
|
IPAddr IpAddress,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
{
|
|
ENTER("DelArpEntry", 0x3427306a)
|
|
NTSTATUS NtStatus;
|
|
|
|
TR_WARN(("DEL ARP ENTRY\n"));
|
|
NtStatus = STATUS_UNSUCCESSFUL;
|
|
|
|
do
|
|
{
|
|
NDIS_STATUS Status;
|
|
NIC1394_FIFO_ADDRESS FifoAddress;
|
|
PARPCB_REMOTE_IP pRemoteIp;
|
|
PRM_TASK pUnloadObjectTask;
|
|
REMOTE_DEST_KEY RemoteDestKey;
|
|
|
|
// If this is a Subnet broadcast IP address, then skip the delete
|
|
//
|
|
#define ARP1394_SUBNET_BROADCAST_IP 0xffff0000
|
|
|
|
if ((IpAddress & ARP1394_SUBNET_BROADCAST_IP ) == ARP1394_SUBNET_BROADCAST_IP )
|
|
{
|
|
break;
|
|
}
|
|
|
|
LOCKOBJ(pIF, pSR);
|
|
|
|
//
|
|
// Initialize the RemoteDestKey
|
|
//
|
|
REMOTE_DEST_KEY_INIT(&RemoteDestKey);
|
|
|
|
RemoteDestKey.IpAddress = IpAddress;
|
|
//
|
|
// Lookup the RemoteIp entry corresponding to this entry and unload
|
|
// it.
|
|
//
|
|
Status = RmLookupObjectInGroup(
|
|
&pIF->RemoteIpGroup,
|
|
0, // Flags
|
|
(PVOID) &RemoteDestKey, // pKey
|
|
NULL, // pvCreateParams
|
|
&(PRM_OBJECT_HEADER)pRemoteIp,
|
|
NULL, // pfCreated
|
|
pSR
|
|
);
|
|
|
|
UNLOCKOBJ(pIF, pSR);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Found pRemoteIp. Let's initiate the unload of pRemoteIp. We won't wait
|
|
// around for it to complete.
|
|
//
|
|
Status = arpAllocateTask(
|
|
&pRemoteIp->Hdr, // pParentObject,
|
|
arpTaskUnloadRemoteIp, // pfnHandler,
|
|
0, // Timeout,
|
|
"Task:Unload RemoteIp (DelArpEntry)",
|
|
&pUnloadObjectTask,
|
|
pSR
|
|
);
|
|
RmTmpDereferenceObject(&pRemoteIp->Hdr, pSR);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
TR_WARN(("Couldn't allocate unload remoteip task."));
|
|
break;
|
|
}
|
|
|
|
RmStartTask(
|
|
pUnloadObjectTask,
|
|
0, // UserParam (unused)
|
|
pSR
|
|
);
|
|
|
|
NtStatus = STATUS_SUCCESS; // always succeed
|
|
|
|
} while (FALSE);
|
|
|
|
EXIT()
|
|
return NtStatus;
|
|
}
|
|
|
|
|