2719 lines
61 KiB
C
2719 lines
61 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1996 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
adapter.c - Adapter Interface routines.
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Handlers for adapter events are here. The only exception is the
|
||
|
CoReceivePacket handler, which is in arppkt.c.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Who When What
|
||
|
-------- -------- ----------------------------------------------
|
||
|
arvindm 08-12-96 Created
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
#include <precomp.h>
|
||
|
|
||
|
#define _FILENUMBER 'PADA'
|
||
|
|
||
|
ULONG MCastSendOk = 0;
|
||
|
ULONG MCastSendFail = 0;
|
||
|
ULONG MCastRcv = 0;
|
||
|
|
||
|
|
||
|
INT
|
||
|
AtmArpBindAdapterHandler(
|
||
|
OUT PNDIS_STATUS pStatus,
|
||
|
IN NDIS_HANDLE BindContext,
|
||
|
IN PNDIS_STRING pDeviceName,
|
||
|
IN PVOID SystemSpecific1,
|
||
|
IN PVOID SystemSpecific2
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is called by NDIS when it has an adapter for which there is a
|
||
|
binding to the ATMARP client.
|
||
|
|
||
|
We first allocate an Adapter structure. Then we open our configuration
|
||
|
section for this adapter and save the handle in the Adapter structure.
|
||
|
Finally, we open the adapter.
|
||
|
|
||
|
We don't do anything more for this adapter until NDIS notifies us of
|
||
|
the presence of a Call manager (via our AfRegisterNotify handler).
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pStatus - Place to return status of this call
|
||
|
BindContext - Not used, because we don't pend this call
|
||
|
pDeviceName - The name of the adapter we are requested to bind to
|
||
|
SystemSpecific1 - Opaque to us; to be used to access configuration info
|
||
|
SystemSpecific2 - Opaque to us; not used.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Always TRUE. We set *pStatus to an error code if something goes wrong before we
|
||
|
call NdisOpenAdapter, otherwise NDIS_STATUS_PENDING.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PATMARP_ADAPTER pAdapter; // Pointer to new adapter structure
|
||
|
PATMARP_ADAPTER * ppAdapter; // Used in case we need to delink
|
||
|
NDIS_STATUS Status;
|
||
|
NDIS_STATUS OpenStatus;
|
||
|
UINT MediumIndex;
|
||
|
ULONG Length;
|
||
|
PNDIS_STRING pAdapterConfigString;
|
||
|
#ifdef ATMARP_WIN98
|
||
|
PANSI_STRING pAnsiConfigString;
|
||
|
NDIS_STRING UnicodeConfigString;
|
||
|
#endif
|
||
|
|
||
|
AADEBUGP(AAD_LOUD,
|
||
|
("BindAdapter: Context 0x%x, pDevName 0x%x, SS1 0x%x, SS2 0x%x\n",
|
||
|
BindContext, pDeviceName, SystemSpecific1, SystemSpecific2));
|
||
|
|
||
|
#if DBG
|
||
|
if (AaSkipAll)
|
||
|
{
|
||
|
AADEBUGP(AAD_ERROR, ("BindAdapter: aborting\n"));
|
||
|
*pStatus = NDIS_STATUS_NOT_RECOGNIZED;
|
||
|
return ((INT)TRUE);
|
||
|
}
|
||
|
#endif // DBG
|
||
|
|
||
|
//
|
||
|
// Initialize.
|
||
|
//
|
||
|
pAdapter = NULL_PATMARP_ADAPTER;
|
||
|
Status = NDIS_STATUS_SUCCESS;
|
||
|
#ifdef ATMARP_WIN98
|
||
|
UnicodeConfigString.Buffer = NULL;
|
||
|
#endif
|
||
|
|
||
|
do
|
||
|
{
|
||
|
#ifndef ATMARP_WIN98
|
||
|
pAdapterConfigString = (PNDIS_STRING)SystemSpecific1;
|
||
|
#else
|
||
|
//
|
||
|
// SS1 is a pointer to an ANSI string. Convert it to Unicode.
|
||
|
//
|
||
|
pAnsiConfigString = (PANSI_STRING)SystemSpecific1;
|
||
|
AA_ALLOC_MEM(UnicodeConfigString.Buffer, WCHAR, sizeof(WCHAR)*(pAnsiConfigString->MaximumLength));
|
||
|
if (UnicodeConfigString.Buffer == NULL)
|
||
|
{
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
UnicodeConfigString.MaximumLength = sizeof(WCHAR) * (pAnsiConfigString->MaximumLength);
|
||
|
UnicodeConfigString.Length = 0;
|
||
|
NdisAnsiStringToUnicodeString(&UnicodeConfigString, pAnsiConfigString);
|
||
|
pAdapterConfigString = &UnicodeConfigString;
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Check if this is a device we have already bound to.
|
||
|
//
|
||
|
if (AtmArpIsDeviceAlreadyBound(pDeviceName))
|
||
|
{
|
||
|
Status = NDIS_STATUS_NOT_ACCEPTED;
|
||
|
AADEBUGP(AAD_WARNING, ("BindAdapter: already bound to %Z\n", pDeviceName));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate an Adapter structure
|
||
|
//
|
||
|
Length = sizeof(ATMARP_ADAPTER) + pDeviceName->MaximumLength + sizeof(WCHAR) + pAdapterConfigString->MaximumLength;
|
||
|
|
||
|
AA_ALLOC_MEM(pAdapter, ATMARP_ADAPTER, Length);
|
||
|
if (pAdapter == NULL_PATMARP_ADAPTER)
|
||
|
{
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize the Adapter structure
|
||
|
//
|
||
|
AA_SET_MEM(pAdapter, 0, Length);
|
||
|
#if DBG
|
||
|
pAdapter->aaa_sig = aaa_signature;
|
||
|
#endif // DBG
|
||
|
AA_INIT_BLOCK_STRUCT(&(pAdapter->Block));
|
||
|
|
||
|
pAdapter->SystemSpecific1 = SystemSpecific1;
|
||
|
pAdapter->SystemSpecific2 = SystemSpecific2;
|
||
|
pAdapter->BindContext = BindContext;
|
||
|
|
||
|
pAdapter->DeviceName.MaximumLength = pDeviceName->MaximumLength;
|
||
|
pAdapter->DeviceName.Length = pDeviceName->Length;
|
||
|
pAdapter->DeviceName.Buffer = (PWCHAR)((PUCHAR)pAdapter + sizeof(ATMARP_ADAPTER));
|
||
|
|
||
|
AA_COPY_MEM(pAdapter->DeviceName.Buffer,
|
||
|
pDeviceName->Buffer,
|
||
|
pDeviceName->Length);
|
||
|
|
||
|
//
|
||
|
// Copy in the string to be used when we want to open our
|
||
|
// configuration key for this adapter.
|
||
|
//
|
||
|
pAdapter->ConfigString.MaximumLength = pAdapterConfigString->MaximumLength;
|
||
|
pAdapter->ConfigString.Length = pAdapterConfigString->Length;
|
||
|
pAdapter->ConfigString.Buffer = (PWCHAR)((PUCHAR)pAdapter + sizeof(ATMARP_ADAPTER)+ pDeviceName->MaximumLength) + sizeof(WCHAR);
|
||
|
|
||
|
AA_COPY_MEM(pAdapter->ConfigString.Buffer,
|
||
|
pAdapterConfigString->Buffer,
|
||
|
pAdapterConfigString->Length);
|
||
|
|
||
|
AA_INIT_BLOCK_STRUCT(&pAdapter->UnbindBlock);
|
||
|
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
//
|
||
|
// Link this Adapter structure to the global list of adapters.
|
||
|
//
|
||
|
pAtmArpGlobalInfo->AdapterCount++;
|
||
|
pAdapter->pNextAdapter = pAtmArpGlobalInfo->pAdapterList;
|
||
|
pAtmArpGlobalInfo->pAdapterList = pAdapter;
|
||
|
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Open the adapter
|
||
|
//
|
||
|
pAdapter->Medium = NdisMediumAtm;
|
||
|
|
||
|
NdisOpenAdapter(
|
||
|
&Status,
|
||
|
&OpenStatus,
|
||
|
&(pAdapter->NdisAdapterHandle),
|
||
|
&(MediumIndex), // place to return selected medium index
|
||
|
&pAdapter->Medium, // Array of medium types
|
||
|
1, // Size of Media list
|
||
|
pAtmArpGlobalInfo->ProtocolHandle,
|
||
|
(NDIS_HANDLE)pAdapter, // our context for the adapter binding
|
||
|
pDeviceName,
|
||
|
0, // Open options
|
||
|
(PSTRING)NULL // Addressing Info...
|
||
|
);
|
||
|
|
||
|
if (Status != NDIS_STATUS_PENDING)
|
||
|
{
|
||
|
AtmArpOpenAdapterCompleteHandler(
|
||
|
(NDIS_HANDLE)pAdapter,
|
||
|
Status,
|
||
|
OpenStatus
|
||
|
);
|
||
|
}
|
||
|
|
||
|
Status = NDIS_STATUS_PENDING;
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
while (FALSE);
|
||
|
|
||
|
|
||
|
if (Status != NDIS_STATUS_PENDING)
|
||
|
{
|
||
|
//
|
||
|
// We didn't make it upto NdisOpenAdapter. Clean up.
|
||
|
//
|
||
|
AADEBUGP(AAD_WARNING, ("BindAdapter: failed with Status 0x%x\n", Status));
|
||
|
|
||
|
if (pAdapter != NULL_PATMARP_ADAPTER)
|
||
|
{
|
||
|
//
|
||
|
// Free it. We know we haven't linked it to the global
|
||
|
// list of adapters.
|
||
|
//
|
||
|
AA_FREE_MEM(pAdapter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef ATMARP_WIN98
|
||
|
if (UnicodeConfigString.Buffer != NULL)
|
||
|
{
|
||
|
AA_FREE_MEM(UnicodeConfigString.Buffer);
|
||
|
}
|
||
|
#endif // ATMARP_WIN98
|
||
|
|
||
|
*pStatus = Status;
|
||
|
|
||
|
AADEBUGP(AAD_INFO, ("BindAdapterHandler: returning Status 0x%x\n", Status));
|
||
|
return ((INT)TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpUnbindAdapterHandler(
|
||
|
OUT PNDIS_STATUS pStatus,
|
||
|
IN NDIS_HANDLE ProtocolBindingContext,
|
||
|
IN NDIS_HANDLE UnbindContext
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called by NDIS when it wants us to unbind
|
||
|
from an adapter. Or, this may be called from within our Unload
|
||
|
handler. We undo the sequence of operations we performed
|
||
|
in our BindAdapter handler.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pStatus - Place to return status of this operation
|
||
|
ProtocolBindingContext - Our context for this adapter binding, which
|
||
|
is a pointer to an ATMARP Adapter structure.
|
||
|
UnbindContext - This is NULL if this routine is called from
|
||
|
within our Unload handler. Otherwise (i.e.
|
||
|
NDIS called us), we retain this for later use
|
||
|
when calling NdisCompleteUnbindAdapter.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None. We set *pStatus to NDIS_STATUS_PENDING always.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PATMARP_ADAPTER pAdapter;
|
||
|
PATMARP_INTERFACE pInterface;
|
||
|
PATMARP_INTERFACE pNextInterface;
|
||
|
NDIS_STATUS Status;
|
||
|
#if DBG
|
||
|
AA_IRQL EntryIrq, ExitIrq;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
AA_GET_ENTRY_IRQL(EntryIrq);
|
||
|
|
||
|
pAdapter = (PATMARP_ADAPTER)ProtocolBindingContext;
|
||
|
AA_STRUCT_ASSERT(pAdapter, aaa);
|
||
|
|
||
|
AADEBUGP(AAD_INFO, ("UnbindAdapterHandler: pAdapter 0x%x, UnbindContext 0x%x\n",
|
||
|
pAdapter, UnbindContext));
|
||
|
|
||
|
*pStatus = NDIS_STATUS_PENDING;
|
||
|
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
//
|
||
|
// Save the unbind context for a possible later call to
|
||
|
// NdisCompleteUnbindAdapter.
|
||
|
//
|
||
|
pAdapter->UnbindContext = UnbindContext;
|
||
|
pAdapter->Flags |= AA_ADAPTER_FLAGS_UNBINDING;
|
||
|
|
||
|
//
|
||
|
// Wait for any AF register processing to finish.
|
||
|
//
|
||
|
while (pAdapter->Flags & AA_ADAPTER_FLAGS_PROCESSING_AF)
|
||
|
{
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
AADEBUGP(AAD_FATAL, ("UnbindAdapter: pAdapter %x, Afregister going on!!!\n", pAdapter));
|
||
|
Status = AA_WAIT_ON_BLOCK_STRUCT(&(pAdapter->UnbindBlock));
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
}
|
||
|
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
//
|
||
|
// If there are no Interfaces on this adapter, we are done.
|
||
|
//
|
||
|
if (pAdapter->pInterfaceList == NULL_PATMARP_INTERFACE)
|
||
|
{
|
||
|
AtmArpCompleteUnbindAdapter(pAdapter);
|
||
|
AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Mark all interfaces on this adapter.
|
||
|
//
|
||
|
for (pInterface = pAdapter->pInterfaceList;
|
||
|
pInterface != NULL_PATMARP_INTERFACE;
|
||
|
pInterface = pNextInterface)
|
||
|
{
|
||
|
pNextInterface = pInterface->pNextInterface;
|
||
|
|
||
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
||
|
pInterface->AdminState = pInterface->State = IF_STATUS_DOWN;
|
||
|
pInterface->LastChangeTime = GetTimeTicks();
|
||
|
AA_RELEASE_IF_LOCK(pInterface);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now, bring down each of these interfaces. For each interface,
|
||
|
// we tear down the ARP table, and shut down the Call Manager
|
||
|
// interface. When this is complete, we will call IP's DelInterface
|
||
|
// entry point.
|
||
|
//
|
||
|
for (pInterface = pAdapter->pInterfaceList;
|
||
|
pInterface != NULL_PATMARP_INTERFACE;
|
||
|
pInterface = pNextInterface)
|
||
|
{
|
||
|
pNextInterface = pInterface->pNextInterface;
|
||
|
|
||
|
AtmArpShutdownInterface(pInterface);
|
||
|
}
|
||
|
|
||
|
AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpCompleteUnbindAdapter(
|
||
|
IN PATMARP_ADAPTER pAdapter
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Complete the process of adapter unbinding. All Interfaces on this
|
||
|
adapter are assumed to have been removed.
|
||
|
|
||
|
If we are unbinding from the adapter as a result of NDIS' call to
|
||
|
our UnbindAdapter handler, we complete that here.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pAdapter - Pointer to the adapter being unbound.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NDIS_HANDLE UnbindContext;
|
||
|
PATMARP_ADAPTER * ppAdapter;
|
||
|
NDIS_STATUS Status;
|
||
|
|
||
|
UnbindContext = pAdapter->UnbindContext;
|
||
|
|
||
|
AADEBUGP(AAD_INFO, ("CompleteUnbindAdapter: pAdapter 0x%x, UnbindContext 0x%x\n",
|
||
|
pAdapter, UnbindContext));
|
||
|
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
if (pAdapter->Flags & AA_ADAPTER_FLAGS_CLOSING)
|
||
|
{
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pAdapter->Flags |= AA_ADAPTER_FLAGS_CLOSING;
|
||
|
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
#if ATMOFFLOAD
|
||
|
//
|
||
|
// Disable offload if enabled...
|
||
|
//
|
||
|
AtmArpDisableOffload(pAdapter);
|
||
|
#endif // ATMOFFLOAD
|
||
|
|
||
|
NdisCloseAdapter(
|
||
|
&Status,
|
||
|
pAdapter->NdisAdapterHandle
|
||
|
);
|
||
|
|
||
|
if (Status != NDIS_STATUS_PENDING)
|
||
|
{
|
||
|
AtmArpCloseAdapterCompleteHandler(
|
||
|
(NDIS_HANDLE) pAdapter,
|
||
|
Status
|
||
|
);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpOpenAdapterCompleteHandler(
|
||
|
IN NDIS_HANDLE ProtocolBindingContext,
|
||
|
IN NDIS_STATUS Status,
|
||
|
IN NDIS_STATUS OpenErrorStatus
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is called by NDIS when a previous call to NdisOpenAdapter
|
||
|
that had pended has completed. We now complete the BindAdapter
|
||
|
that lead to this.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ProtocolBindingContext - Our context for this adapter binding, which
|
||
|
is a pointer to an ATMARP Adapter structure.
|
||
|
Status - Status of OpenAdapter
|
||
|
OpenErrorStatus - Error code in case of failure.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PATMARP_ADAPTER pAdapter;
|
||
|
PATMARP_ADAPTER * ppAdapter;
|
||
|
NDIS_HANDLE BindAdapterContext;
|
||
|
|
||
|
pAdapter = (PATMARP_ADAPTER)ProtocolBindingContext;
|
||
|
|
||
|
AA_STRUCT_ASSERT(pAdapter, aaa);
|
||
|
|
||
|
BindAdapterContext = pAdapter->BindContext;
|
||
|
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
//
|
||
|
// Remove the adapter from the global list.
|
||
|
//
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
ppAdapter = &(pAtmArpGlobalInfo->pAdapterList);
|
||
|
while (*ppAdapter != pAdapter)
|
||
|
{
|
||
|
ppAdapter = &((*ppAdapter)->pNextAdapter);
|
||
|
}
|
||
|
*ppAdapter = pAdapter->pNextAdapter;
|
||
|
|
||
|
pAtmArpGlobalInfo->AdapterCount--;
|
||
|
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
AA_FREE_MEM(pAdapter);
|
||
|
}
|
||
|
#if ATMOFFLOAD
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Query and enable offloading
|
||
|
//
|
||
|
Status = AtmArpQueryAndEnableOffload(pAdapter);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
//
|
||
|
// AtmArpQueryAndEnableOffload is not supposed to return unless
|
||
|
// there's a fatal error -- we don't expect this.
|
||
|
//
|
||
|
AA_ASSERT(FALSE);
|
||
|
}
|
||
|
}
|
||
|
#endif //ATMOFFLOAD
|
||
|
|
||
|
AADEBUGP(AAD_INFO, ("OpenAdapterComplete: pAdapter 0x%x, Status 0x%x\n",
|
||
|
pAdapter, Status));
|
||
|
|
||
|
(*(pAtmArpGlobalInfo->pIPBindCompleteRtn))(
|
||
|
Status,
|
||
|
BindAdapterContext
|
||
|
);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpCloseAdapterCompleteHandler(
|
||
|
IN NDIS_HANDLE ProtocolBindingContext,
|
||
|
IN NDIS_STATUS Status
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is called by NDIS when a previous call to NdisCloseAdapter
|
||
|
that had pended has completed. The thread that called NdisCloseAdapter
|
||
|
would have blocked itself, so we simply wake it up now.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ProtocolBindingContext - Our context for this adapter binding, which
|
||
|
is a pointer to an ATMARP Adapter structure.
|
||
|
Status - Status of CloseAdapter
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PATMARP_ADAPTER pAdapter;
|
||
|
NDIS_HANDLE UnbindContext;
|
||
|
PATMARP_ADAPTER * ppAdapter;
|
||
|
|
||
|
pAdapter = (PATMARP_ADAPTER)ProtocolBindingContext;
|
||
|
|
||
|
AA_STRUCT_ASSERT(pAdapter, aaa);
|
||
|
|
||
|
UnbindContext = pAdapter->UnbindContext;
|
||
|
|
||
|
AADEBUGP(AAD_INFO, ("CloseAdapterCompleteHandler: pAdapter 0x%x, UnbindContext 0x%x\n",
|
||
|
pAdapter, UnbindContext));
|
||
|
|
||
|
pAdapter->NdisAdapterHandle = NULL;
|
||
|
|
||
|
//
|
||
|
// Remove the adapter from the global list.
|
||
|
//
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
ppAdapter = &(pAtmArpGlobalInfo->pAdapterList);
|
||
|
while (*ppAdapter != pAdapter)
|
||
|
{
|
||
|
ppAdapter = &((*ppAdapter)->pNextAdapter);
|
||
|
}
|
||
|
*ppAdapter = pAdapter->pNextAdapter;
|
||
|
|
||
|
pAtmArpGlobalInfo->AdapterCount--;
|
||
|
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
//
|
||
|
// Free any structures attached to the adapter structure.
|
||
|
//
|
||
|
if (pAdapter->pDescrString != (PUCHAR)NULL)
|
||
|
{
|
||
|
AA_FREE_MEM(pAdapter->pDescrString);
|
||
|
}
|
||
|
if (pAdapter->IPConfigString.Buffer != NULL)
|
||
|
{
|
||
|
AA_FREE_MEM(pAdapter->IPConfigString.Buffer);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Release the adapter structure.
|
||
|
//
|
||
|
AA_FREE_MEM(pAdapter);
|
||
|
|
||
|
//
|
||
|
// If NDIS had requested us to Unbind, complete the
|
||
|
// request now.
|
||
|
//
|
||
|
if (UnbindContext != (NDIS_HANDLE)NULL)
|
||
|
{
|
||
|
NdisCompleteUnbindAdapter(
|
||
|
UnbindContext,
|
||
|
NDIS_STATUS_SUCCESS
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// We initiated the unbind from our Unload handler,
|
||
|
// which would have been waiting for us to complete.
|
||
|
// Wake up that thread now.
|
||
|
//
|
||
|
AA_SIGNAL_BLOCK_STRUCT(&(pAtmArpGlobalInfo->Block), NDIS_STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpSendCompleteHandler(
|
||
|
IN NDIS_HANDLE ProtocolBindingContext,
|
||
|
IN PNDIS_PACKET pNdisPacket,
|
||
|
IN NDIS_STATUS Status
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the Connection-less Send Complete handler, which signals
|
||
|
completion of such a Send. Since we don't ever use this feature,
|
||
|
we don't expect this routine to be called.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
<Ignored>
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
AADEBUGP(AAD_ERROR, ("SendCompleteHandler unexpected\n"));
|
||
|
AA_ASSERT(FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpTransferDataCompleteHandler(
|
||
|
IN NDIS_HANDLE ProtocolBindingContext,
|
||
|
IN PNDIS_PACKET pNdisPacket,
|
||
|
IN NDIS_STATUS Status,
|
||
|
IN UINT BytesTransferred
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the Connection-less Transfer Data Complete handler, which
|
||
|
signals completion of a call to NdisTransferData. Since we never
|
||
|
call NdisTransferData, this routine should never get called.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
<Ignored>
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
AADEBUGP(AAD_ERROR, ("TransferDataComplete Handler unexpected!\n"));
|
||
|
AA_ASSERT(FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpResetCompleteHandler(
|
||
|
IN NDIS_HANDLE ProtocolBindingContext,
|
||
|
IN NDIS_STATUS Status
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called when the miniport indicates that a Reset
|
||
|
operation has just completed. We ignore this event.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ProtocolBindingContext - Our context for this adapter binding, which
|
||
|
is a pointer to an ATMARP Adapter structure.
|
||
|
Status - Status of the reset operation.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PATMARP_ADAPTER pAdapter;
|
||
|
|
||
|
pAdapter = (PATMARP_ADAPTER)ProtocolBindingContext;
|
||
|
AA_STRUCT_ASSERT(pAdapter, aaa);
|
||
|
|
||
|
AADEBUGP(AAD_INFO, ("Reset Complete on Adapter 0x%x\n", pAdapter));
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpRequestCompleteHandler(
|
||
|
IN NDIS_HANDLE ProtocolBindingContext,
|
||
|
IN PNDIS_REQUEST pNdisRequest,
|
||
|
IN NDIS_STATUS Status
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is called by NDIS when a previous call we made to NdisRequest() has
|
||
|
completed. We would be blocked on our adapter structure, waiting for this
|
||
|
to happen -- wake up the blocked thread.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ProtocolBindingContext - Pointer to our Adapter structure
|
||
|
pNdisRequest - The request that completed
|
||
|
Status - Status of the request.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PATMARP_ADAPTER pAdapter;
|
||
|
|
||
|
pAdapter = (PATMARP_ADAPTER)ProtocolBindingContext;
|
||
|
AA_STRUCT_ASSERT(pAdapter, aaa);
|
||
|
|
||
|
AA_SIGNAL_BLOCK_STRUCT(&(pAdapter->Block), Status);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
NDIS_STATUS
|
||
|
AtmArpReceiveHandler(
|
||
|
IN NDIS_HANDLE ProtocolBindingContext,
|
||
|
IN NDIS_HANDLE MacReceiveContext,
|
||
|
IN PVOID pHeaderBuffer,
|
||
|
IN UINT HeaderBufferSize,
|
||
|
IN PVOID pLookAheadBuffer,
|
||
|
IN UINT LookaheadBufferSize,
|
||
|
IN UINT PacketSize
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is our Connection-less receive handler. Since we only use
|
||
|
Connection oriented services, this routine should never get called.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
<Ignored>
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
AADEBUGP(AAD_ERROR, ("Connectionless ReceiveHandler unexpected\n"));
|
||
|
AA_ASSERT(FALSE);
|
||
|
|
||
|
return(NDIS_STATUS_NOT_RECOGNIZED);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpReceiveCompleteHandler(
|
||
|
IN NDIS_HANDLE ProtocolBindingContext
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is called by NDIS when the miniport is done with receiving
|
||
|
a bunch of packets, meaning that it is now time to start processing
|
||
|
them. We simply pass this on to IP (on all IF's configured on this
|
||
|
adapter).
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ProtocolBindingContext - Our context for this adapter binding, which
|
||
|
is a pointer to an ATMARP Adapter structure.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PATMARP_ADAPTER pAdapter;
|
||
|
PATMARP_INTERFACE pInterface;
|
||
|
|
||
|
pAdapter = (PATMARP_ADAPTER)ProtocolBindingContext;
|
||
|
AA_STRUCT_ASSERT(pAdapter, aaa);
|
||
|
|
||
|
for (pInterface = pAdapter->pInterfaceList;
|
||
|
pInterface != NULL_PATMARP_INTERFACE;
|
||
|
pInterface = pInterface->pNextInterface)
|
||
|
{
|
||
|
(*(pInterface->IPRcvCmpltHandler))();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
INT
|
||
|
AtmArpReceivePacketHandler(
|
||
|
IN NDIS_HANDLE ProtocolBindingContext,
|
||
|
IN PNDIS_PACKET pNdisPacket
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the Connectionless receive handler, which should never be
|
||
|
called, since we only use Connection Oriented miniport services.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
<Ignored>
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Reference count on the received packet. We always return 0.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
AADEBUGP(AAD_ERROR, ("ReceivePacket Handler unexpected!\n"));
|
||
|
AA_ASSERT(FALSE);
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpStatusHandler(
|
||
|
IN NDIS_HANDLE ProtocolBindingContext,
|
||
|
IN NDIS_STATUS GeneralStatus,
|
||
|
IN PVOID pStatusBuffer,
|
||
|
IN UINT StatusBufferSize
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called when the miniport indicates an adapter-wide
|
||
|
status change. We ignore this.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
<Ignored>
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
AADEBUGP(AAD_INFO, ("Status Handler: Bind Ctx 0x%x, Status 0x%x\n",
|
||
|
ProtocolBindingContext,
|
||
|
GeneralStatus));
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpStatusCompleteHandler(
|
||
|
IN NDIS_HANDLE ProtocolBindingContext
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called when the miniport wants to tell us about
|
||
|
completion of a status change (?). Ignore this.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
<Ignored>
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
AADEBUGP(AAD_INFO, ("Status Complete Handler: Bind Ctx 0x%x\n",
|
||
|
ProtocolBindingContext));
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
AtmArpCoSendCompleteHandler(
|
||
|
IN NDIS_STATUS Status,
|
||
|
IN NDIS_HANDLE ProtocolVcContext,
|
||
|
IN PNDIS_PACKET pNdisPacket
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called by NDIS when the ATM miniport is finished
|
||
|
with a packet we had previously sent via NdisCoSendPackets. We first
|
||
|
check if this packet was generated by us (e.g. ATMARP protocol packet):
|
||
|
if so, we free this here. Otherwise (packet sent by the IP layer), we
|
||
|
first remove any header buffer that we had attached to the packet and
|
||
|
free it, before calling IP's entry point for Transmit Complete.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Status - Status of the NdisCoSendPackets.
|
||
|
ProtocolVcContext - Our context for the VC on which the packet was sent
|
||
|
(i.e. pointer to ATMARP VC).
|
||
|
pNdisPacket - The packet whose "send" is being completed.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PATMARP_VC pVc;
|
||
|
PATMARP_INTERFACE pInterface;
|
||
|
PacketContext *PC; // IP/ARP Info about this packet
|
||
|
PNDIS_BUFFER pNdisBuffer; // First Buffer in this packet
|
||
|
UINT TotalLength;
|
||
|
AA_HEADER_TYPE HdrType;
|
||
|
ATMARP_VC_ENCAPSULATION_TYPE Encapsulation;
|
||
|
ULONG rc;
|
||
|
|
||
|
pVc = (PATMARP_VC)ProtocolVcContext;
|
||
|
AA_STRUCT_ASSERT(pVc, avc);
|
||
|
|
||
|
#ifdef VC_REFS_ON_SENDS
|
||
|
|
||
|
AA_ACQUIRE_VC_LOCK(pVc);
|
||
|
|
||
|
pInterface = pVc->pInterface;
|
||
|
Encapsulation = pVc->FlowSpec.Encapsulation;
|
||
|
|
||
|
rc = AtmArpDereferenceVc(pVc); // SendComplete
|
||
|
|
||
|
if (rc != 0)
|
||
|
{
|
||
|
pVc->OutstandingSends--;
|
||
|
|
||
|
if (AA_IS_FLAG_SET(
|
||
|
pVc->Flags,
|
||
|
AA_VC_CLOSE_STATE_MASK,
|
||
|
AA_VC_CLOSE_STATE_CLOSING) &&
|
||
|
(pVc->OutstandingSends == 0))
|
||
|
{
|
||
|
AtmArpCloseCall(pVc);
|
||
|
//
|
||
|
// VC lock is released above.
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AA_RELEASE_VC_LOCK(pVc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
pInterface = pVc->pInterface;
|
||
|
Encapsulation = pVc->FlowSpec.Encapsulation;
|
||
|
|
||
|
#endif // VC_REFS_ON_SENDS
|
||
|
|
||
|
AA_ASSERT(pNdisPacket->Private.Head != NULL);
|
||
|
#if DBG
|
||
|
#if DBG_CO_SEND
|
||
|
{
|
||
|
PULONG pContext;
|
||
|
extern ULONG OutstandingSends;
|
||
|
|
||
|
pContext = (PULONG)&(pNdisPacket->WrapperReserved[0]);;
|
||
|
// Check for duplicate completion:
|
||
|
AA_ASSERT(*pContext != 'BbBb');
|
||
|
*pContext = 'BbBb';
|
||
|
NdisInterlockedDecrement(&OutstandingSends);
|
||
|
}
|
||
|
#endif // DBG_CO_SEND
|
||
|
#endif // DBG
|
||
|
|
||
|
NdisQueryPacket(
|
||
|
pNdisPacket,
|
||
|
NULL, // we don't need PhysicalBufferCount
|
||
|
NULL, // we don't need BufferCount
|
||
|
NULL, // we don't need FirstBuffer (yet)
|
||
|
&TotalLength
|
||
|
);
|
||
|
|
||
|
if (Status == NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
AA_IF_STAT_ADD(pInterface, OutOctets, TotalLength);
|
||
|
}
|
||
|
else if (Status == NDIS_STATUS_RESOURCES)
|
||
|
{
|
||
|
AA_IF_STAT_INCR(pInterface, OutDiscards);
|
||
|
}
|
||
|
else if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
AA_IF_STAT_INCR(pInterface, OutErrors);
|
||
|
}
|
||
|
|
||
|
|
||
|
PC = (PacketContext *)pNdisPacket->ProtocolReserved;
|
||
|
|
||
|
AADEBUGP(AAD_EXTRA_LOUD,
|
||
|
("CoSend complete[%s]: VC 0x%x, Pkt 0x%x, Status 0x%x:\n",
|
||
|
((PC->pc_common.pc_owner != PACKET_OWNER_LINK)? "IP": "ARP"),
|
||
|
pVc, pNdisPacket, Status));
|
||
|
|
||
|
//
|
||
|
// Check who generated this packet.
|
||
|
//
|
||
|
if (PC->pc_common.pc_owner != PACKET_OWNER_LINK)
|
||
|
{
|
||
|
//
|
||
|
// Belongs to IP. Check if we had prepended an LLC/SNAP header.
|
||
|
//
|
||
|
if (Encapsulation == ENCAPSULATION_TYPE_LLCSNAP)
|
||
|
{
|
||
|
PUCHAR pPacket;
|
||
|
UINT Length;
|
||
|
|
||
|
#ifdef BACK_FILL
|
||
|
NdisQueryPacket(pNdisPacket, NULL, NULL, &pNdisBuffer, NULL);
|
||
|
AA_ASSERT(pNdisBuffer != NULL);
|
||
|
NdisQueryBuffer(pNdisBuffer, &pPacket, &Length);
|
||
|
|
||
|
//
|
||
|
// Commmon part first: find the header type, and update
|
||
|
// statistics.
|
||
|
//
|
||
|
if (pPacket[5] == LLC_SNAP_OUI2)
|
||
|
{
|
||
|
HdrType = AA_HEADER_TYPE_UNICAST;
|
||
|
if (Status == NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
AA_IF_STAT_INCR(pInterface, OutUnicastPkts);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
HdrType = AA_HEADER_TYPE_NUNICAST;
|
||
|
if (Status == NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
AA_IF_STAT_INCR(pInterface, OutNonUnicastPkts);
|
||
|
INCR_STAT(MCastSendOk);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
INCR_STAT(MCastSendFail);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now check if we had attached a header buffer or not.
|
||
|
//
|
||
|
if (AtmArpDoBackFill && AA_BACK_FILL_POSSIBLE(pNdisBuffer))
|
||
|
{
|
||
|
ULONG HeaderLength;
|
||
|
|
||
|
//
|
||
|
// We would have back-filled IP's buffer with the LLC/SNAP
|
||
|
// header. Remove the back-fill.
|
||
|
//
|
||
|
HeaderLength = ((HdrType == AA_HEADER_TYPE_UNICAST)?
|
||
|
sizeof(AtmArpLlcSnapHeader) :
|
||
|
#ifdef IPMCAST
|
||
|
sizeof(AtmArpMcType1ShortHeader));
|
||
|
#else
|
||
|
0);
|
||
|
#endif // IPMCAST
|
||
|
(PUCHAR)pNdisBuffer->MappedSystemVa += HeaderLength;
|
||
|
pNdisBuffer->ByteOffset += HeaderLength;
|
||
|
pNdisBuffer->ByteCount -= HeaderLength;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// The first buffer would be our header buffer. Remove
|
||
|
// it from the packet and return to our pool.
|
||
|
//
|
||
|
NdisUnchainBufferAtFront(pNdisPacket, &pNdisBuffer);
|
||
|
AtmArpFreeHeader(pInterface, pNdisBuffer, HdrType);
|
||
|
}
|
||
|
#else
|
||
|
//
|
||
|
// Free the LLC/SNAP header buffer.
|
||
|
//
|
||
|
NdisUnchainBufferAtFront(pNdisPacket, &pNdisBuffer);
|
||
|
AA_ASSERT(pNdisBuffer != NULL);
|
||
|
NdisQueryBuffer(pNdisBuffer, &pPacket, &Length);
|
||
|
if (pPacket[5] == LLC_SNAP_OUI2)
|
||
|
{
|
||
|
HdrType = AA_HEADER_TYPE_UNICAST;
|
||
|
if (Status == NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
AA_IF_STAT_INCR(pInterface, OutUnicastPkts);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
HdrType = AA_HEADER_TYPE_NUNICAST;
|
||
|
if (Status == NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
AA_IF_STAT_INCR(pInterface, OutNonUnicastPkts);
|
||
|
INCR_STAT(MCastSendOk);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
INCR_STAT(MCastSendFail);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
AtmArpFreeHeader(pInterface, pNdisBuffer, HdrType);
|
||
|
#endif // BACK_FILL
|
||
|
}
|
||
|
|
||
|
#ifdef PERF
|
||
|
AadLogSendComplete(pNdisPacket);
|
||
|
#endif // PERF
|
||
|
|
||
|
//
|
||
|
// Inform IP of send completion.
|
||
|
//
|
||
|
(*(pInterface->IPTxCmpltHandler))(
|
||
|
pInterface->IPContext,
|
||
|
pNdisPacket,
|
||
|
Status
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Packet generated by the ATMARP module. This would be an
|
||
|
// ATMARP protocol packet, so free the NDIS buffer now.
|
||
|
//
|
||
|
NdisUnchainBufferAtFront(pNdisPacket, &pNdisBuffer);
|
||
|
AA_ASSERT(pNdisBuffer != NULL);
|
||
|
|
||
|
#if DBG
|
||
|
{
|
||
|
ULONG ArpPktLength;
|
||
|
PUCHAR ArpPktStart;
|
||
|
|
||
|
NdisQueryBuffer(pNdisBuffer, (PVOID)&ArpPktStart, &ArpPktLength);
|
||
|
AADEBUGPDUMP(AAD_EXTRA_LOUD+100, ArpPktStart, ArpPktLength);
|
||
|
}
|
||
|
#endif // DBG
|
||
|
|
||
|
AtmArpFreeProtoBuffer(pInterface, pNdisBuffer);
|
||
|
AtmArpFreePacket(pInterface, pNdisPacket);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpCoStatusHandler(
|
||
|
IN NDIS_HANDLE ProtocolBindingContext,
|
||
|
IN NDIS_HANDLE ProtocolVcContext OPTIONAL,
|
||
|
IN NDIS_STATUS GeneralStatus,
|
||
|
IN PVOID pStatusBuffer,
|
||
|
IN UINT StatusBufferSize
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called when the miniport indicates a status
|
||
|
change, possibly on a VC. Ignore this.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
<Ignored>
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
AADEBUGP(AAD_INFO, ("CoStatus Handler: Bind Ctx 0x%x, VC Ctx 0x%x, Status 0x%x\n",
|
||
|
ProtocolBindingContext,
|
||
|
ProtocolVcContext,
|
||
|
GeneralStatus));
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
AtmArpCoReceivePacketHandler -- is in arppkt.c
|
||
|
--*/
|
||
|
|
||
|
|
||
|
#ifdef _PNP_POWER_
|
||
|
|
||
|
|
||
|
NDIS_STATUS
|
||
|
AtmArpPnPReconfigHandler(
|
||
|
IN PATMARP_ADAPTER pAdapter OPTIONAL,
|
||
|
IN PNET_PNP_EVENT pNetPnPEvent
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Handle a reconfig message on the specified adapter. If no adapter
|
||
|
is specified, it is a global parameter that has changed.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pAdapter - Pointer to our adapter structure
|
||
|
pNetPnPEvent - Pointer to reconfig event
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NDIS_STATUS_SUCCESS always, for now.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ATMARPC_PNP_RECONFIG_REQUEST UNALIGNED * pArpReconfigReq;
|
||
|
PIP_PNP_RECONFIG_REQUEST pIpReconfigReq;
|
||
|
NDIS_STATUS Status;
|
||
|
|
||
|
pIpReconfigReq = (PIP_PNP_RECONFIG_REQUEST)pNetPnPEvent->Buffer;
|
||
|
|
||
|
AA_ASSERT(pIpReconfigReq->arpConfigOffset != 0);
|
||
|
|
||
|
pArpReconfigReq = (ATMARPC_PNP_RECONFIG_REQUEST UNALIGNED *)
|
||
|
((PUCHAR)pIpReconfigReq + pIpReconfigReq->arpConfigOffset);
|
||
|
|
||
|
AADEBUGP(AAD_WARNING, ("AtmArpPnPReconfig: pIpReconfig 0x%x, arpConfigOffset 0x%x\n",
|
||
|
pIpReconfigReq, pIpReconfigReq->arpConfigOffset));
|
||
|
|
||
|
|
||
|
do
|
||
|
{
|
||
|
PATMARP_INTERFACE pInterface;
|
||
|
PATMARP_INTERFACE pNextInterface;
|
||
|
NDIS_STRING IPReconfigString;
|
||
|
//
|
||
|
// Locate the IP interface string passed in...
|
||
|
//
|
||
|
ULONG uOffset = pArpReconfigReq->IfKeyOffset;
|
||
|
|
||
|
if (uOffset == 0)
|
||
|
{
|
||
|
Status = NDIS_STATUS_FAILURE;
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// ((PUCHAR)pArpReconfigReq + uOffset) points to a
|
||
|
// "counted unicode string", which means that it's an array
|
||
|
// of words, with the 1st word being the length in characters of
|
||
|
// the string (there is no terminating null) and the following
|
||
|
// <length> words being the string itself.
|
||
|
// We need to create an NDIS_STRING based on this buffer in order
|
||
|
// to compare it with each interface's config string.
|
||
|
//
|
||
|
PWCH pwc = (PWCH) ((PUCHAR)pArpReconfigReq + uOffset);
|
||
|
IPReconfigString.Length = sizeof(WCHAR)*pwc[0];
|
||
|
IPReconfigString.MaximumLength = IPReconfigString.Length;
|
||
|
IPReconfigString.Buffer = pwc+1;
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Do we have a binding context?
|
||
|
//
|
||
|
if (pAdapter == NULL_PATMARP_ADAPTER)
|
||
|
{
|
||
|
Status = NDIS_STATUS_FAILURE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// We wrap the search in a try-except clause because the passed-in
|
||
|
// structure could be bogus. Note that we will only test at most
|
||
|
// as many characters of the passed-in string as the lengths of
|
||
|
// our internal set of interface config strings.
|
||
|
//
|
||
|
try
|
||
|
{
|
||
|
//
|
||
|
// Find the interface associated with this request.
|
||
|
//
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
for (pInterface = pAdapter->pInterfaceList;
|
||
|
pInterface != NULL_PATMARP_INTERFACE;
|
||
|
pInterface = pNextInterface)
|
||
|
{
|
||
|
BOOLEAN IsEqual = FALSE;
|
||
|
|
||
|
pNextInterface = pInterface->pNextInterface;
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
//
|
||
|
// Compare the IPReconfigString
|
||
|
// JJ TODO: NdisEqualUnicodeString must be called in PASSIVE level
|
||
|
// we know that the reconfig call is done at passive level,
|
||
|
// but how to assert that fact here?
|
||
|
// AA_ASSERT(EntryIrq == PASSIVE_LEVEL);
|
||
|
//
|
||
|
IsEqual = NdisEqualUnicodeString(
|
||
|
&IPReconfigString,
|
||
|
&(pInterface->IPConfigString),
|
||
|
TRUE // case insensitive
|
||
|
);
|
||
|
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
if (IsEqual)
|
||
|
{
|
||
|
break; // found it!
|
||
|
}
|
||
|
}
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
}
|
||
|
except (EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
Status = NDIS_STATUS_FAILURE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// JJ We should find the interface if this adapter has any interfaces
|
||
|
// at all -- else it means that we're being sent bogus reconfig
|
||
|
// information.
|
||
|
//
|
||
|
AA_ASSERT(pInterface!= NULL || pAdapter->pInterfaceList==NULL);
|
||
|
|
||
|
if (pInterface != NULL_PATMARP_INTERFACE)
|
||
|
{
|
||
|
|
||
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
||
|
|
||
|
//
|
||
|
// Set it's state to indicate that a reconfig is pending.
|
||
|
// and save away pNetPnPEvent for completion later.
|
||
|
//
|
||
|
if ( pInterface->ReconfigState != RECONFIG_NOT_IN_PROGRESS
|
||
|
|| pInterface->pReconfigEvent != NULL)
|
||
|
{
|
||
|
AA_RELEASE_IF_LOCK(pInterface);
|
||
|
//
|
||
|
// We should not get here because this means that
|
||
|
// we were asked to reconfigure when there was a
|
||
|
// pending reconfiguration, which is not supposed to happen.
|
||
|
//
|
||
|
Status = NDIS_STATUS_FAILURE;
|
||
|
AA_ASSERT(FALSE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pInterface->ReconfigState = RECONFIG_SHUTDOWN_PENDING;
|
||
|
pInterface->pReconfigEvent = pNetPnPEvent;
|
||
|
pInterface->AdminState = IF_STATUS_DOWN;
|
||
|
AtmArpReferenceInterface(pInterface); // Reconfig
|
||
|
|
||
|
AA_RELEASE_IF_LOCK(pInterface);
|
||
|
|
||
|
//
|
||
|
// Initiate shutdown in preparation of a restart.
|
||
|
// AtmArpShutdown is responsible for
|
||
|
// completing the ndis reconfig request asynchronously.
|
||
|
//
|
||
|
AtmArpShutdownInterface(pInterface);
|
||
|
Status = NDIS_STATUS_PENDING;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// We didn't find the interface, fail the request...
|
||
|
//
|
||
|
|
||
|
Status = NDIS_STATUS_FAILURE;
|
||
|
}
|
||
|
} while (FALSE);
|
||
|
|
||
|
|
||
|
return (Status);
|
||
|
}
|
||
|
|
||
|
|
||
|
NDIS_STATUS
|
||
|
AtmArpPnPEventHandler(
|
||
|
IN NDIS_HANDLE ProtocolBindingContext,
|
||
|
IN PNET_PNP_EVENT pNetPnPEvent
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the NDIS entry point called when NDIS wants to inform
|
||
|
us about a PNP/PM event happening on an adapter. If the event
|
||
|
is for us, we consume it. Otherwise, we pass this event along
|
||
|
to IP along the first Interface on this adapter.
|
||
|
|
||
|
When IP is done with it, it will call our IfPnPEventComplete
|
||
|
routine.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ProtocolBindingContext - Our context for this adapter binding, which
|
||
|
is a pointer to an ATMARP Adapter structure.
|
||
|
|
||
|
pNetPnPEvent - Pointer to the event.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PATMARP_ADAPTER pAdapter;
|
||
|
PATMARP_INTERFACE pInterface;
|
||
|
NDIS_STATUS Status;
|
||
|
|
||
|
PIP_PNP_RECONFIG_REQUEST pIpReconfigReq;
|
||
|
ULONG Length;
|
||
|
|
||
|
pAdapter = (PATMARP_ADAPTER)ProtocolBindingContext;
|
||
|
|
||
|
#ifdef NT
|
||
|
do
|
||
|
{
|
||
|
pIpReconfigReq = (PIP_PNP_RECONFIG_REQUEST)pNetPnPEvent->Buffer;
|
||
|
Length = pNetPnPEvent->BufferLength;
|
||
|
|
||
|
//
|
||
|
// Is this directed to us?
|
||
|
//
|
||
|
if (pNetPnPEvent->NetEvent == NetEventReconfigure)
|
||
|
{
|
||
|
if (Length < sizeof(IP_PNP_RECONFIG_REQUEST))
|
||
|
{
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pIpReconfigReq->arpConfigOffset != 0)
|
||
|
{
|
||
|
Status = AtmArpPnPReconfigHandler(pAdapter, pNetPnPEvent);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This belongs to IP. Do we have a binding context?
|
||
|
//
|
||
|
if (pAdapter == NULL_PATMARP_ADAPTER)
|
||
|
{
|
||
|
Status = NDIS_STATUS_FAILURE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
AA_STRUCT_ASSERT(pAdapter, aaa);
|
||
|
pInterface = pAdapter->pInterfaceList;
|
||
|
|
||
|
if ((pInterface != NULL_PATMARP_INTERFACE) &&
|
||
|
(pInterface->IPContext != NULL))
|
||
|
{
|
||
|
AA_ASSERT(pInterface->IPPnPEventHandler != NULL);
|
||
|
Status = (*pInterface->IPPnPEventHandler)(
|
||
|
pInterface->IPContext,
|
||
|
pNetPnPEvent
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Status = NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
while (FALSE);
|
||
|
#else
|
||
|
Status = NDIS_STATUS_SUCCESS;
|
||
|
#endif // NT
|
||
|
|
||
|
AADEBUGP(AAD_INFO,
|
||
|
("PnPEventHandler: pIF 0x%x, pEvent 0x%x, Evt 0x%x, Status 0x%x\n",
|
||
|
pInterface, pNetPnPEvent, pNetPnPEvent->NetEvent, Status));
|
||
|
|
||
|
return (Status);
|
||
|
}
|
||
|
|
||
|
#endif // _PNP_POWER_
|
||
|
|
||
|
|
||
|
NDIS_STATUS
|
||
|
AtmArpSendAdapterNdisRequest(
|
||
|
IN PATMARP_ADAPTER pAdapter,
|
||
|
IN PNDIS_REQUEST pNdisRequest,
|
||
|
IN NDIS_REQUEST_TYPE RequestType,
|
||
|
IN NDIS_OID Oid,
|
||
|
IN PVOID pBuffer,
|
||
|
IN ULONG BufferLength
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Send an NDIS Request to query an adapter for information.
|
||
|
If the request pends, block on the ATMARP Adapter structure
|
||
|
till it completes.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pAdapter - Points to ATMARP Adapter structure
|
||
|
pNdisRequest - Pointer to NDIS request structure
|
||
|
RequestType - Set/Query information
|
||
|
Oid - OID to be passed in the request
|
||
|
pBuffer - place for value(s)
|
||
|
BufferLength - length of above
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The NDIS status of the request.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NDIS_STATUS Status;
|
||
|
|
||
|
//
|
||
|
// Fill in the NDIS Request structure
|
||
|
//
|
||
|
pNdisRequest->RequestType = RequestType;
|
||
|
if (RequestType == NdisRequestQueryInformation)
|
||
|
{
|
||
|
pNdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
|
||
|
pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer = pBuffer;
|
||
|
pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength = BufferLength;
|
||
|
pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten = 0;
|
||
|
pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BufferLength;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pNdisRequest->DATA.SET_INFORMATION.Oid = Oid;
|
||
|
pNdisRequest->DATA.SET_INFORMATION.InformationBuffer = pBuffer;
|
||
|
pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength = BufferLength;
|
||
|
pNdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
||
|
pNdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
|
||
|
}
|
||
|
|
||
|
AA_INIT_BLOCK_STRUCT(&(pAdapter->Block));
|
||
|
|
||
|
NdisRequest(
|
||
|
&Status,
|
||
|
pAdapter->NdisAdapterHandle,
|
||
|
pNdisRequest
|
||
|
);
|
||
|
|
||
|
if (Status == NDIS_STATUS_PENDING)
|
||
|
{
|
||
|
Status = AA_WAIT_ON_BLOCK_STRUCT(&(pAdapter->Block));
|
||
|
}
|
||
|
|
||
|
return (Status);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NDIS_STATUS
|
||
|
AtmArpGetAdapterInfo(
|
||
|
IN PATMARP_ADAPTER pAdapter
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Query an adapter for hardware-specific information that we need:
|
||
|
- burnt in hardware address (ESI part)
|
||
|
- Max packet size
|
||
|
- line rate
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pAdapter - Pointer to ATMARP adapter structure
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NDIS_STATUS_SUCCESS on success.
|
||
|
Failure code on some non-ignorable failure (such as
|
||
|
device doesn't support MTU >= 8196).
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NDIS_STATUS Status;
|
||
|
NDIS_REQUEST NdisRequest;
|
||
|
ULONG Value;
|
||
|
|
||
|
//
|
||
|
// Initialize.
|
||
|
//
|
||
|
AA_SET_MEM(pAdapter->MacAddress, 0, AA_ATM_ESI_LEN);
|
||
|
|
||
|
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// Description string: we first query this with a 0 length buffer
|
||
|
// length, so that we get the actual # of bytes needed. Then we
|
||
|
// allocate a buffer for the descriptor string, and use that to
|
||
|
// get the actual string.
|
||
|
//
|
||
|
Status = AtmArpSendAdapterNdisRequest(
|
||
|
pAdapter,
|
||
|
&NdisRequest,
|
||
|
NdisRequestQueryInformation,
|
||
|
OID_GEN_CO_VENDOR_DESCRIPTION,
|
||
|
(PVOID)(pAdapter->pDescrString),
|
||
|
0
|
||
|
);
|
||
|
|
||
|
if ((Status == NDIS_STATUS_INVALID_LENGTH) ||
|
||
|
(Status == NDIS_STATUS_BUFFER_TOO_SHORT))
|
||
|
{
|
||
|
//
|
||
|
// Now allocate a buffer of the right length.
|
||
|
//
|
||
|
pAdapter->DescrLength = NdisRequest.DATA.QUERY_INFORMATION.BytesNeeded;
|
||
|
AA_ALLOC_MEM(pAdapter->pDescrString, UCHAR, pAdapter->DescrLength);
|
||
|
if (pAdapter->pDescrString != (PUCHAR)NULL)
|
||
|
{
|
||
|
Status = AtmArpSendAdapterNdisRequest(
|
||
|
pAdapter,
|
||
|
&NdisRequest,
|
||
|
NdisRequestQueryInformation,
|
||
|
OID_GEN_CO_VENDOR_DESCRIPTION,
|
||
|
(PVOID)(pAdapter->pDescrString),
|
||
|
pAdapter->DescrLength
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pAdapter->DescrLength = 0;
|
||
|
}
|
||
|
AADEBUGP(AAD_LOUD, ("GetAdapterInfo: Query VENDOR Descr2 ret 0x%x, DescrLen %d\n",
|
||
|
Status, pAdapter->DescrLength));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AADEBUGP(AAD_LOUD, ("GetAdapterInfo: Query VENDOR Descr1 ret 0x%x\n", Status));
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// MAC Address:
|
||
|
//
|
||
|
Status = AtmArpSendAdapterNdisRequest(
|
||
|
pAdapter,
|
||
|
&NdisRequest,
|
||
|
NdisRequestQueryInformation,
|
||
|
OID_ATM_HW_CURRENT_ADDRESS,
|
||
|
(PVOID)(pAdapter->MacAddress),
|
||
|
AA_ATM_ESI_LEN
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Max Frame Size:
|
||
|
//
|
||
|
Status = AtmArpSendAdapterNdisRequest(
|
||
|
pAdapter,
|
||
|
&NdisRequest,
|
||
|
NdisRequestQueryInformation,
|
||
|
OID_ATM_MAX_AAL5_PACKET_SIZE,
|
||
|
(PVOID)(&(pAdapter->MaxPacketSize)),
|
||
|
sizeof(ULONG)
|
||
|
);
|
||
|
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
//
|
||
|
// Use the default.
|
||
|
//
|
||
|
pAdapter->MaxPacketSize = AA_DEF_ATM_MAX_PACKET_SIZE;
|
||
|
}
|
||
|
|
||
|
if (pAdapter->MaxPacketSize > AA_MAX_ATM_MAX_PACKET_SIZE)
|
||
|
{
|
||
|
pAdapter->MaxPacketSize = AA_MAX_ATM_MAX_PACKET_SIZE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check that the adapter support the minimum.
|
||
|
//
|
||
|
if (pAdapter->MaxPacketSize < AA_MIN_ATM_MAX_PACKET_SIZE)
|
||
|
{
|
||
|
AADEBUGP(AAD_FATAL,
|
||
|
("GetAdapterInfo: (FATAL) MaxPacketSize of (%lu) is too small.\n",
|
||
|
pAdapter->MaxPacketSize));
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Link speed:
|
||
|
//
|
||
|
Status = AtmArpSendAdapterNdisRequest(
|
||
|
pAdapter,
|
||
|
&NdisRequest,
|
||
|
NdisRequestQueryInformation,
|
||
|
OID_GEN_CO_LINK_SPEED,
|
||
|
(PVOID)(&(pAdapter->LineRate)),
|
||
|
sizeof(pAdapter->LineRate)
|
||
|
);
|
||
|
|
||
|
if ((Status != NDIS_STATUS_SUCCESS) ||
|
||
|
(pAdapter->LineRate.Inbound == 0) ||
|
||
|
(pAdapter->LineRate.Outbound == 0))
|
||
|
{
|
||
|
//
|
||
|
// Use the default.
|
||
|
//
|
||
|
pAdapter->LineRate.Outbound = pAdapter->LineRate.Inbound = AA_DEF_ATM_LINE_RATE;
|
||
|
AADEBUGP(AAD_LOUD, ("Using default line rate %d bytes/sec\n",
|
||
|
AA_DEF_ATM_LINE_RATE));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Convert from 100 bits/sec to bytes/sec
|
||
|
//
|
||
|
pAdapter->LineRate.Outbound = (pAdapter->LineRate.Outbound * 100)/8;
|
||
|
pAdapter->LineRate.Inbound = (pAdapter->LineRate.Inbound * 100)/8;
|
||
|
AADEBUGP(AAD_LOUD, ("Got line rates from miniport: In %d, Out %d bytes/sec\n",
|
||
|
pAdapter->LineRate.Outbound,
|
||
|
pAdapter->LineRate.Inbound));
|
||
|
}
|
||
|
|
||
|
Status = NDIS_STATUS_SUCCESS;
|
||
|
|
||
|
} while(FALSE);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NDIS_STATUS
|
||
|
AtmArpSendNdisRequest(
|
||
|
IN PATMARP_ADAPTER pAdapter,
|
||
|
IN PNDIS_REQUEST pNdisRequest,
|
||
|
IN NDIS_REQUEST_TYPE RequestType,
|
||
|
IN NDIS_OID Oid,
|
||
|
IN PVOID pBuffer,
|
||
|
IN ULONG BufferLength
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Send an NDIS (non-Connection Oriented) request to the Miniport. We
|
||
|
allocate an NDIS_REQUEST structure, link the supplied buffer to it,
|
||
|
and send the request. If the request does not pend, we call our
|
||
|
completion routine from here.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pAdapter - Pointer to our Adapter structure representing
|
||
|
the adapter to which the request is to be sent
|
||
|
pNdisRequest - Pointer to NDIS request structure
|
||
|
RequestType - Set/Query information
|
||
|
Oid - OID to be passed in the request
|
||
|
pBuffer - place for value(s)
|
||
|
BufferLength - length of above
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Status of the NdisRequest.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NDIS_STATUS Status;
|
||
|
|
||
|
//
|
||
|
// Fill in the NDIS Request structure
|
||
|
//
|
||
|
pNdisRequest->RequestType = RequestType;
|
||
|
if (RequestType == NdisRequestQueryInformation)
|
||
|
{
|
||
|
pNdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
|
||
|
pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer = pBuffer;
|
||
|
pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength = BufferLength;
|
||
|
pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten = 0;
|
||
|
pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BufferLength;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pNdisRequest->DATA.SET_INFORMATION.Oid = Oid;
|
||
|
pNdisRequest->DATA.SET_INFORMATION.InformationBuffer = pBuffer;
|
||
|
pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength = BufferLength;
|
||
|
pNdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
||
|
pNdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
|
||
|
}
|
||
|
|
||
|
NdisRequest(
|
||
|
&Status,
|
||
|
pAdapter->NdisAdapterHandle,
|
||
|
pNdisRequest);
|
||
|
|
||
|
return (Status);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpShutdownInterface(
|
||
|
IN PATMARP_INTERFACE pInterface
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Bring down the specified ARP interface.
|
||
|
|
||
|
We tear down the ARP table, and shut down the Call Manager
|
||
|
interface. When this is complete, we will call IP's DelInterface
|
||
|
entry point.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pInterface - Points to the Interface to be shut down.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
IP_STATUS Status;
|
||
|
INT i;
|
||
|
ULONG rc;
|
||
|
PATMARP_IP_ENTRY pIpEntry;
|
||
|
PATMARP_ATM_ENTRY pAtmEntry;
|
||
|
PATMARP_ATM_ENTRY pNextAtmEntry;
|
||
|
PATMARP_VC pVc;
|
||
|
PATMARP_VC pNextVc;
|
||
|
PATMARP_ADAPTER pAdapter;
|
||
|
BOOLEAN WasRunning;
|
||
|
#if DBG
|
||
|
AA_IRQL EntryIrq, ExitIrq;
|
||
|
#endif
|
||
|
|
||
|
AA_GET_ENTRY_IRQL(EntryIrq);
|
||
|
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
pAdapter = pInterface->pAdapter;
|
||
|
|
||
|
//
|
||
|
// Wait for any AF register processing to finish.
|
||
|
//
|
||
|
while (pAdapter->Flags & AA_ADAPTER_FLAGS_PROCESSING_AF)
|
||
|
{
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
AADEBUGP(AAD_FATAL, ("ShutdownIf: IF %p, pAdapter %x, Afregister going on!!!\n",
|
||
|
pInterface, pAdapter));
|
||
|
Status = AA_WAIT_ON_BLOCK_STRUCT(&(pAdapter->UnbindBlock));
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
}
|
||
|
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
//
|
||
|
// Stop any timer running on this interface
|
||
|
//
|
||
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
||
|
|
||
|
if (AtmArpStopTimer(&(pInterface->Timer), pInterface))
|
||
|
{
|
||
|
rc = AtmArpDereferenceInterface(pInterface); // Timer ref
|
||
|
AA_ASSERT(rc != 0);
|
||
|
}
|
||
|
#ifdef IPMCAST
|
||
|
//
|
||
|
// Stop any Multicast timer running on this interface
|
||
|
//
|
||
|
if (AtmArpStopTimer(&(pInterface->McTimer), pInterface))
|
||
|
{
|
||
|
rc = AtmArpDereferenceInterface(pInterface); // Timer ref
|
||
|
AA_ASSERT(rc != 0);
|
||
|
}
|
||
|
#endif
|
||
|
AA_RELEASE_IF_LOCK(pInterface);
|
||
|
|
||
|
//
|
||
|
// Deregister all SAPs so that we don't get any more
|
||
|
// incoming calls.
|
||
|
//
|
||
|
AtmArpDeregisterSaps(pInterface);
|
||
|
AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
||
|
|
||
|
//
|
||
|
// We set the ARP Table state to "down" -- this will ensure that it
|
||
|
// will not grow while we are shutting down.
|
||
|
//
|
||
|
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
|
||
|
pInterface->ArpTableUp = FALSE;
|
||
|
|
||
|
//
|
||
|
// Go through the ARP Table and abort all IP entries
|
||
|
//
|
||
|
for (i = 0; i < ATMARP_TABLE_SIZE; i++)
|
||
|
{
|
||
|
while (pInterface->pArpTable[i] != NULL_PATMARP_IP_ENTRY)
|
||
|
{
|
||
|
pIpEntry = pInterface->pArpTable[i];
|
||
|
|
||
|
AA_ACQUIRE_IE_LOCK_DPC(pIpEntry);
|
||
|
AA_REF_IE(pIpEntry, IE_REFTYPE_TMP); // Shutdown Interface
|
||
|
AA_RELEASE_IE_LOCK_DPC(pIpEntry);
|
||
|
|
||
|
AA_RELEASE_IF_TABLE_LOCK(pInterface);
|
||
|
|
||
|
AA_ACQUIRE_IE_LOCK(pIpEntry);
|
||
|
if (AA_DEREF_IE(pIpEntry, IE_REFTYPE_TMP)) // Shutdown Interface
|
||
|
{
|
||
|
AtmArpAbortIPEntry(pIpEntry);
|
||
|
//
|
||
|
// IE Lock is released within the above.
|
||
|
//
|
||
|
}
|
||
|
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
|
||
|
}
|
||
|
}
|
||
|
AA_RELEASE_IF_TABLE_LOCK(pInterface);
|
||
|
|
||
|
AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
||
|
|
||
|
#ifdef IPMCAST
|
||
|
//
|
||
|
// Delete all Join Entries
|
||
|
//
|
||
|
|
||
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
||
|
|
||
|
{
|
||
|
PATMARP_IPMC_JOIN_ENTRY pJoinEntry;
|
||
|
PATMARP_IPMC_JOIN_ENTRY pNextJoinEntry;
|
||
|
|
||
|
for (pJoinEntry = pInterface->pJoinList;
|
||
|
pJoinEntry != NULL_PATMARP_IPMC_JOIN_ENTRY;
|
||
|
pJoinEntry = pNextJoinEntry)
|
||
|
{
|
||
|
WasRunning = AtmArpStopTimer(&(pJoinEntry->Timer), pInterface);
|
||
|
pNextJoinEntry = pJoinEntry->pNextJoinEntry;
|
||
|
|
||
|
if (WasRunning)
|
||
|
{
|
||
|
rc = AA_DEREF_JE(pJoinEntry); // ShutdownIF: timer stopped
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rc = pJoinEntry->RefCount;
|
||
|
}
|
||
|
|
||
|
if (rc != 0)
|
||
|
{
|
||
|
(VOID)AA_DEREF_JE(pJoinEntry); // ShutdownIF: kill Join Entry
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pInterface->pJoinList = NULL_PATMARP_IPMC_JOIN_ENTRY;
|
||
|
}
|
||
|
|
||
|
AA_RELEASE_IF_LOCK(pInterface);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// We set the AtmEntry list state to "down" (this will ensure that it
|
||
|
// will not grow while we are shutting down), then
|
||
|
// go through the list of ATM Entries on this interface, and
|
||
|
// abort all of them.
|
||
|
//
|
||
|
|
||
|
AA_ACQUIRE_IF_ATM_LIST_LOCK(pInterface);
|
||
|
pInterface->AtmEntryListUp = FALSE;
|
||
|
|
||
|
pNextAtmEntry = pInterface->pAtmEntryList;
|
||
|
|
||
|
if (pNextAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
||
|
{
|
||
|
AA_ACQUIRE_AE_LOCK_DPC(pNextAtmEntry);
|
||
|
AA_REF_AE(pNextAtmEntry, AE_REFTYPE_TMP); // ShutdownInterface
|
||
|
AA_RELEASE_AE_LOCK_DPC(pNextAtmEntry);
|
||
|
}
|
||
|
|
||
|
while (pNextAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
||
|
{
|
||
|
pAtmEntry = pNextAtmEntry;
|
||
|
pNextAtmEntry = pAtmEntry->pNext;
|
||
|
|
||
|
//
|
||
|
// Note that we still have the lock to pInterface when
|
||
|
// we aquire the lock to pAtmEntry below. This order of aquiring
|
||
|
// locks must be strictly followed everywhere in order to prevent
|
||
|
// a deadlock.
|
||
|
//
|
||
|
// We can't release the LIST_LOCK without first addrefing pAtmEntry,
|
||
|
// otherwise while both locks are free someone else can delref and
|
||
|
// possibly deallocate pAtmEntry.
|
||
|
//
|
||
|
if (pNextAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
||
|
{
|
||
|
AA_ACQUIRE_AE_LOCK_DPC(pNextAtmEntry);
|
||
|
AA_REF_AE(pNextAtmEntry, AE_REFTYPE_TMP); // ShutdownInterface
|
||
|
AA_RELEASE_AE_LOCK_DPC(pNextAtmEntry);
|
||
|
}
|
||
|
|
||
|
AA_RELEASE_IF_ATM_LIST_LOCK(pInterface);
|
||
|
|
||
|
AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
||
|
|
||
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
||
|
|
||
|
if (AA_DEREF_AE(pAtmEntry, AE_REFTYPE_TMP) != 0) // ShutdownInterface
|
||
|
{
|
||
|
AtmArpInvalidateAtmEntry(
|
||
|
pAtmEntry,
|
||
|
TRUE // we ARE shutting down
|
||
|
);
|
||
|
//
|
||
|
// The ATM Entry lock is released within the above.
|
||
|
//
|
||
|
}
|
||
|
|
||
|
AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
||
|
AA_ACQUIRE_IF_ATM_LIST_LOCK(pInterface);
|
||
|
}
|
||
|
AA_RELEASE_IF_ATM_LIST_LOCK(pInterface);
|
||
|
AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
||
|
|
||
|
//
|
||
|
// Go through the list of unresolved VCs on this interface,
|
||
|
// and close all of them.
|
||
|
//
|
||
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
||
|
pVc = pInterface->pUnresolvedVcs;
|
||
|
pInterface->pUnresolvedVcs = NULL_PATMARP_VC;
|
||
|
|
||
|
while (pVc != NULL_PATMARP_VC)
|
||
|
{
|
||
|
pNextVc = pVc->pNextVc;
|
||
|
|
||
|
AA_RELEASE_IF_LOCK(pInterface);
|
||
|
|
||
|
AA_ACQUIRE_VC_LOCK(pVc);
|
||
|
if (AtmArpDereferenceVc(pVc) != 0) // Unresolved VC list entry
|
||
|
{
|
||
|
AtmArpCloseCall(pVc);
|
||
|
//
|
||
|
// the VC lock is released within the above.
|
||
|
//
|
||
|
}
|
||
|
|
||
|
pVc = pNextVc;
|
||
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
||
|
}
|
||
|
|
||
|
AA_RELEASE_IF_LOCK(pInterface);
|
||
|
AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Close the Call Manager interface.
|
||
|
//
|
||
|
AtmArpCloseCallMgr(pInterface);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
AtmArpIsDeviceAlreadyBound(
|
||
|
IN PNDIS_STRING pDeviceName
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Check if we have already bound to a device (adapter).
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pDeviceName - Points to device name to be checked.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE iff we already have an Adapter structure representing
|
||
|
this device.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PATMARP_ADAPTER pAdapter;
|
||
|
BOOLEAN bFound = FALSE;
|
||
|
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
for (pAdapter = pAtmArpGlobalInfo->pAdapterList;
|
||
|
pAdapter != NULL_PATMARP_ADAPTER;
|
||
|
pAdapter = pAdapter->pNextAdapter)
|
||
|
{
|
||
|
if ((pDeviceName->Length == pAdapter->DeviceName.Length) &&
|
||
|
(AA_MEM_CMP(pDeviceName->Buffer,
|
||
|
pAdapter->DeviceName.Buffer,
|
||
|
pDeviceName->Length) == 0))
|
||
|
{
|
||
|
bFound = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
return (bFound);
|
||
|
}
|
||
|
|
||
|
#if ATMOFFLOAD
|
||
|
|
||
|
NDIS_STATUS
|
||
|
AtmArpQueryAndEnableOffload(
|
||
|
IN PATMARP_ADAPTER pAdapter
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Query the capabilities of the adapter and set all recognized offload capabilities.
|
||
|
Set pMaxOffLoadSize and pMinSegmentCount to the corresponding values, and
|
||
|
also set pInterface->OffloadFlags to the set of enabled tasks.
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pAdapter - The adapter on which to enable offloading.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE iff the operation was either succesful or no tasks were enabled. False
|
||
|
if there was a fatal error.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NDIS_STATUS Status = STATUS_BUFFER_OVERFLOW;
|
||
|
PNDIS_TASK_OFFLOAD_HEADER pHeader = NULL;
|
||
|
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
pAdapter->Offload.Flags = 0;
|
||
|
pAdapter->Offload.MaxOffLoadSize = 0;
|
||
|
pAdapter->Offload.MinSegmentCount = 0;
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
PNDIS_TASK_OFFLOAD pTask;
|
||
|
ULONG Flags = 0;
|
||
|
UINT MaxOffLoadSize = 0;
|
||
|
UINT MinSegmentCount = 0;
|
||
|
NDIS_TASK_IPSEC ipsecCaps;
|
||
|
UINT BufferSize = 0;
|
||
|
NDIS_REQUEST NdisRequest;
|
||
|
|
||
|
//
|
||
|
// Query capabilities
|
||
|
//
|
||
|
{
|
||
|
NDIS_TASK_OFFLOAD_HEADER Header;
|
||
|
AA_SET_MEM(&Header, 0, sizeof(Header));
|
||
|
|
||
|
Header.EncapsulationFormat.Flags.FixedHeaderSize = 1;
|
||
|
Header.EncapsulationFormat.EncapsulationHeaderSize =
|
||
|
AA_PKT_LLC_SNAP_HEADER_LENGTH;
|
||
|
Header.EncapsulationFormat.Encapsulation =
|
||
|
LLC_SNAP_ROUTED_Encapsulation;
|
||
|
Header.Version = NDIS_TASK_OFFLOAD_VERSION;
|
||
|
Header.Size = sizeof(Header);
|
||
|
|
||
|
AADEBUGP(AAD_INFO, ("Querying for Task offload\n"));
|
||
|
|
||
|
Status = AtmArpSendAdapterNdisRequest(
|
||
|
pAdapter,
|
||
|
&NdisRequest,
|
||
|
NdisRequestQueryInformation,
|
||
|
OID_TCP_TASK_OFFLOAD,
|
||
|
&Header,
|
||
|
sizeof(Header)
|
||
|
);
|
||
|
|
||
|
if ((Status == NDIS_STATUS_INVALID_LENGTH) ||
|
||
|
(Status == NDIS_STATUS_BUFFER_TOO_SHORT)) {
|
||
|
|
||
|
//
|
||
|
// Alloc the proper-sized buffer and query a 2nd time...
|
||
|
//
|
||
|
|
||
|
BufferSize = NdisRequest.DATA.QUERY_INFORMATION.BytesNeeded;
|
||
|
|
||
|
AA_ALLOC_MEM(pHeader, NDIS_TASK_OFFLOAD_HEADER, BufferSize);
|
||
|
|
||
|
if (pHeader != NULL)
|
||
|
{
|
||
|
*pHeader = Header; // struct copy.
|
||
|
|
||
|
Status = AtmArpSendAdapterNdisRequest(
|
||
|
pAdapter,
|
||
|
&NdisRequest,
|
||
|
NdisRequestQueryInformation,
|
||
|
OID_TCP_TASK_OFFLOAD,
|
||
|
pHeader,
|
||
|
BufferSize
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
AADEBUGP(AAD_INFO, ("Query Offload failed. Status=%x\n", Status));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( pHeader == NULL
|
||
|
|| pHeader->OffsetFirstTask == 0)
|
||
|
{
|
||
|
AADEBUGP(AAD_INFO, ("No tasks to offload\n"));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
AA_ASSERT(pHeader->OffsetFirstTask == sizeof(NDIS_TASK_OFFLOAD_HEADER));
|
||
|
|
||
|
AADEBUGP(AAD_WARNING,
|
||
|
("Something to Offload. Offload buffer size %x\n", BufferSize));
|
||
|
|
||
|
//
|
||
|
// Parse the buffer for Checksum and tcplargesend offload capabilities
|
||
|
//
|
||
|
for (
|
||
|
pTask = (NDIS_TASK_OFFLOAD *) ((UCHAR *)pHeader
|
||
|
+ pHeader->OffsetFirstTask);
|
||
|
1; // we break when done
|
||
|
pTask = (PNDIS_TASK_OFFLOAD) ((PUCHAR)pTask + pTask->OffsetNextTask))
|
||
|
{
|
||
|
|
||
|
if (pTask->Task == TcpIpChecksumNdisTask)
|
||
|
{
|
||
|
//
|
||
|
//this adapter supports checksum offload
|
||
|
//check if tcp and/or ip chksums bits are present
|
||
|
//
|
||
|
|
||
|
PNDIS_TASK_TCP_IP_CHECKSUM ChecksumInfo
|
||
|
= (PNDIS_TASK_TCP_IP_CHECKSUM) pTask->TaskBuffer;
|
||
|
|
||
|
// if (ChecksumInfo->V4Transmit.V4Checksum) (commented out in arpc.c)
|
||
|
{
|
||
|
|
||
|
AADEBUGP(AAD_INFO, ("V4 Checksum offload\n"));
|
||
|
|
||
|
if (ChecksumInfo->V4Transmit.TcpChecksum) {
|
||
|
Flags |= TCP_XMT_CHECKSUM_OFFLOAD;
|
||
|
AADEBUGP(AAD_INFO, (" Tcp Checksum offload\n"));
|
||
|
}
|
||
|
|
||
|
if (ChecksumInfo->V4Transmit.IpChecksum) {
|
||
|
Flags |= IP_XMT_CHECKSUM_OFFLOAD;
|
||
|
AADEBUGP(AAD_INFO, (" IP xmt Checksum offload\n"));
|
||
|
}
|
||
|
|
||
|
if (ChecksumInfo->V4Receive.TcpChecksum) {
|
||
|
Flags |= TCP_RCV_CHECKSUM_OFFLOAD;
|
||
|
AADEBUGP(AAD_INFO, (" Tcp Rcv Checksum offload\n"));
|
||
|
}
|
||
|
|
||
|
if (ChecksumInfo->V4Receive.IpChecksum) {
|
||
|
Flags |= IP_RCV_CHECKSUM_OFFLOAD;
|
||
|
AADEBUGP(AAD_INFO, (" IP rcv Checksum offload\n"));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else if (pTask->Task == TcpLargeSendNdisTask)
|
||
|
{
|
||
|
|
||
|
PNDIS_TASK_TCP_LARGE_SEND TcpLargeSend, in_LargeSend =
|
||
|
(PNDIS_TASK_TCP_LARGE_SEND)pTask->TaskBuffer;
|
||
|
|
||
|
Flags |= TCP_LARGE_SEND_OFFLOAD;
|
||
|
|
||
|
MaxOffLoadSize = in_LargeSend->MaxOffLoadSize;
|
||
|
MinSegmentCount = in_LargeSend->MinSegmentCount;
|
||
|
|
||
|
AADEBUGP(AAD_INFO, (" Tcp large send!! \n"));
|
||
|
|
||
|
}
|
||
|
else if (pTask->Task == IpSecNdisTask)
|
||
|
{
|
||
|
PNDIS_TASK_IPSEC pIPSecCaps =
|
||
|
(PNDIS_TASK_IPSEC) pTask->TaskBuffer;
|
||
|
//
|
||
|
// Save off the capabilities for setting them later.
|
||
|
//
|
||
|
ipsecCaps = *pIPSecCaps;
|
||
|
|
||
|
|
||
|
//
|
||
|
// CryptoOnly is assumed if we have IpSecNdisTask
|
||
|
//
|
||
|
Flags |= IPSEC_OFFLOAD_CRYPTO_ONLY;
|
||
|
|
||
|
//
|
||
|
// Do Support first
|
||
|
//
|
||
|
|
||
|
if (pIPSecCaps->Supported.AH_ESP_COMBINED) {
|
||
|
Flags |= IPSEC_OFFLOAD_AH_ESP;
|
||
|
AADEBUGP(AAD_INFO, ("AH_ESP\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->Supported.TRANSPORT_TUNNEL_COMBINED) {
|
||
|
Flags |= IPSEC_OFFLOAD_TPT_TUNNEL;
|
||
|
AADEBUGP(AAD_INFO, ("TPT_TUNNEL\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->Supported.V4_OPTIONS) {
|
||
|
Flags |= IPSEC_OFFLOAD_V4_OPTIONS;
|
||
|
AADEBUGP(AAD_INFO, ("V4_OPTIONS\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->Supported.RESERVED) {
|
||
|
pIPSecCaps->Supported.RESERVED = 0;
|
||
|
//Flags |= IPSEC_OFFLOAD_QUERY_SPI;
|
||
|
AADEBUGP(AAD_INFO, ("QUERY_SPI\n"));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Do V4AH next
|
||
|
//
|
||
|
|
||
|
if (pIPSecCaps->V4AH.MD5) {
|
||
|
Flags |= IPSEC_OFFLOAD_AH_MD5;
|
||
|
AADEBUGP(AAD_INFO, ("MD5\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->V4AH.SHA_1) {
|
||
|
Flags |= IPSEC_OFFLOAD_AH_SHA_1;
|
||
|
AADEBUGP(AAD_INFO, ("SHA\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->V4AH.Transport) {
|
||
|
Flags |= IPSEC_OFFLOAD_AH_TPT;
|
||
|
AADEBUGP(AAD_INFO, ("AH_TRANSPORT\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->V4AH.Tunnel) {
|
||
|
Flags |= IPSEC_OFFLOAD_AH_TUNNEL;
|
||
|
AADEBUGP(AAD_INFO, ("AH_TUNNEL\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->V4AH.Send) {
|
||
|
Flags |= IPSEC_OFFLOAD_AH_XMT;
|
||
|
AADEBUGP(AAD_INFO, ("AH_XMT\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->V4AH.Receive) {
|
||
|
Flags |= IPSEC_OFFLOAD_AH_RCV;
|
||
|
AADEBUGP(AAD_INFO, ("AH_RCV\n"));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Do V4ESP next
|
||
|
//
|
||
|
|
||
|
if (pIPSecCaps->V4ESP.DES) {
|
||
|
Flags |= IPSEC_OFFLOAD_ESP_DES;
|
||
|
AADEBUGP(AAD_INFO, ("ESP_DES\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->V4ESP.RESERVED) {
|
||
|
pIPSecCaps->V4ESP.RESERVED = 0;
|
||
|
//Flags |= IPSEC_OFFLOAD_ESP_DES_40;
|
||
|
AADEBUGP(AAD_INFO, ("ESP_DES_40\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->V4ESP.TRIPLE_DES) {
|
||
|
Flags |= IPSEC_OFFLOAD_ESP_3_DES;
|
||
|
AADEBUGP(AAD_INFO, ("ESP_3_DES\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->V4ESP.NULL_ESP) {
|
||
|
Flags |= IPSEC_OFFLOAD_ESP_NONE;
|
||
|
AADEBUGP(AAD_INFO, ("ESP_NONE\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->V4ESP.Transport) {
|
||
|
Flags |= IPSEC_OFFLOAD_ESP_TPT;
|
||
|
AADEBUGP(AAD_INFO, ("ESP_TRANSPORT\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->V4ESP.Tunnel) {
|
||
|
Flags |= IPSEC_OFFLOAD_ESP_TUNNEL;
|
||
|
AADEBUGP(AAD_INFO, ("ESP_TUNNEL\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->V4ESP.Send) {
|
||
|
Flags |= IPSEC_OFFLOAD_ESP_XMT;
|
||
|
AADEBUGP(AAD_INFO, ("ESP_XMT\n"));
|
||
|
}
|
||
|
|
||
|
if (pIPSecCaps->V4ESP.Receive) {
|
||
|
Flags |= IPSEC_OFFLOAD_ESP_RCV;
|
||
|
AADEBUGP(AAD_INFO, ("ESP_RCV\n"));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pTask->OffsetNextTask == 0)
|
||
|
{
|
||
|
break; // No more tasks.
|
||
|
}
|
||
|
|
||
|
} // for
|
||
|
|
||
|
//
|
||
|
// Done parsing supported tasks.
|
||
|
// Now construct the set of tasks we actually want to enable.
|
||
|
//
|
||
|
if (Flags)
|
||
|
{
|
||
|
UINT *pPrevOffset = &pHeader->OffsetFirstTask;
|
||
|
|
||
|
AADEBUGP(AAD_WARNING, ("Enabling H/W capabilities: %lx\n", Flags));
|
||
|
|
||
|
//
|
||
|
// Zero out the buffer beyond the task offload header structure
|
||
|
//
|
||
|
AA_SET_MEM(pTask, 0, BufferSize-sizeof(*pHeader));
|
||
|
pHeader->OffsetFirstTask = 0;
|
||
|
pTask = (NDIS_TASK_OFFLOAD *) (pHeader+1);
|
||
|
|
||
|
if ((Flags & TCP_XMT_CHECKSUM_OFFLOAD) ||
|
||
|
(Flags & IP_XMT_CHECKSUM_OFFLOAD) ||
|
||
|
(Flags & TCP_RCV_CHECKSUM_OFFLOAD) ||
|
||
|
(Flags & IP_RCV_CHECKSUM_OFFLOAD))
|
||
|
{
|
||
|
|
||
|
PNDIS_TASK_TCP_IP_CHECKSUM ChksumBuf =
|
||
|
(PNDIS_TASK_TCP_IP_CHECKSUM)pTask->TaskBuffer;
|
||
|
|
||
|
*pPrevOffset = (UINT) ((PUCHAR)pTask - (PUCHAR)pHeader);
|
||
|
pPrevOffset = &pTask->OffsetNextTask;
|
||
|
|
||
|
pTask->Task = TcpIpChecksumNdisTask;
|
||
|
pTask->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
|
||
|
|
||
|
if (Flags & TCP_XMT_CHECKSUM_OFFLOAD)
|
||
|
{
|
||
|
ChksumBuf->V4Transmit.TcpChecksum = 1;
|
||
|
//ChksumBuf->V4Transmit.V4Checksum = 1;
|
||
|
}
|
||
|
|
||
|
if (Flags & IP_XMT_CHECKSUM_OFFLOAD)
|
||
|
{
|
||
|
ChksumBuf->V4Transmit.IpChecksum = 1;
|
||
|
//ChksumBuf->V4Transmit.V4Checksum = 1;
|
||
|
}
|
||
|
|
||
|
if (Flags & TCP_RCV_CHECKSUM_OFFLOAD)
|
||
|
{
|
||
|
ChksumBuf->V4Receive.TcpChecksum = 1;
|
||
|
//ChksumBuf->V4Receive.V4Checksum = 1;
|
||
|
}
|
||
|
|
||
|
if (Flags & IP_RCV_CHECKSUM_OFFLOAD)
|
||
|
{
|
||
|
ChksumBuf->V4Receive.IpChecksum = 1;
|
||
|
//ChksumBuf->V4Receive.V4Checksum = 1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Point to place where next task goes...
|
||
|
//
|
||
|
pTask = (PNDIS_TASK_OFFLOAD) (ChksumBuf+1);
|
||
|
|
||
|
}
|
||
|
|
||
|
if (Flags & TCP_LARGE_SEND_OFFLOAD)
|
||
|
{
|
||
|
|
||
|
PNDIS_TASK_TCP_LARGE_SEND out_LargeSend =
|
||
|
(PNDIS_TASK_TCP_LARGE_SEND)pTask->TaskBuffer;
|
||
|
|
||
|
*pPrevOffset = (UINT) ((PUCHAR)pTask - (PUCHAR)pHeader);
|
||
|
pPrevOffset = &pTask->OffsetNextTask;
|
||
|
|
||
|
pTask->Task = TcpLargeSendNdisTask;
|
||
|
pTask->TaskBufferLength = sizeof(NDIS_TASK_TCP_LARGE_SEND);
|
||
|
|
||
|
out_LargeSend->MaxOffLoadSize = MaxOffLoadSize;
|
||
|
out_LargeSend->MinSegmentCount = MinSegmentCount;
|
||
|
|
||
|
//
|
||
|
// Point to place where next task goes...
|
||
|
//
|
||
|
pTask = (PNDIS_TASK_OFFLOAD) (out_LargeSend+1);
|
||
|
}
|
||
|
|
||
|
if ((Flags & (IPSEC_OFFLOAD_AH_XMT |
|
||
|
IPSEC_OFFLOAD_AH_RCV |
|
||
|
IPSEC_OFFLOAD_ESP_XMT |
|
||
|
IPSEC_OFFLOAD_ESP_RCV)))
|
||
|
{
|
||
|
|
||
|
PNDIS_TASK_IPSEC pIPSecCaps =
|
||
|
(PNDIS_TASK_IPSEC)pTask->TaskBuffer;
|
||
|
|
||
|
*pPrevOffset = (UINT) ((PUCHAR)pTask - (PUCHAR)pHeader);
|
||
|
pPrevOffset = &pTask->OffsetNextTask;
|
||
|
|
||
|
//
|
||
|
// plunk down the advertised capabilities
|
||
|
//
|
||
|
|
||
|
pTask->Task = IpSecNdisTask;
|
||
|
pTask->TaskBufferLength = sizeof(NDIS_TASK_IPSEC);
|
||
|
|
||
|
//
|
||
|
// Point to place where next task goes...
|
||
|
//
|
||
|
pTask = (PNDIS_TASK_OFFLOAD) (pIPSecCaps+1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Having constructed the set of tasks to enable, we actually attempt
|
||
|
// to enable them...
|
||
|
//
|
||
|
if (pHeader->OffsetFirstTask)
|
||
|
{
|
||
|
//
|
||
|
// At least one task to enable, let's enable ...
|
||
|
//
|
||
|
UINT SetBufferSize = (UINT) ((PUCHAR)pTask - (PUCHAR)pHeader);
|
||
|
|
||
|
AA_ASSERT(SetBufferSize <= BufferSize);
|
||
|
AADEBUGP(AAD_WARNING,
|
||
|
("Setting offload tasks: %x bytes. Miniport returned %x bytes\n",
|
||
|
SetBufferSize, BufferSize));
|
||
|
|
||
|
Status = AtmArpSendAdapterNdisRequest(
|
||
|
pAdapter,
|
||
|
&NdisRequest,
|
||
|
NdisRequestSetInformation,
|
||
|
OID_TCP_TASK_OFFLOAD,
|
||
|
pHeader,
|
||
|
SetBufferSize
|
||
|
);
|
||
|
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
|
||
|
AADEBUGP(AAD_WARNING,
|
||
|
("ARP: Failed to set offload tasks: %lx, status: %lx\n",
|
||
|
Flags, Status));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AADEBUGP(AAD_WARNING,
|
||
|
("ARP: Succeeded setting offload tasks: %lx:\n", Flags));
|
||
|
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
pAdapter->Offload.Flags = Flags;
|
||
|
pAdapter->Offload.MaxOffLoadSize = MaxOffLoadSize;
|
||
|
pAdapter->Offload.MinSegmentCount = MinSegmentCount;
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} while (FALSE);
|
||
|
|
||
|
|
||
|
if (pHeader != NULL)
|
||
|
{
|
||
|
AA_FREE_MEM(pHeader);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We return success unless there was a fatal error and there was none...
|
||
|
//
|
||
|
|
||
|
return NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
AtmArpDisableOffload(
|
||
|
IN PATMARP_ADAPTER pAdapter
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Disable offload capabilities, if enabled for this interface.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pAdapter - The adapter on which to disable offloading.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE iff the operation was either succesful or no tasks were enabled. False
|
||
|
if there was a fatal error.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG Flags;
|
||
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
Flags = pAdapter->Offload.Flags;
|
||
|
pAdapter->Offload.Flags = 0;
|
||
|
pAdapter->Offload.MaxOffLoadSize = 0;
|
||
|
pAdapter->Offload.MinSegmentCount = 0;
|
||
|
|
||
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
||
|
|
||
|
if (Flags)
|
||
|
{
|
||
|
NDIS_REQUEST NdisRequest;
|
||
|
NDIS_TASK_OFFLOAD_HEADER Header;
|
||
|
AA_SET_MEM(&Header, 0, sizeof(Header));
|
||
|
|
||
|
Header.EncapsulationFormat.Flags.FixedHeaderSize = 1;
|
||
|
Header.EncapsulationFormat.EncapsulationHeaderSize = 2;
|
||
|
Header.EncapsulationFormat.Encapsulation =
|
||
|
LLC_SNAP_ROUTED_Encapsulation;
|
||
|
Header.Version = NDIS_TASK_OFFLOAD_VERSION;
|
||
|
Header.Size = sizeof(Header);
|
||
|
|
||
|
//
|
||
|
// Header.OffsetFirstTask == 0 tells the miniport to disable all tasks.
|
||
|
//
|
||
|
|
||
|
AADEBUGP(AAD_WARNING, ("Disabling all offloaded tasks for this adapter\n"));
|
||
|
|
||
|
AtmArpSendAdapterNdisRequest(
|
||
|
pAdapter,
|
||
|
&NdisRequest,
|
||
|
NdisRequestSetInformation,
|
||
|
OID_TCP_TASK_OFFLOAD,
|
||
|
&Header,
|
||
|
sizeof(Header)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif // ATMOFFLOAD
|
||
|
|