2342 lines
54 KiB
C
2342 lines
54 KiB
C
/*++
|
|
|
|
Copyright (c) 1997 FORE Systems, Inc.
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
miniport.c
|
|
|
|
Abstract:
|
|
|
|
Miniport upper-edge functions.
|
|
|
|
Author:
|
|
|
|
Larry Cleeton, FORE Systems (v-lcleet@microsoft.com, lrc@fore.com)
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// List of supported OIDs for this driver when an Ethernet Elan.
|
|
//
|
|
static
|
|
NDIS_OID EthernetSupportedOids[] = {
|
|
OID_GEN_SUPPORTED_LIST,
|
|
OID_GEN_HARDWARE_STATUS,
|
|
OID_GEN_MEDIA_CONNECT_STATUS,
|
|
OID_GEN_MEDIA_SUPPORTED,
|
|
OID_GEN_MEDIA_IN_USE,
|
|
OID_GEN_MAXIMUM_LOOKAHEAD,
|
|
OID_GEN_MAXIMUM_FRAME_SIZE,
|
|
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
|
OID_GEN_MAC_OPTIONS,
|
|
OID_GEN_PROTOCOL_OPTIONS,
|
|
OID_GEN_LINK_SPEED,
|
|
OID_GEN_TRANSMIT_BUFFER_SPACE,
|
|
OID_GEN_RECEIVE_BUFFER_SPACE,
|
|
OID_GEN_TRANSMIT_BLOCK_SIZE,
|
|
OID_GEN_RECEIVE_BLOCK_SIZE,
|
|
OID_GEN_MAXIMUM_SEND_PACKETS,
|
|
OID_GEN_VENDOR_DESCRIPTION,
|
|
OID_GEN_VENDOR_ID,
|
|
OID_GEN_DRIVER_VERSION,
|
|
OID_GEN_VENDOR_DRIVER_VERSION,
|
|
OID_GEN_CURRENT_PACKET_FILTER,
|
|
OID_GEN_CURRENT_LOOKAHEAD,
|
|
OID_GEN_XMIT_OK,
|
|
OID_GEN_RCV_OK,
|
|
OID_GEN_XMIT_ERROR,
|
|
OID_GEN_RCV_ERROR,
|
|
OID_GEN_RCV_NO_BUFFER,
|
|
OID_802_3_PERMANENT_ADDRESS,
|
|
OID_802_3_CURRENT_ADDRESS,
|
|
OID_802_3_MULTICAST_LIST,
|
|
OID_802_3_MAXIMUM_LIST_SIZE,
|
|
OID_802_3_RCV_ERROR_ALIGNMENT,
|
|
OID_802_3_XMIT_ONE_COLLISION,
|
|
OID_802_3_XMIT_MORE_COLLISIONS,
|
|
OID_GEN_NETWORK_LAYER_ADDRESSES,
|
|
};
|
|
|
|
static
|
|
NDIS_OID TokenRingSupportedOids[] = {
|
|
OID_GEN_SUPPORTED_LIST,
|
|
OID_GEN_HARDWARE_STATUS,
|
|
OID_GEN_MEDIA_CONNECT_STATUS,
|
|
OID_GEN_MEDIA_SUPPORTED,
|
|
OID_GEN_MEDIA_IN_USE,
|
|
OID_GEN_MAXIMUM_LOOKAHEAD,
|
|
OID_GEN_MAXIMUM_FRAME_SIZE,
|
|
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
|
OID_GEN_MAC_OPTIONS,
|
|
OID_GEN_PROTOCOL_OPTIONS,
|
|
OID_GEN_LINK_SPEED,
|
|
OID_GEN_TRANSMIT_BUFFER_SPACE,
|
|
OID_GEN_RECEIVE_BUFFER_SPACE,
|
|
OID_GEN_TRANSMIT_BLOCK_SIZE,
|
|
OID_GEN_RECEIVE_BLOCK_SIZE,
|
|
OID_GEN_MAXIMUM_SEND_PACKETS,
|
|
OID_GEN_VENDOR_ID,
|
|
OID_GEN_VENDOR_DESCRIPTION,
|
|
OID_GEN_DRIVER_VERSION,
|
|
OID_GEN_VENDOR_DRIVER_VERSION,
|
|
OID_GEN_CURRENT_PACKET_FILTER,
|
|
OID_GEN_CURRENT_LOOKAHEAD,
|
|
OID_GEN_XMIT_OK,
|
|
OID_GEN_RCV_OK,
|
|
OID_GEN_XMIT_ERROR,
|
|
OID_GEN_RCV_ERROR,
|
|
OID_GEN_RCV_NO_BUFFER,
|
|
OID_802_5_PERMANENT_ADDRESS,
|
|
OID_802_5_CURRENT_ADDRESS,
|
|
OID_802_5_CURRENT_FUNCTIONAL,
|
|
OID_802_5_CURRENT_GROUP,
|
|
OID_802_5_LAST_OPEN_STATUS,
|
|
OID_802_5_CURRENT_RING_STATUS,
|
|
OID_802_5_CURRENT_RING_STATE,
|
|
OID_802_5_LINE_ERRORS,
|
|
OID_802_5_LOST_FRAMES,
|
|
OID_802_5_BURST_ERRORS,
|
|
OID_802_5_FRAME_COPIED_ERRORS,
|
|
OID_802_5_TOKEN_ERRORS,
|
|
OID_GEN_NETWORK_LAYER_ADDRESSES,
|
|
};
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmLaneMInitialize(
|
|
OUT PNDIS_STATUS OpenErrorStatus,
|
|
OUT PUINT SelectedMediumIndex,
|
|
IN PNDIS_MEDIUM MediumArray,
|
|
IN UINT MediumArraySize,
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_HANDLE WrapperConfigurationContext
|
|
)
|
|
{
|
|
UINT i;
|
|
NDIS_MEDIUM MediumToFind;
|
|
NDIS_STATUS Status;
|
|
PATMLANE_ELAN pElan;
|
|
PUCHAR pMacAddr;
|
|
UINT MacAddrLength;
|
|
|
|
|
|
TRACEIN(MInitialize);
|
|
|
|
//
|
|
// Get context (Elan) supplied with NdisIMInitializeDeviceEx
|
|
//
|
|
pElan = NdisIMGetDeviceContext(MiniportAdapterHandle);
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
ASSERT(pElan->Flags & ELAN_MINIPORT_INIT_PENDING);
|
|
|
|
DBGP((1, "%d MInitialize\n", pElan->ElanNumber));
|
|
|
|
do
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
//
|
|
// Are we Ethernet or Token Ring?
|
|
//
|
|
if (pElan->LanType == LANE_LANTYPE_ETH)
|
|
{
|
|
MediumToFind = NdisMedium802_3;
|
|
}
|
|
else
|
|
{
|
|
MediumToFind = NdisMedium802_5;
|
|
}
|
|
|
|
//
|
|
// Look for MediumToFind in MediumArray.
|
|
//
|
|
for (i = 0; i < MediumArraySize; i++)
|
|
{
|
|
if (MediumArray[i] == MediumToFind)
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Not found, return error.
|
|
|
|
if (i == MediumArraySize)
|
|
{
|
|
Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
|
|
break;
|
|
}
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
//
|
|
// Output select medium
|
|
//
|
|
*SelectedMediumIndex = i;
|
|
|
|
//
|
|
// Set my attributes
|
|
//
|
|
NdisMSetAttributesEx(
|
|
MiniportAdapterHandle, // MiniportAdapterHandle
|
|
(NDIS_HANDLE)pElan, // MiniportAdapterContext
|
|
0, // CheckForHangTimeInSeconds
|
|
NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT | // AttributeFlags
|
|
NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT |
|
|
NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER |
|
|
NDIS_ATTRIBUTE_DESERIALIZE,
|
|
0 // AdapterType
|
|
);
|
|
|
|
ACQUIRE_ELAN_LOCK(pElan);
|
|
AtmLaneReferenceElan(pElan, "miniport");
|
|
|
|
//
|
|
// Save away the MiniportAdapterHandle now. This is so that we
|
|
// don't call NdisMIndicateStatus before calling NdisMSetAttributesEx.
|
|
//
|
|
pElan->MiniportAdapterHandle = MiniportAdapterHandle;
|
|
|
|
RELEASE_ELAN_LOCK(pElan);
|
|
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
//
|
|
// Wake up any thread (i.e. AtmLaneShutdownElan) waiting for
|
|
// a pending Init to be over.
|
|
//
|
|
ACQUIRE_ELAN_LOCK(pElan);
|
|
pElan->Flags &= ~ELAN_MINIPORT_INIT_PENDING;
|
|
RELEASE_ELAN_LOCK(pElan);
|
|
|
|
DBGP((2, "%d MInitialize ELAN %p/%x, Ref %d, Status %x\n",
|
|
pElan->ElanNumber, pElan, pElan->Flags, pElan->RefCount, Status));
|
|
|
|
SIGNAL_BLOCK_STRUCT(&pElan->InitBlock, NDIS_STATUS_SUCCESS);
|
|
|
|
TRACEOUT(MInitialize);
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
AtmLaneMSendPackets(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
{
|
|
PATMLANE_ELAN pElan;
|
|
UINT PacketIndex;
|
|
PNDIS_PACKET pSendNdisPacket;
|
|
PNDIS_PACKET pNewNdisPacket;
|
|
PNDIS_BUFFER pHeaderNdisBuffer;
|
|
PUCHAR pHeaderBuffer;
|
|
PUCHAR pPktHeader;
|
|
PNDIS_BUFFER pTempNdisBuffer;
|
|
PATMLANE_VC pVc;
|
|
ULONG TotalLength;
|
|
ULONG BufferLength;
|
|
NDIS_STATUS Status;
|
|
ULONG DestAddrType;
|
|
MAC_ADDRESS DestAddress;
|
|
BOOLEAN SendViaBUS;
|
|
PATMLANE_MAC_ENTRY pMacEntry;
|
|
PATMLANE_ATM_ENTRY pAtmEntry;
|
|
ULONG rc;
|
|
#if DEBUG_IRQL
|
|
KIRQL EntryIrql;
|
|
#endif
|
|
|
|
GET_ENTRY_IRQL(EntryIrql);
|
|
|
|
TRACEIN(MSendPackets);
|
|
|
|
pElan = (PATMLANE_ELAN)MiniportAdapterContext;
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
TRACELOGWRITE((&TraceLog, TL_MSENDPKTIN, NumberOfPackets));
|
|
|
|
DBGP((2, "MSendPackets: Count %d\n", NumberOfPackets));
|
|
|
|
//
|
|
// loop thru the array of packets to send
|
|
//
|
|
for (PacketIndex = 0; PacketIndex < NumberOfPackets; PacketIndex++)
|
|
{
|
|
pSendNdisPacket = PacketArray[PacketIndex];
|
|
|
|
pNewNdisPacket = (PNDIS_PACKET)NULL;
|
|
SendViaBUS = FALSE;
|
|
pMacEntry = NULL_PATMLANE_MAC_ENTRY;
|
|
pVc = NULL_PATMLANE_VC;
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
|
|
// DBGP((0, "MSendPackets: Pkt %x\n", pSendNdisPacket));
|
|
|
|
TRACELOGWRITE((&TraceLog, TL_MSENDPKTBEGIN, PacketIndex, pSendNdisPacket));
|
|
TRACELOGWRITEPKT((&TraceLog, pSendNdisPacket));
|
|
|
|
//
|
|
// ALWAYS set packet status to NDIS_STATUS_PENDING
|
|
//
|
|
NDIS_SET_PACKET_STATUS(pSendNdisPacket, NDIS_STATUS_PENDING);
|
|
|
|
do
|
|
{
|
|
//
|
|
// Wrap it up for sending
|
|
//
|
|
pNewNdisPacket = AtmLaneWrapSendPacket(
|
|
pElan,
|
|
pSendNdisPacket,
|
|
&DestAddrType,
|
|
&DestAddress,
|
|
&SendViaBUS
|
|
);
|
|
if (pNewNdisPacket == (PNDIS_PACKET)NULL)
|
|
{
|
|
//
|
|
// Out of resources
|
|
//
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If Elan is down then just set local status to failure
|
|
//
|
|
if (ELAN_STATE_OPERATIONAL != pElan->State ||
|
|
ELAN_STATE_OPERATIONAL != pElan->AdminState)
|
|
{
|
|
DBGP((0, "%d Send failure on ELAN %x flags %x state %d AdminSt %d\n",
|
|
pElan->ElanNumber,
|
|
pElan,
|
|
pElan->Flags,
|
|
pElan->State,
|
|
pElan->AdminState));
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
if (SendViaBUS)
|
|
{
|
|
//
|
|
// Packet is multicast so send it to the bus
|
|
//
|
|
ACQUIRE_ELAN_ATM_LIST_LOCK(pElan);
|
|
|
|
pAtmEntry = pElan->pBusAtmEntry;
|
|
|
|
if (pAtmEntry == NULL_PATMLANE_ATM_ENTRY)
|
|
{
|
|
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
ACQUIRE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
|
|
pVc = pAtmEntry->pVcList;
|
|
if (pVc == NULL_PATMLANE_VC)
|
|
{
|
|
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
|
|
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Reference the VC to keep it around
|
|
//
|
|
ACQUIRE_VC_LOCK_DPC(pVc);
|
|
AtmLaneReferenceVc(pVc, "temp");
|
|
RELEASE_VC_LOCK_DPC(pVc);
|
|
|
|
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
|
|
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
|
|
|
|
|
|
//
|
|
// Reacquire VC lock and dereference it
|
|
//
|
|
ACQUIRE_VC_LOCK(pVc);
|
|
rc = AtmLaneDereferenceVc(pVc, "temp");
|
|
if (rc == 0)
|
|
{
|
|
//
|
|
// Vc pulled out from under us.
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Send it!
|
|
//
|
|
DBGP((2, "MSendPackets: Sending to BUS, VC %x\n", pVc));
|
|
AtmLaneSendPacketOnVc(pVc, pNewNdisPacket, FALSE);
|
|
//
|
|
// VC lock released in above
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Packet is unicast
|
|
//
|
|
DBGP((2, "MSendPackets: Sending unicast, dest %x:%x:%x:%x:%x:%x\n",
|
|
((PUCHAR)&DestAddress)[0],
|
|
((PUCHAR)&DestAddress)[1],
|
|
((PUCHAR)&DestAddress)[2],
|
|
((PUCHAR)&DestAddress)[3],
|
|
((PUCHAR)&DestAddress)[4],
|
|
((PUCHAR)&DestAddress)[5]
|
|
));
|
|
|
|
Status = AtmLaneSendUnicastPacket(
|
|
pElan,
|
|
DestAddrType,
|
|
&DestAddress,
|
|
pNewNdisPacket
|
|
);
|
|
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
//
|
|
// If no new packet header than it must be a resource failure
|
|
// or Elan is down.
|
|
// Complete the packet with NDIS_STATUS_SUCCESS.
|
|
//
|
|
if (pNewNdisPacket == (PNDIS_PACKET)NULL)
|
|
{
|
|
ASSERT(Status != NDIS_STATUS_PENDING);
|
|
|
|
// DBGP((0, "NdisMSendComplete: Pkt %x Stat %x\n", pSendNdisPacket, NDIS_STATUS_SUCCESS));
|
|
|
|
NdisMSendComplete(
|
|
pElan->MiniportAdapterHandle,
|
|
pSendNdisPacket,
|
|
NDIS_STATUS_SUCCESS);
|
|
|
|
TRACELOGWRITE((&TraceLog, TL_MSENDPKTEND, PacketIndex, pSendNdisPacket, Status));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// If status isn't pending then some other failure to send occurred.
|
|
// Complete the packet with NDIS_STATUS_SUCCESS.
|
|
//
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
#if PROTECT_PACKETS
|
|
ACQUIRE_SENDPACKET_LOCK(pNewNdisPacket);
|
|
ASSERT((PSEND_RSVD(pNewNdisPacket)->Flags & PACKET_RESERVED_COSENDRETURNED) == 0);
|
|
ASSERT((PSEND_RSVD(pNewNdisPacket)->Flags & PACKET_RESERVED_COMPLETED) == 0);
|
|
PSEND_RSVD(pNewNdisPacket)->Flags |= PACKET_RESERVED_COSENDRETURNED;
|
|
PSEND_RSVD(pNewNdisPacket)->Flags |= PACKET_RESERVED_COMPLETED;
|
|
#endif // PROTECT_PACKETS
|
|
AtmLaneCompleteSendPacket(pElan, pNewNdisPacket, NDIS_STATUS_SUCCESS);
|
|
//
|
|
// packet lock released in above
|
|
//
|
|
TRACELOGWRITE((&TraceLog, TL_MSENDPKTEND, PacketIndex, pSendNdisPacket, Status));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Otherwise do nothing
|
|
//
|
|
ASSERT(Status == NDIS_STATUS_PENDING);
|
|
TRACELOGWRITE((&TraceLog, TL_MSENDPKTEND, PacketIndex, pSendNdisPacket, Status));
|
|
|
|
} // for(...next packet
|
|
|
|
TRACELOGWRITE((&TraceLog, TL_MSENDPKTOUT));
|
|
|
|
TRACEOUT(MSendPackets);
|
|
|
|
CHECK_EXIT_IRQL(EntryIrql);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
AtmLaneMReturnPacket(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by a protocol or by NDIS on
|
|
behalf of a protocol to return a packet that was
|
|
retained beyond the context of the receive indication.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext - Pointer to ATMLANE elan structure
|
|
|
|
pNdisPacket - Pointer to NDIS packet
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
PATMLANE_ELAN pElan;
|
|
PNDIS_PACKET pOrigNdisPacket;
|
|
PNDIS_BUFFER pTempNdisBuffer;
|
|
ULONG Length;
|
|
#if DEBUG_IRQL
|
|
KIRQL EntryIrql;
|
|
#endif
|
|
GET_ENTRY_IRQL(EntryIrql);
|
|
|
|
TRACEIN(MReturnPacket);
|
|
|
|
pElan = (PATMLANE_ELAN)MiniportAdapterContext;
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
TRACELOGWRITE((&TraceLog,
|
|
TL_MRETNPACKET,
|
|
pNdisPacket));
|
|
|
|
ASSERT(NDIS_GET_PACKET_STATUS(pNdisPacket) != NDIS_STATUS_RESOURCES);
|
|
|
|
pOrigNdisPacket = AtmLaneUnwrapRecvPacket(pElan, pNdisPacket);
|
|
|
|
TRACELOGWRITE((&TraceLog,
|
|
TL_CORETNPACKET,
|
|
pOrigNdisPacket));
|
|
|
|
//
|
|
// Return original packet to ATM miniport.
|
|
//
|
|
NdisReturnPackets(
|
|
&pOrigNdisPacket,
|
|
1);
|
|
|
|
TRACEOUT(MReturnPacket);
|
|
CHECK_EXIT_IRQL(EntryIrql);
|
|
return;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
AtmLaneMQueryInformation(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN NDIS_OID Oid,
|
|
IN PVOID InformationBuffer,
|
|
IN ULONG InformationBufferLength,
|
|
OUT PULONG BytesWritten,
|
|
OUT PULONG BytesNeeded
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The QueryInformation Handler for the virtual miniport.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext - a pointer to the Elan.
|
|
|
|
Oid - the NDIS_OID to process.
|
|
|
|
InformationBuffer - a pointer into the NdisRequest->InformationBuffer
|
|
into which store the result of the query.
|
|
|
|
InformationBufferLength - a pointer to the number of bytes left in the
|
|
InformationBuffer.
|
|
|
|
BytesWritten - a pointer to the number of bytes written into the
|
|
InformationBuffer.
|
|
|
|
BytesNeeded - If there is not enough room in the information
|
|
buffer then this will contain the number of bytes
|
|
needed to complete the request.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
{
|
|
UINT BytesLeft = InformationBufferLength;
|
|
PUCHAR InfoBuffer = (PUCHAR)(InformationBuffer);
|
|
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
|
|
NDIS_MEDIA_STATE MediaState;
|
|
NDIS_MEDIUM Medium;
|
|
PATMLANE_ELAN pElan;
|
|
PATMLANE_ADAPTER pAdapter;
|
|
ULONG GenericULong;
|
|
USHORT GenericUShort;
|
|
UCHAR GenericArray[6];
|
|
UINT MoveBytes = sizeof(ULONG);
|
|
PVOID MoveSource = (PVOID)(&GenericULong);
|
|
ULONG i;
|
|
PATMLANE_MAC_ENTRY pMacEntry;
|
|
PATMLANE_ATM_ENTRY pAtmEntry;
|
|
BOOLEAN IsShuttingDown;
|
|
#if DEBUG_IRQL
|
|
KIRQL EntryIrql;
|
|
#endif
|
|
GET_ENTRY_IRQL(EntryIrql);
|
|
|
|
TRACEIN(MQueryInformation);
|
|
|
|
pElan = (PATMLANE_ELAN)MiniportAdapterContext;
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
DBGP((1, "%d Query OID %x %s\n", pElan->ElanNumber, Oid, OidToString(Oid)));
|
|
|
|
ACQUIRE_ELAN_LOCK(pElan);
|
|
IsShuttingDown = (ELAN_STATE_OPERATIONAL != pElan->AdminState);
|
|
pAdapter = pElan->pAdapter;
|
|
RELEASE_ELAN_LOCK(pElan);
|
|
|
|
//
|
|
// Switch on request type
|
|
//
|
|
switch (Oid)
|
|
{
|
|
case OID_GEN_MAC_OPTIONS:
|
|
|
|
GenericULong =
|
|
NDIS_MAC_OPTION_NO_LOOPBACK;
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
case OID_GEN_SUPPORTED_LIST:
|
|
|
|
if (pElan->LanType == LANE_LANTYPE_ETH)
|
|
{
|
|
MoveSource = (PVOID)(EthernetSupportedOids);
|
|
MoveBytes = sizeof(EthernetSupportedOids);
|
|
}
|
|
else
|
|
{
|
|
MoveSource = (PVOID)(TokenRingSupportedOids);
|
|
MoveBytes = sizeof(TokenRingSupportedOids);
|
|
}
|
|
break;
|
|
|
|
case OID_GEN_HARDWARE_STATUS:
|
|
|
|
HardwareStatus = NdisHardwareStatusReady;
|
|
MoveSource = (PVOID)(&HardwareStatus);
|
|
MoveBytes = sizeof(NDIS_HARDWARE_STATUS);
|
|
|
|
break;
|
|
|
|
case OID_GEN_MEDIA_CONNECT_STATUS:
|
|
if (ELAN_STATE_OPERATIONAL == pElan->State)
|
|
{
|
|
MediaState = NdisMediaStateConnected;
|
|
}
|
|
else
|
|
{
|
|
MediaState = NdisMediaStateDisconnected;
|
|
}
|
|
DBGP((2, "%d Elan %p returning conn status %d: %s\n",
|
|
pElan->ElanNumber,
|
|
pElan,
|
|
MediaState,
|
|
((MediaState == NdisMediaStateConnected)?
|
|
"Connected": "Disconnected")));
|
|
MoveSource = (PVOID)(&MediaState);
|
|
MoveBytes = sizeof(NDIS_MEDIA_STATE);
|
|
|
|
break;
|
|
|
|
case OID_GEN_MEDIA_SUPPORTED:
|
|
case OID_GEN_MEDIA_IN_USE:
|
|
|
|
if (pElan->LanType == LANE_LANTYPE_ETH)
|
|
{
|
|
Medium = NdisMedium802_3;
|
|
DBGP((2, "Media is NdisMedium802_3\n"));
|
|
}
|
|
else
|
|
{
|
|
Medium = NdisMedium802_5;
|
|
DBGP((2, "Media is NdisMedium802_5\n"));
|
|
}
|
|
MoveSource = (PVOID) (&Medium);
|
|
MoveBytes = sizeof(NDIS_MEDIUM);
|
|
|
|
break;
|
|
|
|
case OID_GEN_MAXIMUM_LOOKAHEAD:
|
|
|
|
if (pAdapter != NULL_PATMLANE_ADAPTER)
|
|
{
|
|
GenericULong = pElan->pAdapter->MaxAAL5PacketSize;
|
|
}
|
|
else
|
|
{
|
|
GenericULong = pElan->CurLookAhead;
|
|
}
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
|
|
if (pElan->CurLookAhead == 0)
|
|
{
|
|
if (pAdapter != NULL_PATMLANE_ADAPTER)
|
|
{
|
|
pElan->CurLookAhead = pAdapter->MaxAAL5PacketSize;
|
|
}
|
|
}
|
|
|
|
GenericULong = pElan->CurLookAhead;
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
|
|
|
GenericULong = (pElan->MaxFrameSize - LANE_ETH_HEADERSIZE);
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
|
|
|
GenericULong = (pElan->MaxFrameSize - LANE_HEADERSIZE);
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
|
|
|
GenericULong = (pElan->MaxFrameSize - LANE_HEADERSIZE);
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
|
|
|
GenericULong = (pElan->MaxFrameSize - LANE_HEADERSIZE);
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
case OID_GEN_MAXIMUM_SEND_PACKETS:
|
|
|
|
GenericULong = 32; // XXX What is our limit? From adapter?
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
case OID_GEN_LINK_SPEED:
|
|
|
|
if (pAdapter != NULL_PATMLANE_ADAPTER)
|
|
{
|
|
GenericULong = pElan->pAdapter->LinkSpeed.Outbound;
|
|
}
|
|
else
|
|
{
|
|
GenericULong = ATM_USER_DATA_RATE_SONET_155;
|
|
}
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
case OID_GEN_TRANSMIT_BUFFER_SPACE:
|
|
case OID_GEN_RECEIVE_BUFFER_SPACE:
|
|
|
|
GenericULong = 32 * 1024; // XXX What should this really be?
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
case OID_GEN_VENDOR_ID:
|
|
|
|
NdisMoveMemory(
|
|
(PVOID)&GenericULong,
|
|
&pElan->MacAddressEth,
|
|
3
|
|
);
|
|
GenericULong &= 0xFFFFFF00;
|
|
MoveSource = (PVOID)(&GenericULong);
|
|
MoveBytes = sizeof(GenericULong);
|
|
break;
|
|
|
|
case OID_GEN_VENDOR_DESCRIPTION:
|
|
|
|
MoveSource = (PVOID)"Microsoft ATM LAN Emulation";
|
|
MoveBytes = 28;
|
|
|
|
break;
|
|
|
|
case OID_GEN_DRIVER_VERSION:
|
|
case OID_GEN_VENDOR_DRIVER_VERSION:
|
|
|
|
GenericUShort = ((USHORT)5 << 8) | 0;
|
|
MoveSource = (PVOID)(&GenericUShort);
|
|
MoveBytes = sizeof(GenericUShort);
|
|
|
|
DBGP((2, "Value %x\n", GenericUShort));
|
|
|
|
break;
|
|
|
|
case OID_802_3_PERMANENT_ADDRESS:
|
|
case OID_802_3_CURRENT_ADDRESS:
|
|
|
|
NdisMoveMemory((PCHAR)GenericArray,
|
|
&pElan->MacAddressEth,
|
|
sizeof(MAC_ADDRESS));
|
|
MoveSource = (PVOID)(GenericArray);
|
|
MoveBytes = sizeof(MAC_ADDRESS);
|
|
|
|
DBGP((1, "%d Address is %s\n", pElan->ElanNumber,
|
|
MacAddrToString(MoveSource)));
|
|
|
|
break;
|
|
|
|
case OID_802_5_PERMANENT_ADDRESS:
|
|
case OID_802_5_CURRENT_ADDRESS:
|
|
|
|
NdisMoveMemory((PCHAR)GenericArray,
|
|
&pElan->MacAddressTr,
|
|
sizeof(MAC_ADDRESS));
|
|
MoveSource = (PVOID)(GenericArray);
|
|
MoveBytes = sizeof(MAC_ADDRESS);
|
|
|
|
DBGP((1, "%d Address is %s\n", pElan->ElanNumber,
|
|
MacAddrToString(MoveSource)));
|
|
|
|
break;
|
|
|
|
case OID_802_3_MULTICAST_LIST:
|
|
|
|
MoveSource = (PVOID) &pElan->McastAddrs[0];
|
|
MoveBytes = pElan->McastAddrCount * sizeof(MAC_ADDRESS);
|
|
|
|
break;
|
|
|
|
case OID_802_3_MAXIMUM_LIST_SIZE:
|
|
|
|
GenericULong = MCAST_LIST_SIZE;
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
case OID_802_5_CURRENT_FUNCTIONAL:
|
|
case OID_802_5_CURRENT_GROUP:
|
|
|
|
NdisZeroMemory((PCHAR)GenericArray,
|
|
sizeof(MAC_ADDRESS));
|
|
MoveSource = (PVOID)(GenericArray);
|
|
MoveBytes = sizeof(MAC_ADDRESS);
|
|
|
|
DBGP((2, "Address is %s\n", MacAddrToString(MoveSource)));
|
|
|
|
break;
|
|
|
|
case OID_802_5_LAST_OPEN_STATUS:
|
|
case OID_802_5_CURRENT_RING_STATUS:
|
|
case OID_802_5_CURRENT_RING_STATE:
|
|
|
|
GenericULong = 0;
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
|
|
case OID_GEN_XMIT_OK:
|
|
|
|
GenericULong = (UINT)(pElan->FramesXmitGood);
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
case OID_GEN_RCV_OK:
|
|
|
|
GenericULong = (UINT)(pElan->FramesRecvGood);
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
case OID_GEN_XMIT_ERROR:
|
|
case OID_GEN_RCV_ERROR:
|
|
case OID_GEN_RCV_NO_BUFFER:
|
|
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
|
case OID_802_3_XMIT_ONE_COLLISION:
|
|
case OID_802_3_XMIT_MORE_COLLISIONS:
|
|
case OID_802_5_LINE_ERRORS:
|
|
case OID_802_5_LOST_FRAMES:
|
|
case OID_802_5_BURST_ERRORS:
|
|
case OID_802_5_FRAME_COPIED_ERRORS:
|
|
case OID_802_5_TOKEN_ERRORS:
|
|
|
|
GenericULong = 0;
|
|
|
|
DBGP((2, "Value %d\n", GenericULong));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_OID;
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
if (StatusToReturn == NDIS_STATUS_SUCCESS)
|
|
{
|
|
if (MoveBytes > BytesLeft)
|
|
{
|
|
//
|
|
// Not enough room in InformationBuffer. Punt
|
|
//
|
|
*BytesNeeded = MoveBytes;
|
|
|
|
*BytesWritten = 0;
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Store result.
|
|
//
|
|
NdisMoveMemory(InfoBuffer, MoveSource, MoveBytes);
|
|
|
|
*BytesWritten = MoveBytes;
|
|
}
|
|
}
|
|
|
|
DBGP((2, "Query Status %x\n", StatusToReturn));
|
|
|
|
TRACEOUT(MQueryInformation);
|
|
CHECK_EXIT_IRQL(EntryIrql);
|
|
return StatusToReturn;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
AtmLaneMSetInformation(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN NDIS_OID Oid,
|
|
IN PVOID InformationBuffer,
|
|
IN ULONG InformationBufferLength,
|
|
OUT PULONG BytesRead,
|
|
OUT PULONG BytesNeeded
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles a set operation for a single OID.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext - a pointer to the Elan.
|
|
|
|
Oid - the NDIS_OID to process.
|
|
|
|
InformationBuffer - Holds the data to be set.
|
|
|
|
InformationBufferLength - The length of InformationBuffer.
|
|
|
|
BytesRead - If the call is successful, returns the number
|
|
of bytes read from InformationBuffer.
|
|
|
|
BytesNeeded - If there is not enough data in InformationBuffer
|
|
to satisfy the OID, returns the amount of storage
|
|
needed.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
NDIS_STATUS_PENDING
|
|
NDIS_STATUS_INVALID_LENGTH
|
|
NDIS_STATUS_INVALID_OID
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
UINT BytesLeft = InformationBufferLength;
|
|
PUCHAR InfoBuffer = (PUCHAR)(InformationBuffer);
|
|
UINT OidLength;
|
|
ULONG LookAhead;
|
|
ULONG Filter;
|
|
PATMLANE_ELAN pElan;
|
|
BOOLEAN IsShuttingDown;
|
|
#if DEBUG_IRQL
|
|
KIRQL EntryIrql;
|
|
#endif
|
|
GET_ENTRY_IRQL(EntryIrql);
|
|
|
|
TRACEIN(MSetInformation);
|
|
|
|
pElan = (PATMLANE_ELAN)MiniportAdapterContext;
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
DBGP((1, "%d Set OID %x %s\n", pElan->ElanNumber, Oid, OidToString(Oid)));
|
|
|
|
ACQUIRE_ELAN_LOCK(pElan);
|
|
IsShuttingDown = (ELAN_STATE_OPERATIONAL != pElan->AdminState);
|
|
RELEASE_ELAN_LOCK(pElan);
|
|
|
|
if (IsShuttingDown)
|
|
{
|
|
DBGP((1, "%d ELAN shutting down. Trivially succeeding Set OID %x %s\n",
|
|
pElan->ElanNumber, Oid, OidToString(Oid)));
|
|
*BytesRead = 0;
|
|
*BytesNeeded = 0;
|
|
|
|
StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
return (StatusToReturn);
|
|
}
|
|
|
|
//
|
|
// Get Oid and Length of request
|
|
//
|
|
OidLength = BytesLeft;
|
|
|
|
switch (Oid)
|
|
{
|
|
|
|
case OID_802_3_MULTICAST_LIST:
|
|
|
|
if (OidLength % sizeof(MAC_ADDRESS))
|
|
{
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
*BytesRead = 0;
|
|
*BytesNeeded = 0;
|
|
break;
|
|
}
|
|
|
|
if (OidLength > (MCAST_LIST_SIZE * sizeof(MAC_ADDRESS)))
|
|
{
|
|
StatusToReturn = NDIS_STATUS_MULTICAST_FULL;
|
|
*BytesRead = 0;
|
|
*BytesNeeded = 0;
|
|
break;
|
|
}
|
|
|
|
NdisZeroMemory(
|
|
&pElan->McastAddrs[0],
|
|
MCAST_LIST_SIZE * sizeof(MAC_ADDRESS)
|
|
);
|
|
NdisMoveMemory(
|
|
&pElan->McastAddrs[0],
|
|
InfoBuffer,
|
|
OidLength
|
|
);
|
|
pElan->McastAddrCount = OidLength / sizeof(MAC_ADDRESS);
|
|
|
|
#if DBG
|
|
{
|
|
ULONG i;
|
|
|
|
for (i = 0; i < pElan->McastAddrCount; i++)
|
|
{
|
|
DBGP((2, "%s\n", MacAddrToString(&pElan->McastAddrs[i])));
|
|
}
|
|
}
|
|
#endif // DBG
|
|
|
|
break;
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
//
|
|
// Verify length
|
|
//
|
|
if (OidLength != sizeof(ULONG))
|
|
{
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
*BytesRead = 0;
|
|
*BytesNeeded = sizeof(ULONG);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Store the new value.
|
|
//
|
|
NdisMoveMemory(&Filter, InfoBuffer, sizeof(ULONG));
|
|
|
|
//
|
|
// Don't allow promisc mode, because we can't support that.
|
|
//
|
|
if (Filter & NDIS_PACKET_TYPE_PROMISCUOUS)
|
|
{
|
|
StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
ACQUIRE_ELAN_LOCK(pElan);
|
|
|
|
pElan->CurPacketFilter = Filter;
|
|
|
|
//
|
|
// Mark Miniport Running if not already
|
|
//
|
|
if ((pElan->Flags & ELAN_MINIPORT_OPERATIONAL) == 0)
|
|
{
|
|
pElan->Flags |= ELAN_MINIPORT_OPERATIONAL;
|
|
|
|
DBGP((1, "%d Miniport OPERATIONAL\n", pElan->ElanNumber));
|
|
}
|
|
|
|
RELEASE_ELAN_LOCK(pElan);
|
|
|
|
DBGP((2, "CurPacketFilter now %x\n", Filter));
|
|
|
|
break;
|
|
|
|
case OID_802_5_CURRENT_FUNCTIONAL:
|
|
case OID_802_5_CURRENT_GROUP:
|
|
|
|
// XXX just accept whatever for now ???
|
|
|
|
break;
|
|
|
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
|
|
//
|
|
// Verify length
|
|
//
|
|
if (OidLength != 4)
|
|
{
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
*BytesRead = 0;
|
|
*BytesNeeded = 0;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Store the new value.
|
|
//
|
|
NdisMoveMemory(&LookAhead, InfoBuffer, 4);
|
|
|
|
if ((pElan->pAdapter == NULL_PATMLANE_ADAPTER) ||
|
|
(LookAhead <= pElan->pAdapter->MaxAAL5PacketSize))
|
|
{
|
|
pElan->CurLookAhead = LookAhead;
|
|
DBGP((2, "CurLookAhead now %d\n", LookAhead));
|
|
}
|
|
else
|
|
{
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
}
|
|
|
|
break;
|
|
|
|
case OID_GEN_NETWORK_LAYER_ADDRESSES:
|
|
StatusToReturn = AtmLaneMSetNetworkAddresses(
|
|
pElan,
|
|
InformationBuffer,
|
|
InformationBufferLength,
|
|
BytesRead,
|
|
BytesNeeded);
|
|
break;
|
|
|
|
default:
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_OID;
|
|
|
|
*BytesRead = 0;
|
|
*BytesNeeded = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (StatusToReturn == NDIS_STATUS_SUCCESS)
|
|
{
|
|
*BytesRead = BytesLeft;
|
|
*BytesNeeded = 0;
|
|
}
|
|
|
|
DBGP((2, "Set Status %x\n", StatusToReturn));
|
|
|
|
TRACEOUT(MSetInformation);
|
|
CHECK_EXIT_IRQL(EntryIrql);
|
|
return StatusToReturn;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmLaneMReset(
|
|
OUT PBOOLEAN AddressingReset,
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
{
|
|
TRACEIN(MReset);
|
|
|
|
TRACEOUT(MReset);
|
|
return NDIS_STATUS_NOT_RESETTABLE;
|
|
}
|
|
|
|
VOID
|
|
AtmLaneMHalt(
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
{
|
|
PATMLANE_ELAN pElan;
|
|
ULONG rc;
|
|
#if DEBUG_IRQL
|
|
KIRQL EntryIrql;
|
|
#endif
|
|
GET_ENTRY_IRQL(EntryIrql);
|
|
TRACEIN(MHalt);
|
|
|
|
pElan = (PATMLANE_ELAN)MiniportAdapterContext;
|
|
STRUCT_ASSERT(pElan, atmlane_elan);
|
|
|
|
ACQUIRE_ELAN_LOCK(pElan);
|
|
|
|
DBGP((1, "%d MHalt pElan %x, ref count %d, Admin state %d, State %d\n",
|
|
pElan->ElanNumber, pElan, pElan->RefCount, pElan->AdminState, pElan->State));
|
|
|
|
pElan->MiniportAdapterHandle = NULL;
|
|
|
|
rc = AtmLaneDereferenceElan(pElan, "miniport"); // Miniport handle is gone.
|
|
|
|
if (rc != 0)
|
|
{
|
|
AtmLaneShutdownElan(pElan, FALSE);
|
|
// lock released in above
|
|
}
|
|
//
|
|
// else the Elan is gone.
|
|
//
|
|
|
|
TRACEOUT(MHalt);
|
|
CHECK_EXIT_IRQL(EntryIrql);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
PNDIS_PACKET
|
|
AtmLaneWrapSendPacket(
|
|
IN PATMLANE_ELAN pElan,
|
|
IN PNDIS_PACKET pSendNdisPacket,
|
|
OUT ULONG * pAddressType,
|
|
OUT PMAC_ADDRESS pDestAddress,
|
|
OUT BOOLEAN * pSendViaBUS
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function repackages a protocol sent NDIS packet.
|
|
It puts on a new NDIS packet header and a buffer for
|
|
the LANE header. It saves away the original packet
|
|
header in the ProtocolReserved area of the new packet header.
|
|
Additionally, it determines if packet is to be sent via
|
|
the BUS and the destination address of the packet.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE elan structure
|
|
|
|
pSendNdisPacket - Pointer to NDIS packet
|
|
|
|
pAddressType - Pointer to ULONG that gets one of
|
|
(LANE_MACADDRTYPE_MACADDR,
|
|
LANE_MACADDRTYPE_ROUTEDESCR).
|
|
|
|
pDestAddress - Pointer to 6-byte buffer that gets
|
|
destination address.
|
|
|
|
pSendViaBus - Pointer to boolean
|
|
|
|
Return Value:
|
|
|
|
New NDIS packet header or NULL if out of resources.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PACKET pNewNdisPacket;
|
|
PNDIS_BUFFER pTempNdisBuffer;
|
|
PUCHAR pHeaderBuffer;
|
|
PUCHAR pNewHeaderBuffer;
|
|
PUCHAR pNewPadBuffer;
|
|
ULONG BufferLength;
|
|
ULONG TotalLength;
|
|
PNDIS_BUFFER pHeaderNdisBuffer;
|
|
PNDIS_BUFFER pPadNdisBuffer;
|
|
NDIS_STATUS Status;
|
|
PSEND_PACKET_RESERVED pNewPacketContext;
|
|
ULONG OrigBufferCount;
|
|
ULONG WrappedBufferCount;
|
|
ULONG RILength;
|
|
BOOLEAN DirectionBit;
|
|
PUCHAR pCurRouteDescr;
|
|
PUCHAR pNextRouteDescr;
|
|
|
|
TRACEIN(WrapSendPacket);
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
pNewNdisPacket = (PNDIS_PACKET)NULL;
|
|
pHeaderNdisBuffer = (PNDIS_BUFFER)NULL;
|
|
pPadNdisBuffer = (PNDIS_BUFFER)NULL;
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
OrigBufferCount = 0;
|
|
WrappedBufferCount = 0;
|
|
|
|
do
|
|
{
|
|
//
|
|
// Get first buffer and total length of packet
|
|
//
|
|
NdisGetFirstBufferFromPacket(
|
|
pSendNdisPacket,
|
|
&pTempNdisBuffer,
|
|
&pHeaderBuffer,
|
|
&BufferLength,
|
|
&TotalLength);
|
|
|
|
DBGP((3, "WrapSendPacket: SendPkt %x Length %d\n",
|
|
pSendNdisPacket, TotalLength));
|
|
|
|
ASSERT(pTempNdisBuffer != NULL);
|
|
|
|
//
|
|
// Allocate a new transmit packet descriptor
|
|
//
|
|
NdisAllocatePacket(&Status, &pNewNdisPacket, pElan->TransmitPacketPool);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGP((0, "WrapSendPacket: Alloc xmit NDIS Packet failed\n"));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
#if PKT_HDR_COUNTS
|
|
InterlockedDecrement(&pElan->XmitPktCount);
|
|
if ((pElan->XmitPktCount % 20) == 0)
|
|
{
|
|
DBGP((1, "XmitPktCount %d\n", pElan->XmitPktCount));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Allocate a Header Buffer
|
|
//
|
|
pHeaderNdisBuffer = AtmLaneAllocateHeader(pElan, &pNewHeaderBuffer);
|
|
if (pHeaderNdisBuffer == (PNDIS_BUFFER)NULL)
|
|
{
|
|
DBGP((0, "WrapSendPacket: Alloc Header Buffer failed\n"));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Spec says we can put zero or our LECID in the header.
|
|
// We'll put our LECID in the header for echo-filtering purposes.
|
|
//
|
|
ASSERT(pElan->HeaderBufSize == LANE_HEADERSIZE);
|
|
*((PUSHORT)pNewHeaderBuffer) = pElan->LecId;
|
|
|
|
|
|
//
|
|
// Allocate a pad buffer now, if necessary, before we get all tied
|
|
// up in knots.
|
|
//
|
|
if ((TotalLength + LANE_HEADERSIZE) < pElan->MinFrameSize)
|
|
{
|
|
pPadNdisBuffer = AtmLaneAllocatePadBuf(pElan, &pNewPadBuffer);
|
|
if (pPadNdisBuffer == (PNDIS_BUFFER)NULL)
|
|
{
|
|
DBGP((0, "WrapSendPacket: Alloc Pad Buffer failed\n"));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Put new header buffer at head of new NDIS Packet
|
|
//
|
|
NdisChainBufferAtFront(pNewNdisPacket, pHeaderNdisBuffer);
|
|
WrappedBufferCount++;
|
|
|
|
//
|
|
// Chain buffers from send packet onto tail of new NDIS Packet
|
|
//
|
|
do
|
|
{
|
|
NdisUnchainBufferAtFront(pSendNdisPacket, &pTempNdisBuffer);
|
|
|
|
if (pTempNdisBuffer == (PNDIS_BUFFER)NULL)
|
|
break;
|
|
ASSERT(pTempNdisBuffer->Next == NULL);
|
|
OrigBufferCount++;
|
|
NdisChainBufferAtBack(pNewNdisPacket, pTempNdisBuffer);
|
|
WrappedBufferCount++;
|
|
}
|
|
while (TRUE);
|
|
|
|
//
|
|
// Chain pad buffer on tail if needed (it would be allocated already)
|
|
//
|
|
if (pPadNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
NdisChainBufferAtBack(pNewNdisPacket, pPadNdisBuffer);
|
|
WrappedBufferCount++;
|
|
|
|
//
|
|
// Set size of pad buffer to minimum necessary
|
|
//
|
|
NdisAdjustBufferLength(pPadNdisBuffer,
|
|
pElan->MinFrameSize - TotalLength - LANE_HEADERSIZE);
|
|
}
|
|
|
|
//
|
|
// Save away pointer to original NDIS Packet header in reserved
|
|
// area of our new NDIS Packet header.
|
|
//
|
|
// NOTE use of ProtocolReserved in this case!
|
|
//
|
|
// Also set Owner and Multicast flags appropriately.
|
|
//
|
|
pNewPacketContext =
|
|
(PSEND_PACKET_RESERVED)&pNewNdisPacket->ProtocolReserved;
|
|
NdisZeroMemory(pNewPacketContext, sizeof(SEND_PACKET_RESERVED));
|
|
#if PROTECT_PACKETS
|
|
INIT_SENDPACKET_LOCK(pNewNdisPacket);
|
|
#endif // PROTECT_PACKETS
|
|
#if DBG
|
|
pNewPacketContext->Signature = 'ENAL';
|
|
#endif
|
|
pNewPacketContext->pOrigNdisPacket = pSendNdisPacket;
|
|
pNewPacketContext->OrigBufferCount = OrigBufferCount;
|
|
pNewPacketContext->OrigPacketLength = TotalLength;
|
|
pNewPacketContext->WrappedBufferCount = WrappedBufferCount;
|
|
SET_FLAG(
|
|
pNewPacketContext->Flags,
|
|
PACKET_RESERVED_OWNER_MASK,
|
|
PACKET_RESERVED_OWNER_PROTOCOL
|
|
);
|
|
ASSERT(pNewPacketContext->Flags == PACKET_RESERVED_OWNER_PROTOCOL);
|
|
|
|
//
|
|
// Branch on Ethernet v.s. Token Ring to sniff pkt contents
|
|
//
|
|
if (pElan->LanType == LANE_LANTYPE_ETH)
|
|
{
|
|
|
|
// Send packet via BUS if it has a multicast
|
|
// Destination Address. If low-order bit in
|
|
// first byte of the Destination Address is set then
|
|
// it's a multicast or broadcast address.
|
|
// Destination Address is first in packet header and it's
|
|
// always a MAC address.
|
|
//
|
|
*pSendViaBUS = ((*pHeaderBuffer) & 1) != 0;
|
|
*pAddressType = LANE_MACADDRTYPE_MACADDR;
|
|
NdisMoveMemory(pDestAddress, pHeaderBuffer, 6);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(pElan->LanType == LANE_LANTYPE_TR);
|
|
|
|
//
|
|
// now the very complicated sorting of TR packets
|
|
//
|
|
do
|
|
{
|
|
//
|
|
// Section 8.5.3 of LANE Specification.
|
|
// Multicast frames go to the BUS.
|
|
//
|
|
if ((*(pHeaderBuffer+2) & 0x80) != 0) // DA multicast bit present?
|
|
{
|
|
*pSendViaBUS = TRUE;
|
|
*pAddressType = LANE_MACADDRTYPE_MACADDR;
|
|
NdisMoveMemory(pDestAddress, pHeaderBuffer+2, 6);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Section 8.5.2 of LANE Specification.
|
|
// NSR frames go to destination address.
|
|
//
|
|
if ( (*(pHeaderBuffer+8) & 0x80) == 0) // SA RI bit not present?
|
|
{
|
|
*pSendViaBUS = FALSE;
|
|
*pAddressType = LANE_MACADDRTYPE_MACADDR;
|
|
NdisMoveMemory(pDestAddress, pHeaderBuffer+2, 6);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Section 8.5.4 of LANE Specification.
|
|
// ARE or STE frames go to the BUS.
|
|
//
|
|
if ( ((*(pHeaderBuffer+8) & 0x80) != 0) && // SA RI bit present and
|
|
((*(pHeaderBuffer+14) & 0xe0) !=0) ) // RI type field upper bits on?
|
|
{
|
|
*pSendViaBUS = TRUE;
|
|
*pAddressType = LANE_MACADDRTYPE_MACADDR;
|
|
NdisMoveMemory(pDestAddress, pHeaderBuffer+2, 6);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Frame is source routed so extract Routing Information (RI) length.
|
|
//
|
|
RILength = *(pHeaderBuffer+14) & 0x1f;
|
|
|
|
//
|
|
// Section 8.5.7 of LANE Specification.
|
|
// SR frame with a RI length less than 6 contains no hops.
|
|
// Send to destination address.
|
|
//
|
|
if (RILength < 6)
|
|
{
|
|
*pSendViaBUS = FALSE;
|
|
*pAddressType = LANE_MACADDRTYPE_MACADDR;
|
|
NdisMoveMemory(pDestAddress, pHeaderBuffer+2, 6);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Section 8.5.6 of LANE Specification.
|
|
// Odd RILength is invalid, we choose to send via BUS.
|
|
//
|
|
if ((RILength & 1) != 0)
|
|
{
|
|
*pSendViaBUS = FALSE;
|
|
*pAddressType = LANE_MACADDRTYPE_MACADDR;
|
|
NdisMoveMemory(pDestAddress, pHeaderBuffer+2, 6);
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Section 8.5.5 of LANE Specification.
|
|
// At this point we have a SR frame with RI Length >= 6;
|
|
// We are never a bridge so frame should go to "next RD".
|
|
//
|
|
*pSendViaBUS = FALSE;
|
|
*pAddressType = LANE_MACADDRTYPE_ROUTEDESCR;
|
|
NdisZeroMemory(pDestAddress, 4);
|
|
|
|
DirectionBit = (*(pHeaderBuffer+15) & 0x80) != 0;
|
|
|
|
if (DirectionBit)
|
|
{
|
|
//
|
|
// Frame is traversing LAN in reverse order of RDs.
|
|
// "next RD" is the next-to-last RD in the packet.
|
|
// Use Segment ID and Bridge Num from this RD.
|
|
//
|
|
pNextRouteDescr = pHeaderBuffer+14+RILength-4;
|
|
pDestAddress->Byte[4] = pNextRouteDescr[0];
|
|
pDestAddress->Byte[5] = pNextRouteDescr[1];
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Frame is traversing LAN in the order of the RDs.
|
|
// "next RD" straddles the first and second RD in the packet.
|
|
// Use Segment ID from second RD and Bridge Num from first RD.
|
|
//
|
|
pCurRouteDescr = pHeaderBuffer+14+2; // first RD
|
|
pNextRouteDescr = pHeaderBuffer+14+4; // second RD
|
|
pDestAddress->Byte[4] = pNextRouteDescr[0];
|
|
pDestAddress->Byte[5] = (pNextRouteDescr[1] & 0xf0) | (pCurRouteDescr[1] & 0x0f);
|
|
}
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
}
|
|
|
|
NdisQueryPacket(pNewNdisPacket, NULL, NULL, NULL, &TotalLength);
|
|
DBGP((3, "WrapSendPacket: SendPkt %x NewPkt %x Bufs %d Length %d\n",
|
|
pSendNdisPacket, pNewNdisPacket, WrappedBufferCount, TotalLength));
|
|
|
|
TRACELOGWRITE((&TraceLog,
|
|
TL_WRAPSEND,
|
|
pSendNdisPacket,
|
|
pNewNdisPacket,
|
|
WrappedBufferCount,
|
|
TotalLength));
|
|
TRACELOGWRITEPKT((&TraceLog, pNewNdisPacket));
|
|
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
if (pNewNdisPacket != (PNDIS_PACKET)NULL)
|
|
{
|
|
#if PROTECT_PACKETS
|
|
FREE_SENDPACKET_LOCK(pNewNdisPacket);
|
|
#endif // PROTECT_PACKETS
|
|
NdisFreePacket(pNewNdisPacket);
|
|
pNewNdisPacket = (PNDIS_PACKET)NULL;
|
|
#if PKT_HDR_COUNTS
|
|
InterlockedIncrement(&pElan->XmitPktCount);
|
|
if ((pElan->XmitPktCount % 20) == 0 &&
|
|
pElan->XmitPktCount != pElan->MaxHeaderBufs)
|
|
{
|
|
DBGP((1, "XmitPktCount %d\n", pElan->XmitPktCount));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (pHeaderNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
AtmLaneFreeHeader(pElan, pHeaderNdisBuffer, FALSE);
|
|
pHeaderNdisBuffer = (PNDIS_BUFFER)NULL;
|
|
}
|
|
|
|
if (pPadNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
AtmLaneFreePadBuf(pElan, pPadNdisBuffer, FALSE);
|
|
pPadNdisBuffer = (PNDIS_BUFFER)NULL;
|
|
}
|
|
|
|
}
|
|
|
|
TRACEOUT(WrapSendPacket);
|
|
|
|
return pNewNdisPacket;
|
|
}
|
|
|
|
|
|
PNDIS_PACKET
|
|
AtmLaneUnwrapSendPacket(
|
|
IN PATMLANE_ELAN pElan,
|
|
IN PNDIS_PACKET pNdisPacket LOCKIN NOLOCKOUT
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function basically undoes what AtmLaneWrapSendPacket
|
|
does. It removes the new NDIS packet header and the LANE
|
|
header and frees them. It restores the original packet header.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE elan structure
|
|
|
|
pNdisPacket - Pointer to NDIS packet
|
|
|
|
Return Value:
|
|
|
|
Original NDIS packet header.
|
|
|
|
--*/
|
|
{
|
|
PSEND_PACKET_RESERVED pPacketContext;
|
|
UINT TotalLength;
|
|
PNDIS_PACKET pOrigNdisPacket;
|
|
PNDIS_BUFFER pTempNdisBuffer;
|
|
ULONG OrigPacketLength;
|
|
ULONG OrigBufferCount;
|
|
ULONG WrappedBufferCount;
|
|
ULONG BufferCount;
|
|
BOOLEAN First;
|
|
|
|
TRACEIN(UnwrapSendPacket);
|
|
|
|
//
|
|
// Get original packet header from reserved area.
|
|
//
|
|
pPacketContext = PSEND_RSVD(pNdisPacket);
|
|
pOrigNdisPacket = pPacketContext->pOrigNdisPacket;
|
|
OrigBufferCount = pPacketContext->OrigBufferCount;
|
|
OrigPacketLength = pPacketContext->OrigPacketLength;
|
|
WrappedBufferCount = pPacketContext->WrappedBufferCount;
|
|
|
|
ASSERT(pPacketContext->Signature == 'ENAL');
|
|
ASSERT((pPacketContext->Flags & PACKET_RESERVED_OWNER_PROTOCOL) != 0);
|
|
ASSERT(pPacketContext->pOrigNdisPacket != NULL);
|
|
|
|
//
|
|
// Unchain first buffer (ours) and free it.
|
|
//
|
|
|
|
pTempNdisBuffer = (PNDIS_BUFFER)NULL;
|
|
NdisUnchainBufferAtFront(pNdisPacket, &pTempNdisBuffer);
|
|
ASSERT(pTempNdisBuffer != (PNDIS_BUFFER)NULL);
|
|
AtmLaneFreeHeader(pElan, pTempNdisBuffer, FALSE);
|
|
|
|
//
|
|
// If padded, unchain last buffer (ours) and free it.
|
|
//
|
|
if ((WrappedBufferCount - OrigBufferCount) > 1)
|
|
{
|
|
pTempNdisBuffer = (PNDIS_BUFFER)NULL;
|
|
NdisUnchainBufferAtBack(pNdisPacket, &pTempNdisBuffer);
|
|
ASSERT(pTempNdisBuffer != (PNDIS_BUFFER)NULL);
|
|
AtmLaneFreePadBuf(pElan, pTempNdisBuffer, FALSE);
|
|
}
|
|
|
|
//
|
|
// Put rest of buffers back on original packet header.
|
|
//
|
|
First = TRUE;
|
|
BufferCount = 0;
|
|
do
|
|
{
|
|
NdisUnchainBufferAtFront(pNdisPacket, &pTempNdisBuffer);
|
|
ASSERT(!((pTempNdisBuffer == NULL) && First));
|
|
First = FALSE;
|
|
if (pTempNdisBuffer == (PNDIS_BUFFER)NULL)
|
|
break;
|
|
NdisChainBufferAtBack(pOrigNdisPacket, pTempNdisBuffer);
|
|
BufferCount++;
|
|
}
|
|
while (TRUE);
|
|
|
|
NdisQueryPacket(pOrigNdisPacket, NULL, NULL, NULL, &TotalLength);
|
|
DBGP((3, "UnwrapSendPacket: SendPkt %x Bufcnt %d Length %d\n",
|
|
pOrigNdisPacket, BufferCount, TotalLength));
|
|
|
|
TRACELOGWRITE((&TraceLog,
|
|
TL_UNWRAPSEND,
|
|
pNdisPacket,
|
|
pOrigNdisPacket,
|
|
BufferCount,
|
|
TotalLength));
|
|
TRACELOGWRITEPKT((&TraceLog, pOrigNdisPacket));
|
|
|
|
ASSERT(OrigBufferCount == BufferCount);
|
|
// ASSERT(OrigPacketLength == TotalLength);
|
|
|
|
//
|
|
// Free the packet header
|
|
//
|
|
#if PROTECT_PACKETS
|
|
RELEASE_SENDPACKET_LOCK(pNdisPacket);
|
|
FREE_SENDPACKET_LOCK(pNdisPacket);
|
|
#endif // PROTECT_PACKETS
|
|
NdisFreePacket(pNdisPacket);
|
|
#if PKT_HDR_COUNTS
|
|
InterlockedIncrement(&pElan->XmitPktCount);
|
|
if ((pElan->XmitPktCount % 20) == 0 &&
|
|
pElan->XmitPktCount != pElan->MaxHeaderBufs)
|
|
{
|
|
DBGP((1, "XmitPktCount %d\n", pElan->XmitPktCount));
|
|
}
|
|
#endif
|
|
|
|
TRACEOUT(UnwrapSendPacket);
|
|
|
|
return pOrigNdisPacket;
|
|
}
|
|
|
|
PNDIS_PACKET
|
|
AtmLaneWrapRecvPacket(
|
|
IN PATMLANE_ELAN pElan,
|
|
IN PNDIS_PACKET pRecvNdisPacket,
|
|
OUT ULONG * pMacHdrSize,
|
|
OUT ULONG * pDestAddrType,
|
|
OUT PMAC_ADDRESS pDestAddr,
|
|
OUT BOOLEAN * pDestIsMulticast
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function repackages an adapter received NDIS packet.
|
|
It puts on a new packet header and creates a new buffer
|
|
descriptor for the first fragment that skips the 2-byte
|
|
LANE header. It then saves away the original packet
|
|
header with the original first buffer descriptor in the
|
|
MiniportReserved area of the new packet header.
|
|
Additionally, it outputs the destination address, the
|
|
destination's address type if the packet is a destination
|
|
address is a multicast address.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE elan structure
|
|
|
|
pRecvNdisPacket - Pointer to NDIS packet
|
|
|
|
pMacHdrSize - Pointer to ULONG that get the length
|
|
of the MAC header.
|
|
|
|
pDestAddrType - Pointer to ULONG that gets one of
|
|
(LANE_MACADDRTYPE_MACADDR,
|
|
LANE_MACADDRTYPE_ROUTEDESCR).
|
|
|
|
pDestAddr - Pointer to 6-byte buffer that gets
|
|
destination address.
|
|
|
|
pDestIsMulticast - Pointer to boolean that gets TRUE if
|
|
destination address is a multicast.
|
|
|
|
Return Value:
|
|
|
|
New NDIS packet header or NULL if out of resources.
|
|
|
|
--*/
|
|
{
|
|
ULONG TotalLength;
|
|
ULONG TempLength;
|
|
PUCHAR pHeaderBuffer;
|
|
PUCHAR pBuffer;
|
|
PNDIS_PACKET pNewNdisPacket;
|
|
PNDIS_BUFFER pFirstNdisBuffer;
|
|
PNDIS_BUFFER pTempNdisBuffer;
|
|
PNDIS_BUFFER pNewNdisBuffer;
|
|
PUCHAR pTempBuffer;
|
|
PRECV_PACKET_RESERVED pNewPacketContext;
|
|
NDIS_STATUS Status;
|
|
ULONG BufferCount;
|
|
|
|
TRACEIN(WrapRecvPacket);
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
pNewNdisPacket = (PNDIS_PACKET)NULL;
|
|
pNewNdisBuffer = (PNDIS_BUFFER)NULL;
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
BufferCount = 0;
|
|
|
|
do
|
|
{
|
|
//
|
|
// Get first buffer and total length of packet
|
|
//
|
|
NdisGetFirstBufferFromPacket(
|
|
pRecvNdisPacket,
|
|
&pTempNdisBuffer,
|
|
&pHeaderBuffer,
|
|
&TempLength,
|
|
&TotalLength);
|
|
|
|
DBGP((3, "WrapRecvPacket: RecvPkt %x Length %d\n",
|
|
pRecvNdisPacket, TotalLength));
|
|
//
|
|
// Allocate a new recv packet descriptor
|
|
//
|
|
NdisAllocatePacket(&Status, &pNewNdisPacket, pElan->ReceivePacketPool);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGP((0, "WrapRecvPacket: Alloc recv NDIS Packet failed\n"));
|
|
break;
|
|
}
|
|
|
|
#if PKT_HDR_COUNTS
|
|
InterlockedDecrement(&pElan->RecvPktCount);
|
|
if ((pElan->RecvPktCount % 20) == 0)
|
|
{
|
|
DBGP((1, "RecvPktCount %d\n", pElan->RecvPktCount));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Unchain first buffer
|
|
//
|
|
NdisUnchainBufferAtFront(pRecvNdisPacket, &pFirstNdisBuffer);
|
|
ASSERT(pFirstNdisBuffer != (PNDIS_BUFFER)NULL);
|
|
NdisQueryBuffer(pFirstNdisBuffer, &pTempBuffer, &TempLength);
|
|
ASSERT(TempLength > 2);
|
|
|
|
//
|
|
// "Copy" it to another buffer header skipping the first 2 bytes
|
|
//
|
|
NdisCopyBuffer(
|
|
&Status,
|
|
&pNewNdisBuffer,
|
|
pElan->ReceiveBufferPool,
|
|
pFirstNdisBuffer,
|
|
2,
|
|
(TempLength - 2)
|
|
);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGP((0, "DataPacketHandler: NdisCopyBuffer failed (%x)\n",
|
|
Status));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Chain new buffer onto new packet header.
|
|
//
|
|
NdisChainBufferAtFront(pNewNdisPacket, pNewNdisBuffer);
|
|
BufferCount++;
|
|
|
|
//
|
|
// Chain rest of buffers onto tail of new NDIS Packet
|
|
//
|
|
do
|
|
{
|
|
NdisUnchainBufferAtFront(pRecvNdisPacket, &pTempNdisBuffer);
|
|
|
|
if (pTempNdisBuffer == (PNDIS_BUFFER)NULL)
|
|
break;
|
|
ASSERT(pTempNdisBuffer->Next == NULL);
|
|
NdisChainBufferAtBack(pNewNdisPacket, pTempNdisBuffer);
|
|
BufferCount++;
|
|
}
|
|
while (TRUE);
|
|
|
|
//
|
|
// Chain original first buffer back on original packet
|
|
//
|
|
NdisChainBufferAtFront(pRecvNdisPacket, pFirstNdisBuffer);
|
|
|
|
//
|
|
// Save away pointer to original NDIS Packet header in reserved
|
|
// area of our new NDIS Packet header.
|
|
//
|
|
// NOTE use of MiniportReserved in this case!
|
|
//
|
|
// Also set Owner flag appropriately.
|
|
pNewPacketContext =
|
|
(PRECV_PACKET_RESERVED)&pNewNdisPacket->MiniportReserved;
|
|
NdisZeroMemory(pNewPacketContext, sizeof(*pNewPacketContext));
|
|
pNewPacketContext->pNdisPacket = pRecvNdisPacket;
|
|
SET_FLAG(
|
|
pNewPacketContext->Flags,
|
|
PACKET_RESERVED_OWNER_MASK,
|
|
PACKET_RESERVED_OWNER_MINIPORT
|
|
);
|
|
|
|
//
|
|
// Increment the frame header pointer past the
|
|
// LANE header (+2 bytes)
|
|
//
|
|
pHeaderBuffer += 2;
|
|
|
|
//
|
|
// Output the MAC header length.
|
|
// Output the address type.
|
|
// Output the destination address.
|
|
// Determine if packet is a multicast.
|
|
//
|
|
if (pElan->LanType == LANE_LANTYPE_ETH)
|
|
{
|
|
//
|
|
// Ethernet/802.3 is simple.
|
|
//
|
|
// Header size is always 14.
|
|
// Type is always a MAC address.
|
|
// Dest Addr is first 6 bytes of header.
|
|
// DestAddress is Multicast if low-order bit in
|
|
// first byte of the Destination Address is set.
|
|
//
|
|
*pMacHdrSize = 14;
|
|
*pDestAddrType = LANE_MACADDRTYPE_MACADDR;
|
|
NdisMoveMemory(pDestAddr, pHeaderBuffer, 6);
|
|
*pDestIsMulticast = (((*pHeaderBuffer) & 1) != 0);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Token Ring/802.5 is a slightly less simple (understatement!).
|
|
//
|
|
|
|
do
|
|
{
|
|
//
|
|
// Calculate MAC header size.
|
|
//
|
|
*pMacHdrSize = 14; // start with minimum
|
|
if (pHeaderBuffer[8] & 0x80) // if SR info present
|
|
{
|
|
*pMacHdrSize += (pHeaderBuffer[14] & 0x1F);// add on SR info length
|
|
}
|
|
|
|
//
|
|
// Is it a true Multicast?
|
|
//
|
|
if ((*(pHeaderBuffer+2) & 0x80) != 0) // DA multicast bit present?
|
|
{
|
|
*pDestIsMulticast = TRUE;
|
|
*pDestAddrType = LANE_MACADDRTYPE_MACADDR;
|
|
NdisMoveMemory(pDestAddr, pHeaderBuffer+2, 6);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Is it an All Routes Explorer (ARE) or Spanning Tree Explorer (STE)?
|
|
// If so treat it as a multicast.
|
|
//
|
|
if ( ((*(pHeaderBuffer+8) & 0x80) != 0) && // SA RI bit present and
|
|
((*(pHeaderBuffer+14) & 0xe0) !=0) ) // RI type field upper bits on?
|
|
{
|
|
*pDestIsMulticast = TRUE;
|
|
*pDestAddrType = LANE_MACADDRTYPE_MACADDR;
|
|
NdisMoveMemory(pDestAddr, pHeaderBuffer+2, 6);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Otherwise it is unicast, Source Routed or not.
|
|
//
|
|
*pDestIsMulticast = FALSE;
|
|
*pDestAddrType = LANE_MACADDRTYPE_MACADDR;
|
|
NdisMoveMemory(pDestAddr, pHeaderBuffer+2, 6);
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
} // if (pElan->LanType == LANE_LANTYPE_ETH)
|
|
|
|
|
|
NdisQueryPacket(pNewNdisPacket, NULL, NULL, NULL, &TotalLength);
|
|
DBGP((3, "WrapRecvPacket: RecvPkt %x NewPkt %x Length %d\n",
|
|
pRecvNdisPacket, pNewNdisPacket, TempLength));
|
|
|
|
TRACELOGWRITE((&TraceLog,
|
|
TL_WRAPRECV,
|
|
pRecvNdisPacket,
|
|
pNewNdisPacket,
|
|
BufferCount,
|
|
TotalLength));
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
if (pNewNdisPacket != (PNDIS_PACKET)NULL)
|
|
{
|
|
NdisFreePacket(pNewNdisPacket);
|
|
#if PKT_HDR_COUNTS
|
|
InterlockedIncrement(&pElan->RecvPktCount);
|
|
if ((pElan->RecvPktCount % 20) == 0 &&
|
|
pElan->RecvPktCount != pElan->MaxHeaderBufs)
|
|
{
|
|
DBGP((1, "RecvPktCount %d\n", pElan->RecvPktCount));
|
|
}
|
|
#endif
|
|
pNewNdisPacket = NULL;
|
|
}
|
|
|
|
if (pNewNdisBuffer != (PNDIS_BUFFER)NULL)
|
|
{
|
|
AtmLaneFreeProtoBuffer(pElan, pNewNdisBuffer);
|
|
}
|
|
}
|
|
|
|
TRACEOUT(WrapRecvPacket);
|
|
|
|
return pNewNdisPacket;
|
|
}
|
|
|
|
|
|
PNDIS_PACKET
|
|
AtmLaneUnwrapRecvPacket(
|
|
IN PATMLANE_ELAN pElan,
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function basically undoes what AtmLaneWrapRecvPacket
|
|
does. It removes the new NDIS packet header and the
|
|
2-byte offset buffer descriptor. It restores the original
|
|
packet header and first buffer descriptor.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to ATMLANE elan structure
|
|
|
|
pNdisPacket - Pointer to NDIS packet
|
|
|
|
Return Value:
|
|
|
|
Original NDIS packet header.
|
|
|
|
--*/
|
|
{
|
|
PRECV_PACKET_RESERVED pPacketContext;
|
|
PNDIS_PACKET pOrigNdisPacket;
|
|
PNDIS_BUFFER pTempNdisBuffer;
|
|
ULONG BufferCount;
|
|
ULONG TotalLength;
|
|
|
|
TRACEIN(UnwrapRecvPacket);
|
|
|
|
//
|
|
// Get original packet from MiniportReserved.
|
|
// Should have original first buffer on it still.
|
|
//
|
|
pPacketContext = (PRECV_PACKET_RESERVED)&pNdisPacket->MiniportReserved;
|
|
pOrigNdisPacket = pPacketContext->pNdisPacket;
|
|
ASSERT(pOrigNdisPacket != (PNDIS_PACKET)NULL);
|
|
ASSERT(pOrigNdisPacket->Private.Head != (PNDIS_BUFFER)NULL);
|
|
BufferCount = 1;
|
|
|
|
//
|
|
// Unchain first buffer (ours) and free it.
|
|
//
|
|
NdisUnchainBufferAtFront(pNdisPacket, &pTempNdisBuffer);
|
|
NdisFreeBuffer(pTempNdisBuffer);
|
|
|
|
//
|
|
// Put rest of buffers back on original packet header.
|
|
//
|
|
do
|
|
{
|
|
NdisUnchainBufferAtFront(pNdisPacket, &pTempNdisBuffer);
|
|
if (pTempNdisBuffer == (PNDIS_BUFFER)NULL)
|
|
break;
|
|
ASSERT(pTempNdisBuffer->Next == NULL);
|
|
NdisChainBufferAtBack(pOrigNdisPacket, pTempNdisBuffer);
|
|
BufferCount++;
|
|
}
|
|
while (TRUE);
|
|
|
|
NdisQueryPacket(pOrigNdisPacket, NULL, NULL, NULL, &TotalLength);
|
|
DBGP((3, "UnwrapRecvPacket: Pkt %x Length %d\n", pOrigNdisPacket, TotalLength));
|
|
|
|
TRACELOGWRITE((&TraceLog,
|
|
TL_UNWRAPRECV,
|
|
pNdisPacket,
|
|
pOrigNdisPacket,
|
|
BufferCount,
|
|
TotalLength));
|
|
|
|
//
|
|
// Free the recv packet descriptor.
|
|
//
|
|
NdisFreePacket(pNdisPacket);
|
|
|
|
#if PKT_HDR_COUNTS
|
|
InterlockedIncrement(&pElan->RecvPktCount);
|
|
if ((pElan->RecvPktCount % 20) == 0 &&
|
|
pElan->RecvPktCount != pElan->MaxHeaderBufs)
|
|
{
|
|
DBGP((1, "RecvPktCount %d\n", pElan->RecvPktCount));
|
|
}
|
|
#endif
|
|
|
|
TRACEOUT(UnwrapRecvPacket);
|
|
|
|
return pOrigNdisPacket;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmLaneMSetNetworkAddresses(
|
|
IN PATMLANE_ELAN pElan,
|
|
IN PVOID InformationBuffer,
|
|
IN ULONG InformationBufferLength,
|
|
OUT PULONG BytesRead,
|
|
OUT PULONG BytesNeeded
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when the protocol above us wants to let us know about
|
|
the network address(es) assigned to this interface. If this is TCP/IP,
|
|
then we reformat and send a request to the ATM Call Manager to set
|
|
its atmfMyIpNmAddress object. We pick the first IP address given to us.
|
|
|
|
Arguments:
|
|
|
|
pElan - Pointer to the ELAN
|
|
|
|
InformationBuffer - Holds the data to be set.
|
|
|
|
InformationBufferLength - The length of InformationBuffer.
|
|
|
|
BytesRead - If the call is successful, returns the number
|
|
of bytes read from InformationBuffer.
|
|
|
|
BytesNeeded - If there is not enough data in InformationBuffer
|
|
to satisfy the OID, returns the amount of storage
|
|
needed.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
NDIS_STATUS_PENDING
|
|
NDIS_STATUS_INVALID_LENGTH
|
|
--*/
|
|
{
|
|
NETWORK_ADDRESS_LIST UNALIGNED * pAddrList;
|
|
NETWORK_ADDRESS UNALIGNED * pAddr;
|
|
NETWORK_ADDRESS_IP UNALIGNED * pIpAddr;
|
|
PNDIS_REQUEST pNdisRequest;
|
|
ULONG RequestSize;
|
|
PUCHAR pNetworkAddr;
|
|
NDIS_HANDLE NdisAdapterHandle;
|
|
NDIS_HANDLE NdisAfHandle;
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
*BytesRead = 0;
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
pAddrList = (NETWORK_ADDRESS_LIST UNALIGNED *)InformationBuffer;
|
|
|
|
do
|
|
{
|
|
ACQUIRE_ELAN_LOCK(pElan);
|
|
|
|
if (NULL_PATMLANE_ADAPTER != pElan->pAdapter)
|
|
{
|
|
NdisAfHandle = pElan->NdisAfHandle;
|
|
NdisAdapterHandle = pElan->pAdapter->NdisAdapterHandle;
|
|
}
|
|
else
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
RELEASE_ELAN_LOCK(pElan);
|
|
|
|
if (NDIS_STATUS_SUCCESS != Status)
|
|
{
|
|
break;
|
|
}
|
|
|
|
*BytesNeeded = sizeof(*pAddrList) -
|
|
FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address) +
|
|
sizeof(NETWORK_ADDRESS) -
|
|
FIELD_OFFSET(NETWORK_ADDRESS, Address);
|
|
|
|
if (InformationBufferLength < *BytesNeeded)
|
|
{
|
|
Status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
if (pAddrList->AddressType != NDIS_PROTOCOL_ID_TCP_IP)
|
|
{
|
|
// Not interesting.
|
|
break;
|
|
}
|
|
|
|
if (pAddrList->AddressCount <= 0)
|
|
{
|
|
Status = NDIS_STATUS_INVALID_DATA;
|
|
break;
|
|
}
|
|
|
|
pAddr = (NETWORK_ADDRESS UNALIGNED *)&pAddrList->Address[0];
|
|
|
|
if ((pAddr->AddressLength > InformationBufferLength - *BytesNeeded) ||
|
|
(pAddr->AddressLength == 0))
|
|
{
|
|
Status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
if (pAddr->AddressType != NDIS_PROTOCOL_ID_TCP_IP)
|
|
{
|
|
// Not interesting.
|
|
break;
|
|
}
|
|
|
|
if (pAddr->AddressLength < sizeof(NETWORK_ADDRESS_IP))
|
|
{
|
|
Status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
pIpAddr = (NETWORK_ADDRESS_IP UNALIGNED *)&pAddr->Address[0];
|
|
|
|
//
|
|
// Allocate an NDIS request to send down to the call manager.
|
|
//
|
|
RequestSize = sizeof(NDIS_REQUEST) + sizeof(pIpAddr->in_addr);
|
|
ALLOC_MEM(&pNdisRequest, RequestSize);
|
|
|
|
if (pNdisRequest == NULL)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Copy the network address in.
|
|
//
|
|
pNetworkAddr = ((PUCHAR)pNdisRequest + sizeof(NDIS_REQUEST));
|
|
NdisMoveMemory(pNetworkAddr, &pIpAddr->in_addr, sizeof(pIpAddr->in_addr));
|
|
|
|
DBGP((3, "%d Set network layer addr: length %d\n", pElan->ElanNumber, pAddr->AddressLength));
|
|
#if DBG
|
|
if (pAddr->AddressLength >= 4)
|
|
{
|
|
DBGP((1, "Network layer addr: %d.%d.%d.%d\n",
|
|
pNetworkAddr[0],
|
|
pNetworkAddr[1],
|
|
pNetworkAddr[2],
|
|
pNetworkAddr[3]));
|
|
}
|
|
#endif // DBG
|
|
|
|
//
|
|
// Send off the request.
|
|
//
|
|
Status = AtmLaneSendNdisCoRequest(
|
|
NdisAdapterHandle,
|
|
NdisAfHandle,
|
|
pNdisRequest,
|
|
NdisRequestSetInformation,
|
|
OID_ATM_MY_IP_NM_ADDRESS,
|
|
pNetworkAddr,
|
|
sizeof(pIpAddr->in_addr)
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_PENDING)
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
|
|
return (Status);
|
|
}
|
|
|