/*++

Copyright (c) 1992  Microsoft Corporation

Module Name:

	lpmini.c

Abstract:

	Loopback miniport

Author:

	Jameel Hyder	jameelh@microsoft.com

Environment:


Revision History:

--*/

#include "precomp.h"
#pragma hdrstop

NDIS_OID LBSupportedOidArray[] =
{
	OID_GEN_SUPPORTED_LIST,
	OID_GEN_HARDWARE_STATUS,
	OID_GEN_MEDIA_SUPPORTED,
	OID_GEN_MEDIA_IN_USE,
	OID_GEN_MAXIMUM_LOOKAHEAD,
	OID_GEN_MAXIMUM_FRAME_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_VENDOR_ID,
	OID_GEN_VENDOR_DESCRIPTION,
	OID_GEN_CURRENT_PACKET_FILTER,
	OID_GEN_CURRENT_LOOKAHEAD,
	OID_GEN_DRIVER_VERSION,
	OID_GEN_MAXIMUM_TOTAL_SIZE,

	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_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_FDDI_LONG_PERMANENT_ADDR,
	OID_FDDI_LONG_CURRENT_ADDR,
	OID_FDDI_LONG_MULTICAST_LIST,
	OID_FDDI_LONG_MAX_LIST_SIZE,
	OID_FDDI_SHORT_PERMANENT_ADDR,
	OID_FDDI_SHORT_CURRENT_ADDR,
	OID_FDDI_SHORT_MULTICAST_LIST,
	OID_FDDI_SHORT_MAX_LIST_SIZE,

	OID_LTALK_CURRENT_NODE_ID,

	OID_ARCNET_PERMANENT_ADDRESS,
	OID_ARCNET_CURRENT_ADDRESS
};

UINT	LBSupportedOids = sizeof(LBSupportedOidArray)/sizeof(NDIS_OID);
UCHAR	LBVendorDescription[] = "MS LoopBack Driver";
UCHAR	LBVendorId[3] = {0xFF, 0xFF, 0xFF};
const	NDIS_PHYSICAL_ADDRESS physicalConst = NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
LONG	LoopDebugLevel = DBG_LEVEL_ERR;
LONG	LoopDebugComponent = DBG_COMP_ALL;

const MEDIA_INFO MediaParams[] =
	{
		/* NdisMedium802_3     */   { 1500, 14, PACKET_FILTER_802_3, 100000},
		/* NdisMedium802_5     */   { 4082, 14, PACKET_FILTER_802_5,  40000},
		/* NdisMediumFddi      */   { 4486, 13, PACKET_FILTER_FDDI, 1000000},
		/* NdisMediumWan       */   { 0, 0, 0, 0},
		/* NdisMediumLocalTalk */   {  600,  3, PACKET_FILTER_LTALK, 2300},
		/* NdisMediumDix       */   { 1500, 14, PACKET_FILTER_DIX, 100000},
		/* NdisMediumArcnetRaw */   { 1512,  3, PACKET_FILTER_ARCNET, 25000},
		/* NdisMediumArcnet878_2 */ {1512, 3, PACKET_FILTER_ARCNET, 25000}
	};

NTSTATUS
DriverEntry(
	IN	PDRIVER_OBJECT		DriverObject,
	IN	PUNICODE_STRING		RegistryPath
	)
/*++

Routine Description:


Arguments:

Return Value:


--*/
{
	NDIS_STATUS						Status;
	NDIS_MINIPORT_CHARACTERISTICS	MChars;
	NDIS_STRING						Name;
	NDIS_HANDLE						WrapperHandle;

	//
	// Register the miniport with NDIS.
	//
    NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, NULL);

	NdisZeroMemory(&MChars, sizeof(NDIS_MINIPORT_CHARACTERISTICS));

	MChars.MajorNdisVersion = NDIS_MAJOR_VERSION;
	MChars.MinorNdisVersion = NDIS_MINOR_VERSION;

	MChars.InitializeHandler = LBInitialize;
	MChars.QueryInformationHandler = LBQueryInformation;
	MChars.SetInformationHandler = LBSetInformation;
	MChars.ResetHandler = LBReset;
	MChars.TransferDataHandler = LBTransferData;
	MChars.SendHandler = LBSend;
	MChars.HaltHandler = LBHalt;
	MChars.CheckForHangHandler = LBCheckForHang;

	Status = NdisMRegisterMiniport(WrapperHandle,
								   &MChars,
								   sizeof(MChars));
	if (Status != NDIS_STATUS_SUCCESS)
	{
		NdisTerminateWrapper(WrapperHandle, NULL);
	}

	return(Status);
}


NDIS_STATUS
LBInitialize(
	OUT PNDIS_STATUS			OpenErrorStatus,
	OUT PUINT					SelectedMediumIndex,
	IN	PNDIS_MEDIUM			MediumArray,
	IN	UINT					MediumArraySize,
	IN	NDIS_HANDLE				MiniportAdapterHandle,
	IN	NDIS_HANDLE				ConfigurationContext
	)
/*++

Routine Description:

	This is the initialize handler.

Arguments:

	OpenErrorStatus			Not used by us.
	SelectedMediumIndex		Place-holder for what media we are using
	MediumArray				Array of ndis media passed down to us to pick from
	MediumArraySize			Size of the array
	MiniportAdapterHandle	The handle NDIS uses to refer to us
	WrapperConfigurationContext	For use by NdisOpenConfiguration

Return Value:

	NDIS_STATUS_SUCCESS unless something goes wrong

--*/
{
	UINT							i, Length;
	PADAPTER						pAdapt;
	NDIS_MEDIUM						AdapterMedium;
	NDIS_HANDLE 					ConfigHandle = NULL;
	PNDIS_CONFIGURATION_PARAMETER	Parameter;
	PUCHAR							NetworkAddress;
	NDIS_STRING						MediumKey = NDIS_STRING_CONST("Medium");
	NDIS_STATUS						Status;

	do
	{
		//
		// Start off by allocating the adapter block
		//
		NdisAllocateMemory(&pAdapt,
						   sizeof(ADAPTER),
						   0,
						   physicalConst);
		if (pAdapt == NULL)
		{
			Status = NDIS_STATUS_RESOURCES;
			break;
		}
	
		NdisZeroMemory(pAdapt, sizeof(ADAPTER));
		pAdapt->MiniportHandle = MiniportAdapterHandle;
	
		NdisOpenConfiguration(&Status,
							  &ConfigHandle,
							  ConfigurationContext);
	
		if (Status != NDIS_STATUS_SUCCESS)
		{
			DBGPRINT(DBG_COMP_REGISTRY, DBG_LEVEL_FATAL,
					("Unable to open configuration database!\n"));
			break;
		}
	
		NdisReadConfiguration(&Status,
							  &Parameter,
							  ConfigHandle,
							  &MediumKey,
							  NdisParameterInteger);
	
		AdapterMedium = NdisMedium802_3;	// Default
		if (Status == NDIS_STATUS_SUCCESS)
		{
			AdapterMedium = (NDIS_MEDIUM)Parameter->ParameterData.IntegerData;
			if ((AdapterMedium != NdisMedium802_3)		&&
				(AdapterMedium != NdisMedium802_5)		&&
				(AdapterMedium != NdisMediumFddi)		&&
				(AdapterMedium != NdisMediumLocalTalk)	&&
				(AdapterMedium != NdisMediumArcnet878_2))
			{
				DBGPRINT(DBG_COMP_REGISTRY, DBG_LEVEL_FATAL,
						("Unable to find 'Medium' keyword or invalid value!\n"));
				Status = NDIS_STATUS_NOT_SUPPORTED;
				break;
			}

		}

		switch (AdapterMedium)
		{
		  case NdisMedium802_3:
			NdisMoveMemory(pAdapt->PermanentAddress,
						   ETH_CARD_ADDRESS,
						   ETH_LENGTH_OF_ADDRESS);
	
			NdisMoveMemory(pAdapt->CurrentAddress,
						   ETH_CARD_ADDRESS,
						   ETH_LENGTH_OF_ADDRESS);
			break;
		  case NdisMedium802_5:
			NdisMoveMemory(pAdapt->PermanentAddress,
						   TR_CARD_ADDRESS,
						   TR_LENGTH_OF_ADDRESS);
	
			NdisMoveMemory(pAdapt->CurrentAddress,
						   TR_CARD_ADDRESS,
						   TR_LENGTH_OF_ADDRESS);
			break;
		  case NdisMediumFddi:
			NdisMoveMemory(pAdapt->PermanentAddress,
						   FDDI_CARD_ADDRESS,
						   FDDI_LENGTH_OF_LONG_ADDRESS);
	
			NdisMoveMemory(pAdapt->CurrentAddress,
						   FDDI_CARD_ADDRESS,
						   FDDI_LENGTH_OF_LONG_ADDRESS);
			break;
		  case NdisMediumLocalTalk:
			pAdapt->PermanentAddress[0] = LTALK_CARD_ADDRESS;
	
			pAdapt->CurrentAddress[0] = LTALK_CARD_ADDRESS;
			break;
		  case NdisMediumArcnet878_2:
			pAdapt->PermanentAddress[0] = ARC_CARD_ADDRESS;
			pAdapt->CurrentAddress[0] = ARC_CARD_ADDRESS;
			break;
		}
	
		pAdapt->Medium = AdapterMedium;
		pAdapt->MediumLinkSpeed = MediaParams[(UINT)AdapterMedium].LinkSpeed;
		pAdapt->MediumMinPacketLen = MediaParams[(UINT)AdapterMedium].MacHeaderLen;
		pAdapt->MediumMaxPacketLen = MediaParams[(UINT)AdapterMedium].MacHeaderLen+
									 MediaParams[(UINT)AdapterMedium].MaxFrameLen;
		pAdapt->MediumMacHeaderLen = MediaParams[(UINT)AdapterMedium].MacHeaderLen;
		pAdapt->MediumMaxFrameLen  = MediaParams[(UINT)AdapterMedium].MaxFrameLen;
		pAdapt->MediumPacketFilters = MediaParams[(UINT)AdapterMedium].PacketFilters;

		NdisReadNetworkAddress(&Status,
							   &NetworkAddress,
							   &Length,
							   ConfigHandle);
	
		if (Status == NDIS_STATUS_SUCCESS)
		{
			//
			// verify the address is appropriate for the specific media and
			// ensure that the locally administered address bit is set
			//
			switch (AdapterMedium)
			{
			  case NdisMedium802_3:
			  case NdisMediumFddi:
				if ((Length != ETH_LENGTH_OF_ADDRESS) ||
					ETH_IS_MULTICAST(NetworkAddress) ||
					((NetworkAddress[0] & 0x02) == 0))
				{
					Length = 0;
				}
				break;
	
			  case NdisMedium802_5:
				if ((Length != TR_LENGTH_OF_ADDRESS) ||
					(NetworkAddress[0] & 0x80) ||
					((NetworkAddress[0] & 0x40) == 0))
				{
					Length = 0;
				}
				break;
	
			  case NdisMediumLocalTalk:
				if ((Length != 1) || LT_IS_BROADCAST(NetworkAddress[0]))
				{
					Length = 0;
				}
				break;
	
			  case NdisMediumArcnet878_2:
				if ((Length != 1) || ARC_IS_BROADCAST(NetworkAddress[0]))
				{
					Length = 0;
				}
				break;
			}
	
			if (Length == 0)
			{
				DBGPRINT(DBG_COMP_REGISTRY, DBG_LEVEL_FATAL,
						("Invalid NetAddress in registry!\n"));
			}
			else
			{
				NdisMoveMemory(pAdapt->CurrentAddress,
							   NetworkAddress,
							   Length);
			}
		}
	
		//
		// Make sure the medium saved is one of the ones being offered
		//
		for (i = 0; i < MediumArraySize; i++)
		{
			if (MediumArray[i] == AdapterMedium)
			{
				*SelectedMediumIndex = i;
				break;
			}
		}
	
		if (i == MediumArraySize)
		{
			Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
			break;
		}
	
		//
		// Set the attributes now.
		//
		NdisMSetAttributesEx(MiniportAdapterHandle,
							 pAdapt,
							 0,										// CheckForHangTimeInSeconds
							 NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT|NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT,
							 0);
		Status = NDIS_STATUS_SUCCESS;
	} while (FALSE);

	if (ConfigHandle != NULL)
	{
		NdisCloseConfiguration(ConfigHandle);
	}

	if (Status != NDIS_STATUS_SUCCESS)
	{
		if (pAdapt != NULL)
		{
			NdisFreeMemory(pAdapt, sizeof(ADAPTER), 0);
		}
	}

	return Status;
}


VOID
LBHalt(
	IN	NDIS_HANDLE				MiniportAdapterContext
	)
/*++

Routine Description:

	Halt handler.

Arguments:

	MiniportAdapterContext	Pointer to the Adapter

Return Value:

	None.

--*/
{
	PADAPTER	pAdapt = (PADAPTER)MiniportAdapterContext;

	//
	// Free the resources now
	//
	NdisFreeMemory(pAdapt, sizeof(ADAPTER), 0);
}


NDIS_STATUS
LBReset(
	OUT PBOOLEAN				AddressingReset,
	IN	NDIS_HANDLE				MiniportAdapterContext
	)
/*++

Routine Description:

	Reset Handler. We just don't do anything.

Arguments:

	AddressingReset			To let NDIS know whether we need help from it with our reset
	MiniportAdapterContext	Pointer to our adapter

Return Value:

	
--*/
{
	PADAPTER	pAdapt = (PADAPTER)MiniportAdapterContext;

	*AddressingReset = FALSE;

	return(NDIS_STATUS_SUCCESS);
}


NDIS_STATUS
LBSend(
	IN	NDIS_HANDLE				MiniportAdapterContext,
	IN	PNDIS_PACKET			Packet,
	IN	UINT					Flags
	)
/*++

Routine Description:

	Send handler. Just re-wrap the packet and send it below. Re-wrapping is necessary since
	NDIS uses the WrapperReserved for its own use.

Arguments:

	MiniportAdapterContext	Pointer to the adapter
	Packet					Packet to send
	Flags					Unused, passed down below

Return Value:

	Return code from NdisSend

--*/
{
    
        PADAPTER	pAdapt = (PADAPTER)MiniportAdapterContext;
    
        pAdapt->SendPackets++;
	
        return NDIS_STATUS_SUCCESS;
}


NDIS_STATUS
LBQueryInformation(
	IN	NDIS_HANDLE				MiniportAdapterContext,
	IN	NDIS_OID				Oid,
	IN	PVOID					InformationBuffer,
	IN	ULONG					InformationBufferLength,
	OUT PULONG					BytesWritten,
	OUT PULONG					BytesNeeded
	)
/*++

Routine Description:

	Miniport QueryInfo handler.

Arguments:

	MiniportAdapterContext	Pointer to the adapter structure
	Oid						Oid for this query
	InformationBuffer		Buffer for information
	InformationBufferLength	Size of this buffer
	BytesWritten			Specifies how much info is written
	BytesNeeded				In case the buffer is smaller than what we need, tell them how much is needed

Return Value:

	Return code from the NdisRequest below.

--*/
{
	PADAPTER	pAdapt = (PADAPTER)MiniportAdapterContext;
	NDIS_STATUS	Status = NDIS_STATUS_SUCCESS;
	UINT		i;
	NDIS_OID	MaskOid;
	PVOID		SourceBuffer;
	UINT		SourceBufferLength;
	ULONG		GenericUlong = 0;
	USHORT		GenericUshort;

    *BytesWritten = 0;
    *BytesNeeded = 0;

    DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
			("OID = %lx\n", Oid));


	for (i = 0;i < LBSupportedOids; i++)
	{
		if (Oid == LBSupportedOidArray[i])
			break;
	}

	if ((i == LBSupportedOids) ||
		(((Oid & OID_TYPE) != OID_TYPE_GENERAL)		 &&
		 (((pAdapt->Medium == NdisMedium802_3)		 && ((Oid & OID_TYPE) != OID_TYPE_802_3)) ||
		  ((pAdapt->Medium == NdisMedium802_5)		 && ((Oid & OID_TYPE) != OID_TYPE_802_5)) ||
		  ((pAdapt->Medium == NdisMediumFddi)		 && ((Oid & OID_TYPE) != OID_TYPE_FDDI))  ||
		  ((pAdapt->Medium == NdisMediumLocalTalk)   && ((Oid & OID_TYPE) != OID_TYPE_LTALK)) ||
		  ((pAdapt->Medium == NdisMediumArcnet878_2) && ((Oid & OID_TYPE) != OID_TYPE_ARCNET)))))
	{
		return NDIS_STATUS_INVALID_OID;
	}

	//
	// Initialize these once, since this is the majority of cases.
	//

	SourceBuffer = (PVOID)&GenericUlong;
	SourceBufferLength = sizeof(ULONG);

	switch (Oid & OID_TYPE_MASK)
	{
	  case OID_TYPE_GENERAL_OPERATIONAL:
                switch (Oid)
		{
		  case OID_GEN_MAC_OPTIONS:
			GenericUlong = (ULONG)(NDIS_MAC_OPTION_NO_LOOPBACK);
			break;

		  case OID_GEN_SUPPORTED_LIST:
			SourceBuffer = LBSupportedOidArray;
			SourceBufferLength = LBSupportedOids * sizeof(ULONG);
			break;

		  case OID_GEN_HARDWARE_STATUS:
			GenericUlong = NdisHardwareStatusReady;
			break;

		  case OID_GEN_MEDIA_SUPPORTED:
		  case OID_GEN_MEDIA_IN_USE:
			GenericUlong = pAdapt->Medium;
			break;

		  case OID_GEN_MAXIMUM_LOOKAHEAD:
			GenericUlong = MAX_LOOKAHEAD;
			break;

		  case OID_GEN_MAXIMUM_FRAME_SIZE:
			GenericUlong = pAdapt->MediumMaxFrameLen;
			break;

		  case OID_GEN_LINK_SPEED:
			GenericUlong = pAdapt->MediumLinkSpeed;
			break;

		  case OID_GEN_TRANSMIT_BUFFER_SPACE:
			GenericUlong = pAdapt->MediumMaxPacketLen;
			break;

		  case OID_GEN_RECEIVE_BUFFER_SPACE:
			GenericUlong = pAdapt->MediumMaxPacketLen;
			break;

		  case OID_GEN_TRANSMIT_BLOCK_SIZE:
			GenericUlong = 1;
			break;

		  case OID_GEN_RECEIVE_BLOCK_SIZE:
			GenericUlong = 1;
			break;

		  case OID_GEN_VENDOR_ID:
			SourceBuffer = LBVendorId;
			SourceBufferLength = sizeof(LBVendorId);
			break;

		  case OID_GEN_VENDOR_DESCRIPTION:
			SourceBuffer = LBVendorDescription;
			SourceBufferLength = sizeof(LBVendorDescription);
			break;

		  case OID_GEN_CURRENT_PACKET_FILTER:
			GenericUlong = pAdapt->PacketFilter;
			break;

		  case OID_GEN_CURRENT_LOOKAHEAD:
			GenericUlong = pAdapt->MaxLookAhead;
			break;

		  case OID_GEN_DRIVER_VERSION:
			GenericUshort = (LOOP_MAJOR_VERSION << 8) + LOOP_MINOR_VERSION;
			SourceBuffer = &GenericUshort;
			SourceBufferLength = sizeof(USHORT);
			break;

		  case OID_GEN_MAXIMUM_TOTAL_SIZE:
			GenericUlong = pAdapt->MediumMaxPacketLen;
			break;

		  default:
			ASSERT(FALSE);
			break;
		}
		break;

          case OID_TYPE_GENERAL_STATISTICS:
                MaskOid = (Oid & OID_INDEX_MASK) - 1;
                switch (Oid & OID_REQUIRED_MASK)
                {
                  case OID_REQUIRED_MANDATORY:
                        switch(Oid)
                        {
                   
                          case OID_GEN_XMIT_OK:
                                SourceBuffer = &(pAdapt->SendPackets);
                                SourceBufferLength = sizeof(ULONG);
                                break;
                      
                          default: 
                                ASSERT (MaskOid < GM_ARRAY_SIZE);
                                GenericUlong = pAdapt->GeneralMandatory[MaskOid];
                                break;
                        }
              
                        break;

                  default:
                        ASSERT(FALSE);
                        break;
                }
                break;

	  case OID_TYPE_802_3_OPERATIONAL:

		switch (Oid)
		{
		  case OID_802_3_PERMANENT_ADDRESS:
			SourceBuffer = pAdapt->PermanentAddress;
			SourceBufferLength = ETH_LENGTH_OF_ADDRESS;
			break;
		  case OID_802_3_CURRENT_ADDRESS:
			SourceBuffer = pAdapt->CurrentAddress;
			SourceBufferLength = ETH_LENGTH_OF_ADDRESS;
			break;

		  case OID_802_3_MAXIMUM_LIST_SIZE:
			GenericUlong = ETH_MAX_MULTICAST_ADDRESS;
			break;

		  default:
			ASSERT(FALSE);
			break;
		}
		break;

	  case OID_TYPE_802_3_STATISTICS:

		switch (Oid)
		{
		  case OID_802_3_RCV_ERROR_ALIGNMENT:
		  case OID_802_3_XMIT_ONE_COLLISION:
		  case OID_802_3_XMIT_MORE_COLLISIONS:
			GenericUlong = 0;
			break;

		  default:
			ASSERT(FALSE);
			break;
		}
		break;

	  case OID_TYPE_802_5_OPERATIONAL:

		switch (Oid)
		{
		  case OID_802_5_PERMANENT_ADDRESS:
			SourceBuffer = pAdapt->PermanentAddress;
			SourceBufferLength = TR_LENGTH_OF_ADDRESS;
			break;

		  case OID_802_5_CURRENT_ADDRESS:
			SourceBuffer = pAdapt->CurrentAddress;
			SourceBufferLength = TR_LENGTH_OF_ADDRESS;
			break;

		  case OID_802_5_LAST_OPEN_STATUS:
			GenericUlong = 0;
			break;

		  case OID_802_5_CURRENT_RING_STATUS:
			GenericUlong = NDIS_RING_SINGLE_STATION;
			break;

		  case OID_802_5_CURRENT_RING_STATE:
			GenericUlong = NdisRingStateOpened;
			break;

		  default:
			ASSERT(FALSE);
			break;

		}
		break;

	  case OID_TYPE_802_5_STATISTICS:

		switch (Oid)
		{
		  case OID_802_5_LINE_ERRORS:
		  case OID_802_5_LOST_FRAMES:
			GenericUlong = 0;
			break;

		  default:
			ASSERT(FALSE);
			break;
		}
		break;

	  case OID_TYPE_FDDI_OPERATIONAL:

		switch (Oid)
		{
		  case OID_FDDI_LONG_PERMANENT_ADDR:
			SourceBuffer = pAdapt->PermanentAddress;
			SourceBufferLength = FDDI_LENGTH_OF_LONG_ADDRESS;
			break;

		  case OID_FDDI_LONG_CURRENT_ADDR:
			SourceBuffer = pAdapt->CurrentAddress;
			SourceBufferLength = FDDI_LENGTH_OF_LONG_ADDRESS;
			break;

		  case OID_FDDI_LONG_MAX_LIST_SIZE:
			GenericUlong = FDDI_MAX_MULTICAST_LONG;
			break;

		  case OID_FDDI_SHORT_PERMANENT_ADDR:
			SourceBuffer = pAdapt->PermanentAddress;
			SourceBufferLength = FDDI_LENGTH_OF_SHORT_ADDRESS;
			break;

		  case OID_FDDI_SHORT_CURRENT_ADDR:
			SourceBuffer = pAdapt->CurrentAddress;
			SourceBufferLength = FDDI_LENGTH_OF_SHORT_ADDRESS;
			break;

		  case OID_FDDI_SHORT_MAX_LIST_SIZE:
			GenericUlong = FDDI_MAX_MULTICAST_SHORT;
			break;

		default:
			ASSERT(FALSE);
			break;
		}
		break;

  case OID_TYPE_LTALK_OPERATIONAL:

		switch(Oid)
		{
		  case OID_LTALK_CURRENT_NODE_ID:
			SourceBuffer = pAdapt->CurrentAddress;
			SourceBufferLength = 1;
			break;

		default:
			ASSERT(FALSE);
			break;
		}
		break;

    case OID_TYPE_ARCNET_OPERATIONAL:
		switch(Oid)
		{
		  case OID_ARCNET_PERMANENT_ADDRESS:
			SourceBuffer = pAdapt->PermanentAddress;
			SourceBufferLength = 1;
			break;

		  case OID_ARCNET_CURRENT_ADDRESS:
			SourceBuffer = pAdapt->CurrentAddress;
			SourceBufferLength = 1;
			break;

		  default:
			ASSERT(FALSE);
			break;

		}
		break;

	  default:
		ASSERT(FALSE);
		break;
	}

	if (SourceBufferLength > InformationBufferLength)
	{
		*BytesNeeded = SourceBufferLength;
		return NDIS_STATUS_BUFFER_TOO_SHORT;
	}

	NdisMoveMemory(InformationBuffer, SourceBuffer, SourceBufferLength);
	*BytesWritten = SourceBufferLength;
	
    return(Status);
}


NDIS_STATUS
LBSetInformation(
	IN	NDIS_HANDLE				MiniportAdapterContext,
	IN	NDIS_OID				Oid,
	IN	PVOID					InformationBuffer,
	IN	ULONG					InformationBufferLength,
	OUT PULONG					BytesRead,
	OUT PULONG					BytesNeeded
	)
/*++

Routine Description:

	Miniport SetInfo handler.

Arguments:

	MiniportAdapterContext	Pointer to the adapter structure
	Oid						Oid for this query
	InformationBuffer		Buffer for information
	InformationBufferLength	Size of this buffer
	BytesRead				Specifies how much info is read
	BytesNeeded				In case the buffer is smaller than what we need, tell them how much is needed

Return Value:

	Return code from the NdisRequest below.

--*/
{
	PADAPTER	pAdapt = (PADAPTER)MiniportAdapterContext;
	NDIS_STATUS	Status = NDIS_STATUS_SUCCESS;

    *BytesRead = 0;
    *BytesNeeded = 0;

    DBGPRINT(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
			("SetInformation: OID = %lx\n", Oid));

    switch (Oid)
	{
	  case OID_GEN_CURRENT_PACKET_FILTER:
        if (InformationBufferLength != sizeof(ULONG))
		{
            Status = NDIS_STATUS_INVALID_DATA;
        }
		else
		{
			ULONG	PacketFilter;

			PacketFilter = *(UNALIGNED ULONG *)InformationBuffer;

			if (PacketFilter != (PacketFilter & pAdapt->MediumPacketFilters))
			{
				Status = NDIS_STATUS_NOT_SUPPORTED;
			}
			else
			{
				pAdapt->PacketFilter = PacketFilter;
				*BytesRead = InformationBufferLength;
			}
		}
        break;

	  case OID_GEN_CURRENT_LOOKAHEAD:
        if (InformationBufferLength != sizeof(ULONG))
		{
			Status = NDIS_STATUS_INVALID_DATA;
		}
		else
		{
			ULONG	CurrentLookahead;

			CurrentLookahead = *(UNALIGNED ULONG *)InformationBuffer;
	
			if (CurrentLookahead > MAX_LOOKAHEAD)
			{
				Status = NDIS_STATUS_INVALID_LENGTH;
			}
			else if (CurrentLookahead >= pAdapt->MaxLookAhead)
			{
				pAdapt->MaxLookAhead = CurrentLookahead;
				*BytesRead = sizeof(ULONG);
				Status = NDIS_STATUS_SUCCESS;
			}
		}
		break;

	  case OID_802_3_MULTICAST_LIST:
		if (pAdapt->Medium != NdisMedium802_3)
		{
			Status = NDIS_STATUS_INVALID_OID;
			break;
		}

		if ((InformationBufferLength % ETH_LENGTH_OF_ADDRESS) != 0)
		{
			Status = NDIS_STATUS_INVALID_LENGTH;
			break;
		}
		break;

	  case OID_802_5_CURRENT_FUNCTIONAL:
		if (pAdapt->Medium != NdisMedium802_5)
		{
			Status = NDIS_STATUS_INVALID_OID;
			break;
		}

		if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL)
		{
			Status = NDIS_STATUS_INVALID_LENGTH;
			break;
		}
		break;

	  case OID_802_5_CURRENT_GROUP:
		if (pAdapt->Medium != NdisMedium802_5)
		{
			Status = NDIS_STATUS_INVALID_OID;
			break;
		}

		if (InformationBufferLength != TR_LENGTH_OF_FUNCTIONAL)
		{
			Status = NDIS_STATUS_INVALID_LENGTH;
			break;
		}
		break;

	  case OID_FDDI_LONG_MULTICAST_LIST:
		if (pAdapt->Medium != NdisMediumFddi)
		{
			Status = NDIS_STATUS_INVALID_OID;
			break;
		}

		if ((InformationBufferLength % FDDI_LENGTH_OF_LONG_ADDRESS) != 0)
		{
			Status = NDIS_STATUS_INVALID_LENGTH;
			break;
		}
		break;

	  case OID_FDDI_SHORT_MULTICAST_LIST:
		if (pAdapt->Medium != NdisMediumFddi)
		{
			Status = NDIS_STATUS_INVALID_OID;
			break;
		}

		if ((InformationBufferLength % FDDI_LENGTH_OF_SHORT_ADDRESS) != 0)
		{
			Status = NDIS_STATUS_INVALID_LENGTH;
			break;
		}
		break;

	  case OID_GEN_PROTOCOL_OPTIONS:
		Status = NDIS_STATUS_SUCCESS;
		break;

	  default:
		Status = NDIS_STATUS_INVALID_OID;
		break;
    }

	return(Status);
}

BOOLEAN
LBCheckForHang(
	IN	NDIS_HANDLE				MiniportAdapterContext
	)
{
	return FALSE;
}


NDIS_STATUS
LBTransferData(
	OUT PNDIS_PACKET			Packet,
	OUT PUINT					BytesTransferred,
	IN	NDIS_HANDLE				MiniportAdapterContext,
	IN	NDIS_HANDLE				MiniportReceiveContext,
	IN	UINT					ByteOffset,
	IN	UINT					BytesToTransfer
	)
{
	ASSERT (0);

	return NDIS_STATUS_NOT_SUPPORTED;
}