3086 lines
91 KiB
C
3086 lines
91 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989-1993 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
ndis.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains code which implements the routines used to
|
|||
|
initialize the IPX <-> NDIS interface, as well as most of the
|
|||
|
interface routines.
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Sanjay Anand (SanjayAn) 3-Oct-1995
|
|||
|
Changes to support transfer of buffer ownership to transports
|
|||
|
1. Added the ReceivePacketHandler to the ProtChars.
|
|||
|
|
|||
|
Sanjay Anand (SanjayAn) 27-Oct-1995
|
|||
|
Changes to support Plug and Play
|
|||
|
|
|||
|
Tony Bell (TonyBe) 10-Dec-1995
|
|||
|
Changes to support new NdisWan Lineup.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
//
|
|||
|
// This is a one-per-driver variable used in binding
|
|||
|
// to the NDIS interface.
|
|||
|
//
|
|||
|
|
|||
|
NDIS_HANDLE IpxNdisProtocolHandle = (NDIS_HANDLE)NULL;
|
|||
|
NDIS_HANDLE IpxGlobalPacketPool = (NDIS_HANDLE)NULL;
|
|||
|
extern CTELock IpxGlobalInterlock;
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
IpxMediaSenseHandler(
|
|||
|
IN CTEEvent *WorkerThreadEvent,
|
|||
|
IN PVOID Context);
|
|||
|
|
|||
|
void
|
|||
|
LineDownOnWorkerThread(
|
|||
|
IN CTEEvent *WorkerThreadEvent,
|
|||
|
IN PVOID Context);
|
|||
|
|
|||
|
void
|
|||
|
LineUpOnWorkerThread(
|
|||
|
IN CTEEvent *WorkerThreadEvent,
|
|||
|
IN PVOID Context);
|
|||
|
|
|||
|
#ifndef max
|
|||
|
#define max(a, b) ((a) > (b)) ? (a) : (b)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IpxRegisterProtocol(
|
|||
|
IN PNDIS_STRING NameString
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine introduces this transport to the NDIS interface.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NameString - The name of the transport.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
STATUS_SUCCESS if all goes well,
|
|||
|
Failure status if we tried to register and couldn't,
|
|||
|
STATUS_INSUFFICIENT_RESOURCES if we couldn't even try to register.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NDIS_STATUS ndisStatus;
|
|||
|
|
|||
|
NDIS_PROTOCOL_CHARACTERISTICS ProtChars; // Used temporarily to register
|
|||
|
|
|||
|
RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
|
|||
|
//
|
|||
|
// Set up the characteristics of this protocol
|
|||
|
//
|
|||
|
#if NDIS40
|
|||
|
ProtChars.MajorNdisVersion = 4;
|
|||
|
|
|||
|
ProtChars.ReceivePacketHandler = IpxReceivePacket;
|
|||
|
#else
|
|||
|
ProtChars.MajorNdisVersion = 3;
|
|||
|
#endif
|
|||
|
ProtChars.MinorNdisVersion = 0;
|
|||
|
|
|||
|
ProtChars.Name = *NameString;
|
|||
|
|
|||
|
ProtChars.OpenAdapterCompleteHandler = IpxOpenAdapterComplete;
|
|||
|
ProtChars.CloseAdapterCompleteHandler = IpxCloseAdapterComplete;
|
|||
|
ProtChars.ResetCompleteHandler = IpxResetComplete;
|
|||
|
ProtChars.RequestCompleteHandler = IpxRequestComplete;
|
|||
|
|
|||
|
ProtChars.SendCompleteHandler = IpxSendComplete;
|
|||
|
ProtChars.TransferDataCompleteHandler = IpxTransferDataComplete;
|
|||
|
|
|||
|
ProtChars.ReceiveHandler = IpxReceiveIndication;
|
|||
|
ProtChars.ReceiveCompleteHandler = IpxReceiveComplete;
|
|||
|
ProtChars.StatusHandler = IpxStatus;
|
|||
|
ProtChars.StatusCompleteHandler = IpxStatusComplete;
|
|||
|
|
|||
|
ProtChars.BindAdapterHandler = IpxBindAdapter;
|
|||
|
ProtChars.UnbindAdapterHandler = IpxUnbindAdapter;
|
|||
|
ProtChars.UnloadHandler = IpxNdisUnload;
|
|||
|
|
|||
|
//
|
|||
|
// We pass up the NET_PNP_EVENT structures passed in by NDIS
|
|||
|
// to the Transports via TDI. We pass on the response from TDI to NDIS.
|
|||
|
//
|
|||
|
#ifdef _PNP_POWER_
|
|||
|
ProtChars.PnPEventHandler = IpxPnPEventHandler;
|
|||
|
#endif
|
|||
|
|
|||
|
NdisRegisterProtocol (
|
|||
|
&ndisStatus,
|
|||
|
&IpxNdisProtocolHandle,
|
|||
|
&ProtChars,
|
|||
|
(UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + NameString->Length);
|
|||
|
|
|||
|
if (ndisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
return (NTSTATUS)ndisStatus;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a pool of packets for use by single send/receive
|
|||
|
//
|
|||
|
IpxGlobalPacketPool = (void *) NDIS_PACKET_POOL_TAG_FOR_NWLNKIPX;
|
|||
|
NdisAllocatePacketPoolEx(&ndisStatus,
|
|||
|
&IpxGlobalPacketPool,
|
|||
|
10,
|
|||
|
90,
|
|||
|
max(sizeof(IPX_SEND_RESERVED), sizeof(IPX_RECEIVE_RESERVED)));
|
|||
|
|
|||
|
NdisSetPacketPoolProtocolId(IpxGlobalPacketPool, NDIS_PROTOCOL_ID_IPX);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
} /* IpxRegisterProtocol */
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IpxDeregisterProtocol (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine removes this transport to the NDIS interface.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NDIS_STATUS ndisStatus;
|
|||
|
CTELockHandle LockHandle;
|
|||
|
NDIS_HANDLE LocalNdisProtocolHandle = (NDIS_HANDLE)NULL;
|
|||
|
NDIS_HANDLE LocalGlobalPacketPool = (NDIS_HANDLE)NULL;
|
|||
|
|
|||
|
|
|||
|
CTEGetLock (&IpxGlobalInterlock, &LockHandle);
|
|||
|
|
|||
|
if (IpxNdisProtocolHandle != (NDIS_HANDLE)NULL) {
|
|||
|
LocalNdisProtocolHandle = IpxNdisProtocolHandle;
|
|||
|
IpxNdisProtocolHandle = (NDIS_HANDLE) NULL;
|
|||
|
CTEFreeLock (&IpxGlobalInterlock, LockHandle);
|
|||
|
NdisDeregisterProtocol (
|
|||
|
&ndisStatus,
|
|||
|
LocalNdisProtocolHandle);
|
|||
|
ASSERT(ndisStatus == NDIS_STATUS_SUCCESS);
|
|||
|
} else {
|
|||
|
CTEFreeLock (&IpxGlobalInterlock, LockHandle);
|
|||
|
}
|
|||
|
|
|||
|
CTEGetLock (&IpxGlobalInterlock, &LockHandle);
|
|||
|
|
|||
|
if (IpxGlobalPacketPool != NULL) {
|
|||
|
LocalGlobalPacketPool = IpxGlobalPacketPool;
|
|||
|
IpxGlobalPacketPool = (NDIS_HANDLE) NULL;
|
|||
|
CTEFreeLock (&IpxGlobalInterlock, LockHandle);
|
|||
|
|
|||
|
NdisFreePacketPool(LocalGlobalPacketPool);
|
|||
|
|
|||
|
} else {
|
|||
|
CTEFreeLock (&IpxGlobalInterlock, LockHandle);
|
|||
|
}
|
|||
|
|
|||
|
} /* IpxDeregisterProtocol */
|
|||
|
|
|||
|
VOID
|
|||
|
IpxDelayedSubmitNdisRequest(
|
|||
|
IN PVOID Param
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine submit an ndis request at PASSIVE level. We assume that Adatper structure
|
|||
|
still exist. IpxDestroyAdapter will delay 1 sec to allow this thread to finish.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Param - pointer to the work item.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PIPX_DELAYED_NDISREQUEST_ITEM DelayedNdisItem = (PIPX_DELAYED_NDISREQUEST_ITEM) Param;
|
|||
|
PADAPTER Adapter;
|
|||
|
UNICODE_STRING AdapterName;
|
|||
|
NDIS_REQUEST IpxRequest;
|
|||
|
NDIS_STATUS NdisStatus;
|
|||
|
|
|||
|
Adapter = (PADAPTER) DelayedNdisItem->Adapter;
|
|||
|
|
|||
|
RtlInitUnicodeString(&AdapterName, Adapter->AdapterName);
|
|||
|
IpxRequest = DelayedNdisItem->IpxRequest;
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, &AdapterName);
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
IPX_DEBUG(PNP, ("Setting the QoS OID SUCCESS\n"));
|
|||
|
} else {
|
|||
|
IPX_DEBUG(PNP, ("Setting the QoS OID failed - Error %lx\n", NdisStatus));
|
|||
|
}
|
|||
|
|
|||
|
IpxFreeMemory(IpxRequest.DATA.SET_INFORMATION.InformationBuffer,
|
|||
|
DelayedNdisItem->AddrListSize,
|
|||
|
MEMORY_ADAPTER,
|
|||
|
"QoS specific stuff");
|
|||
|
|
|||
|
IpxFreeMemory (
|
|||
|
DelayedNdisItem,
|
|||
|
sizeof (IPX_DELAYED_NDISREQUEST_ITEM),
|
|||
|
MEMORY_WORK_ITEM,
|
|||
|
"Work Item");
|
|||
|
|
|||
|
IpxDereferenceDevice (Adapter->Device, DREF_ADAPTER);
|
|||
|
IpxDereferenceAdapter1(Adapter,ADAP_REF_NDISREQ);
|
|||
|
|
|||
|
} /* IpxDelayedSubmitNdisRequest */
|
|||
|
|
|||
|
NDIS_STATUS
|
|||
|
IpxSubmitNdisRequest(
|
|||
|
IN PADAPTER Adapter,
|
|||
|
IN PNDIS_REQUEST Request,
|
|||
|
IN PNDIS_STRING AdapterString
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine passed an NDIS_REQUEST to the MAC and waits
|
|||
|
until it has completed before returning the final status.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Adapter - Pointer to the device context for this driver.
|
|||
|
|
|||
|
Request - Pointer to the NDIS_REQUEST to submit.
|
|||
|
|
|||
|
AdapterString - The name of the adapter, in case an error needs
|
|||
|
to be logged.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NDIS_STATUS NdisStatus;
|
|||
|
|
|||
|
IPX_NDIS_REQUEST IpxRequest;
|
|||
|
|
|||
|
RtlZeroMemory(&IpxRequest, sizeof(IpxRequest));
|
|||
|
RtlCopyMemory(&IpxRequest, Request, sizeof(NDIS_REQUEST));
|
|||
|
KeInitializeEvent(&IpxRequest.NdisRequestEvent,NotificationEvent,FALSE);
|
|||
|
IpxRequest.Status = NDIS_STATUS_SUCCESS;
|
|||
|
|
|||
|
NdisRequest(
|
|||
|
&NdisStatus,
|
|||
|
Adapter->NdisBindingHandle,
|
|||
|
(PNDIS_REQUEST) &IpxRequest);
|
|||
|
|
|||
|
if (NdisStatus == NDIS_STATUS_PENDING) {
|
|||
|
|
|||
|
//
|
|||
|
// The completion routine will set NdisRequestStatus.
|
|||
|
//
|
|||
|
|
|||
|
KeWaitForSingleObject(
|
|||
|
&IpxRequest.NdisRequestEvent,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
TRUE,
|
|||
|
(PLARGE_INTEGER)NULL
|
|||
|
);
|
|||
|
|
|||
|
NdisStatus = IpxRequest.Status;
|
|||
|
|
|||
|
KeResetEvent(
|
|||
|
&IpxRequest.NdisRequestEvent
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// Skip event log when QoS is not installed.
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS &&
|
|||
|
// This is not related to QoS
|
|||
|
(Request->DATA.QUERY_INFORMATION.Oid != OID_GEN_NETWORK_LAYER_ADDRESSES ||
|
|||
|
// or it is related to QoS and the status is not the status when QoS is
|
|||
|
// not installed.
|
|||
|
(Request->DATA.QUERY_INFORMATION.Oid == OID_GEN_NETWORK_LAYER_ADDRESSES &&
|
|||
|
NdisStatus != NDIS_STATUS_INVALID_OID))) {
|
|||
|
|
|||
|
IPX_DEBUG (NDIS, ("%s on OID %8.8lx failed %lx\n",
|
|||
|
Request->RequestType == NdisRequestSetInformation ? "Set" : "Query",
|
|||
|
Request->DATA.QUERY_INFORMATION.Oid,
|
|||
|
NdisStatus));
|
|||
|
|
|||
|
IpxWriteOidErrorLog(
|
|||
|
Adapter->Device->DeviceObject,
|
|||
|
Request->RequestType == NdisRequestSetInformation ?
|
|||
|
EVENT_TRANSPORT_SET_OID_FAILED : EVENT_TRANSPORT_QUERY_OID_FAILED,
|
|||
|
NdisStatus,
|
|||
|
AdapterString->Buffer,
|
|||
|
Request->DATA.QUERY_INFORMATION.Oid);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
IPX_DEBUG (NDIS, ("%s on OID %8.8lx succeeded\n",
|
|||
|
Request->RequestType == NdisRequestSetInformation ? "Set" : "Query",
|
|||
|
Request->DATA.QUERY_INFORMATION.Oid));
|
|||
|
}
|
|||
|
|
|||
|
return NdisStatus;
|
|||
|
|
|||
|
} /* IpxSubmitNdisRequest */
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IpxInitializeNdis(
|
|||
|
IN PADAPTER Adapter,
|
|||
|
IN PBINDING_CONFIG ConfigBinding
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine introduces this transport to the NDIS interface and sets up
|
|||
|
any necessary NDIS data structures (Buffer pools and such). It will be
|
|||
|
called for each adapter opened by this transport.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Adapter - Structure describing this binding.
|
|||
|
|
|||
|
ConfigAdapter - Configuration information for this binding.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NDIS_STATUS NdisStatus;
|
|||
|
NDIS_STATUS OpenErrorStatus;
|
|||
|
NDIS_MEDIUM IpxSupportedMedia[] = { NdisMedium802_3, NdisMedium802_5, NdisMediumFddi, NdisMediumArcnet878_2, NdisMediumWan };
|
|||
|
UINT SelectedMedium;
|
|||
|
NDIS_REQUEST IpxRequest;
|
|||
|
ULONG MinimumLookahead;
|
|||
|
UCHAR WanProtocolId[6] = { 0x80, 0x00, 0x00, 0x00, 0x81, 0x37 };
|
|||
|
UCHAR FunctionalAddress[4] = { 0x00, 0x80, 0x00, 0x00 };
|
|||
|
ULONG WanHeaderFormat = NdisWanHeaderEthernet;
|
|||
|
NDIS_OID IpxOid;
|
|||
|
ULONG MacOptions;
|
|||
|
ULONG PacketFilter;
|
|||
|
PNDIS_STRING AdapterString = &ConfigBinding->AdapterName;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize this adapter for IPX use through NDIS
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// This event is used in case any of the NDIS requests
|
|||
|
// pend; we wait until it is set by the completion
|
|||
|
// routine, which also sets NdisRequestStatus.
|
|||
|
//
|
|||
|
|
|||
|
KeInitializeEvent(
|
|||
|
&Adapter->NdisRequestEvent,
|
|||
|
NotificationEvent,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
|
|||
|
Adapter->NdisBindingHandle = NULL;
|
|||
|
|
|||
|
OpenErrorStatus = 0;
|
|||
|
|
|||
|
NdisOpenAdapter (
|
|||
|
&NdisStatus,
|
|||
|
&OpenErrorStatus,
|
|||
|
&Adapter->NdisBindingHandle,
|
|||
|
&SelectedMedium,
|
|||
|
IpxSupportedMedia,
|
|||
|
sizeof (IpxSupportedMedia) / sizeof(NDIS_MEDIUM),
|
|||
|
IpxNdisProtocolHandle,
|
|||
|
(NDIS_HANDLE)Adapter,
|
|||
|
&ConfigBinding->AdapterName,
|
|||
|
0,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (NdisStatus == NDIS_STATUS_PENDING) {
|
|||
|
|
|||
|
//
|
|||
|
// The completion routine will set NdisRequestStatus.
|
|||
|
//
|
|||
|
|
|||
|
KeWaitForSingleObject(
|
|||
|
&Adapter->NdisRequestEvent,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
TRUE,
|
|||
|
(PLARGE_INTEGER)NULL
|
|||
|
);
|
|||
|
|
|||
|
NdisStatus = Adapter->NdisRequestStatus;
|
|||
|
OpenErrorStatus = Adapter->OpenErrorStatus;
|
|||
|
|
|||
|
KeResetEvent(
|
|||
|
&Adapter->NdisRequestEvent
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
|
|||
|
IPX_DEBUG (NDIS, ("Open %ws failed %lx\n", ConfigBinding->AdapterName.Buffer, NdisStatus));
|
|||
|
|
|||
|
IpxWriteGeneralErrorLog(
|
|||
|
Adapter->Device->DeviceObject,
|
|||
|
EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
|
|||
|
807,
|
|||
|
NdisStatus,
|
|||
|
AdapterString->Buffer,
|
|||
|
1,
|
|||
|
&OpenErrorStatus);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
IPX_DEBUG (NDIS, ("Open %ws succeeded\n", ConfigBinding->AdapterName.Buffer));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Get the information we need about the adapter, based on
|
|||
|
// the media type.
|
|||
|
//
|
|||
|
|
|||
|
MacInitializeMacInfo(
|
|||
|
IpxSupportedMedia[SelectedMedium],
|
|||
|
&Adapter->MacInfo);
|
|||
|
|
|||
|
|
|||
|
switch (Adapter->MacInfo.RealMediumType) {
|
|||
|
|
|||
|
case NdisMedium802_3:
|
|||
|
|
|||
|
IpxOid = OID_802_3_CURRENT_ADDRESS;
|
|||
|
break;
|
|||
|
|
|||
|
case NdisMedium802_5:
|
|||
|
|
|||
|
IpxOid = OID_802_5_CURRENT_ADDRESS;
|
|||
|
break;
|
|||
|
|
|||
|
case NdisMediumFddi:
|
|||
|
|
|||
|
IpxOid = OID_FDDI_LONG_CURRENT_ADDR;
|
|||
|
break;
|
|||
|
|
|||
|
case NdisMediumArcnet878_2:
|
|||
|
|
|||
|
IpxOid = OID_ARCNET_CURRENT_ADDRESS;
|
|||
|
break;
|
|||
|
|
|||
|
case NdisMediumWan:
|
|||
|
|
|||
|
IpxOid = OID_WAN_CURRENT_ADDRESS;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
// 301870
|
|||
|
return NDIS_STATUS_FAILURE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
IpxRequest.RequestType = NdisRequestQueryInformation;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.Oid = IpxOid;
|
|||
|
|
|||
|
if (IpxOid != OID_ARCNET_CURRENT_ADDRESS) {
|
|||
|
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = Adapter->LocalMacAddress.Address;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// We take the arcnet single-byte address and right-justify
|
|||
|
// it in a field of zeros.
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory (Adapter->LocalMacAddress.Address, 5);
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &Adapter->LocalMacAddress.Address[5];
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 1;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
IpxCloseNdis (Adapter);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now query the maximum packet sizes.
|
|||
|
//
|
|||
|
|
|||
|
IpxRequest.RequestType = NdisRequestQueryInformation;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_FRAME_SIZE;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MaxReceivePacketSize);
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
IpxCloseNdis (Adapter);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
IpxRequest.RequestType = NdisRequestQueryInformation;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MaxSendPacketSize);
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
IpxCloseNdis (Adapter);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Query the receive buffer space.
|
|||
|
//
|
|||
|
|
|||
|
IpxRequest.RequestType = NdisRequestQueryInformation;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_RECEIVE_BUFFER_SPACE;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->ReceiveBufferSpace);
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
IpxCloseNdis (Adapter);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now set the minimum lookahead size. The value we choose
|
|||
|
// here is the 128 needed for TDI indications, plus the size
|
|||
|
// of the IPX header, plus the largest extra header possible
|
|||
|
// (a SNAP header, 8 bytes), plus the largest higher-level
|
|||
|
// header (I think it is a Netbios datagram, 34 bytes).
|
|||
|
//
|
|||
|
// Adapt this based on higher-level bindings and
|
|||
|
// configured frame types.
|
|||
|
//
|
|||
|
|
|||
|
MinimumLookahead = 128 + sizeof(IPX_HEADER) + 8 + 34;
|
|||
|
IpxRequest.RequestType = NdisRequestSetInformation;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MinimumLookahead;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
|
|||
|
#define HACK
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
#if defined HACK
|
|||
|
KdPrint(("IPX: OID_GEN_CURRENT_LOOKAHEAD FAiled\n"));
|
|||
|
MinimumLookahead = 200;
|
|||
|
#else //!HACK
|
|||
|
IpxCloseNdis (Adapter);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
#endif //HACK
|
|||
|
// The above hack is to deal with NDIS's incorrect handling on
|
|||
|
// the LOOKAHEAD request.
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now query the link speed
|
|||
|
//
|
|||
|
|
|||
|
IpxRequest.RequestType = NdisRequestQueryInformation;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_LINK_SPEED;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MediumSpeed);
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS || Adapter->MediumSpeed == 0) {
|
|||
|
IpxCloseNdis (Adapter);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// For wan, specify our protocol ID and header format.
|
|||
|
// We don't query the medium subtype because we don't
|
|||
|
// case (since we require ethernet emulation).
|
|||
|
//
|
|||
|
|
|||
|
if (Adapter->MacInfo.MediumAsync) {
|
|||
|
|
|||
|
if (Adapter->BindSap != 0x8137) {
|
|||
|
*(UNALIGNED USHORT *)(&WanProtocolId[4]) = Adapter->BindSapNetworkOrder;
|
|||
|
}
|
|||
|
IpxRequest.RequestType = NdisRequestSetInformation;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_PROTOCOL_TYPE;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = WanProtocolId;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
IpxCloseNdis (Adapter);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
IpxRequest.RequestType = NdisRequestSetInformation;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_HEADER_FORMAT;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanHeaderFormat;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
IpxCloseNdis (Adapter);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now query the line count.
|
|||
|
//
|
|||
|
// NDIS returns 252
|
|||
|
|
|||
|
IpxRequest.RequestType = NdisRequestQueryInformation;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_LINE_COUNT;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &Adapter->WanNicIdCount;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
DbgPrint("NdisRequest WAN_LINE_COUNT failed with status (%x)\n",NdisStatus);
|
|||
|
Adapter->WanNicIdCount = 1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We dont need static info anymore. We just do it on demand...
|
|||
|
//
|
|||
|
// Allocating WAN line on demand is not done yet, the comment above
|
|||
|
// is BS.
|
|||
|
|
|||
|
// Adapter->WanNicIdCount = 1;
|
|||
|
|
|||
|
if (Adapter->WanNicIdCount == 0) {
|
|||
|
|
|||
|
IPX_DEBUG (NDIS, ("OID_WAN_LINE_COUNT returned 0 lines\n"));
|
|||
|
|
|||
|
IpxWriteOidErrorLog(
|
|||
|
Adapter->Device->DeviceObject,
|
|||
|
EVENT_TRANSPORT_QUERY_OID_FAILED,
|
|||
|
NDIS_STATUS_INVALID_DATA,
|
|||
|
AdapterString->Buffer,
|
|||
|
OID_WAN_LINE_COUNT);
|
|||
|
|
|||
|
IpxCloseNdis (Adapter);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// For 802.5 adapter's configured that way, we enable the
|
|||
|
// functional address (C0-00-00-80-00-00).
|
|||
|
//
|
|||
|
|
|||
|
if ((Adapter->MacInfo.MediumType == NdisMedium802_5) &&
|
|||
|
(Adapter->EnableFunctionalAddress)) {
|
|||
|
|
|||
|
//
|
|||
|
// For token-ring, we pass the last four bytes of the
|
|||
|
// Netbios functional address.
|
|||
|
//
|
|||
|
|
|||
|
IpxRequest.RequestType = NdisRequestSetInformation;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = FunctionalAddress;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
IpxCloseNdis (Adapter);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now query the MAC's optional characteristics.
|
|||
|
//
|
|||
|
|
|||
|
IpxRequest.RequestType = NdisRequestQueryInformation;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MacOptions;
|
|||
|
IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
IpxCloseNdis (Adapter);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
Adapter->MacInfo.CopyLookahead =
|
|||
|
((MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) != 0) ?
|
|||
|
TDI_RECEIVE_COPY_LOOKAHEAD : 0;
|
|||
|
Adapter->MacInfo.MacOptions = MacOptions;
|
|||
|
|
|||
|
|
|||
|
switch (Adapter->MacInfo.MediumType) {
|
|||
|
|
|||
|
case NdisMedium802_3:
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 14;
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 14;
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 14;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 14;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
|
|||
|
break;
|
|||
|
|
|||
|
case NdisMedium802_5:
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 17;
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 17;
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 17;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 17;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
|
|||
|
break;
|
|||
|
|
|||
|
case NdisMediumFddi:
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 16;
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 13;
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 16;
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 21;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 16;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 13;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 16;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 21;
|
|||
|
break;
|
|||
|
|
|||
|
case NdisMediumArcnet878_2:
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 3;
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 3;
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 3;
|
|||
|
Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 3;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 3;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 3;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 3;
|
|||
|
Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 3;
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If functional filtering is set, set the address
|
|||
|
// for the appropriate binding.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Now that everything is set up, we enable the filter
|
|||
|
// for packet reception.
|
|||
|
//
|
|||
|
|
|||
|
switch (Adapter->MacInfo.MediumType) {
|
|||
|
|
|||
|
case NdisMedium802_3:
|
|||
|
case NdisMediumFddi:
|
|||
|
case NdisMedium802_5:
|
|||
|
case NdisMediumArcnet878_2:
|
|||
|
|
|||
|
//
|
|||
|
// If we have a virtual network number we need to receive
|
|||
|
// broadcasts (either the router will be bound in which
|
|||
|
// case we want them, or we need to respond to rip requests
|
|||
|
// ourselves).
|
|||
|
//
|
|||
|
|
|||
|
PacketFilter = NDIS_PACKET_TYPE_DIRECTED;
|
|||
|
|
|||
|
if (Adapter->Device->VirtualNetworkNumber != 0) {
|
|||
|
|
|||
|
Adapter->BroadcastEnabled = TRUE;
|
|||
|
|
|||
|
// [MS]
|
|||
|
// New scheme: EnableBroadcastCount incremented for every client who
|
|||
|
// is interested in BCAST. Decrement this when someone
|
|||
|
// doesnt want it. If the count goes to 0, we remove this
|
|||
|
// quality in the adapter. At IPXDevice creation, we set it
|
|||
|
// to 0.
|
|||
|
//
|
|||
|
// Adapter->Device->EnableBroadcastCount = 1;
|
|||
|
PacketFilter |= NDIS_PACKET_TYPE_BROADCAST;
|
|||
|
|
|||
|
if ((Adapter->MacInfo.MediumType == NdisMedium802_5) && (Adapter->EnableFunctionalAddress)) {
|
|||
|
PacketFilter |= NDIS_PACKET_TYPE_FUNCTIONAL;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Adapter->BroadcastEnabled = FALSE;
|
|||
|
Adapter->Device->EnableBroadcastCount = 0;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
CTEAssert (FALSE);
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now fill in the NDIS_REQUEST.
|
|||
|
//
|
|||
|
|
|||
|
IpxRequest.RequestType = NdisRequestSetInformation;
|
|||
|
IpxRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
|
|||
|
IpxRequest.DATA.SET_INFORMATION.InformationBuffer = &PacketFilter;
|
|||
|
IpxRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
IpxCloseNdis (Adapter);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
} /* IpxInitializeNdis */
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IpxAddBroadcast(
|
|||
|
IN PDEVICE Device
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called when another reason for enabling
|
|||
|
broadcast reception is added. If it is the first, then
|
|||
|
reception on the card is enabled by queueing a call to
|
|||
|
IpxBroadcastOperation.
|
|||
|
|
|||
|
THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Device - The IPX device.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
++Device->EnableBroadcastCount;
|
|||
|
|
|||
|
if (Device->EnableBroadcastCount == 1) {
|
|||
|
|
|||
|
//
|
|||
|
// Broadcasts should be enabled.
|
|||
|
//
|
|||
|
|
|||
|
if (!Device->EnableBroadcastPending) {
|
|||
|
|
|||
|
if (Device->DisableBroadcastPending) {
|
|||
|
Device->ReverseBroadcastOperation = TRUE;
|
|||
|
} else {
|
|||
|
Device->EnableBroadcastPending = TRUE;
|
|||
|
IpxBroadcastOperation((PVOID)TRUE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} /* IpxAddBroadcast */
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IpxRemoveBroadcast(
|
|||
|
IN PDEVICE Device
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called when a reason for enabling
|
|||
|
broadcast reception is removed. If it is the last, then
|
|||
|
reception on the card is disabled by queueing a call to
|
|||
|
IpxBroadcastOperation.
|
|||
|
|
|||
|
THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Device - The IPX device.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
--Device->EnableBroadcastCount;
|
|||
|
|
|||
|
if (Device->EnableBroadcastCount <= 0) {
|
|||
|
|
|||
|
//
|
|||
|
// Broadcasts should be disabled.
|
|||
|
//
|
|||
|
|
|||
|
if (!Device->DisableBroadcastPending) {
|
|||
|
|
|||
|
if (Device->EnableBroadcastPending) {
|
|||
|
Device->ReverseBroadcastOperation = TRUE;
|
|||
|
} else {
|
|||
|
Device->DisableBroadcastPending = TRUE;
|
|||
|
IpxBroadcastOperation((PVOID)FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} /* IpxRemoveBroadcast */
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IpxBroadcastOperation(
|
|||
|
IN PVOID Parameter
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is used to change whether broadcast reception
|
|||
|
is enabled or disabled. It performs the requested operation
|
|||
|
on every adapter bound to by IPX.
|
|||
|
|
|||
|
This routine is called by a worker thread queued when a
|
|||
|
bind/unbind operation changes the broadcast state.
|
|||
|
|
|||
|
[ShreeM] New scheme: EnableBroadcastCount incremented for every client who
|
|||
|
is interested in BCAST. Decrement this when someone
|
|||
|
doesnt want it. If the count goes to 0, we remove this
|
|||
|
quality in the adapter. At IPXDevice creation, we set it
|
|||
|
to 0.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Parameter - TRUE if broadcasts should be enabled, FALSE
|
|||
|
if they should be disabled.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE Device = IpxDevice;
|
|||
|
BOOLEAN Enable = (BOOLEAN)Parameter;
|
|||
|
UINT i;
|
|||
|
PBINDING Binding;
|
|||
|
PADAPTER Adapter;
|
|||
|
ULONG PacketFilter;
|
|||
|
NDIS_REQUEST IpxRequest;
|
|||
|
NDIS_STRING AdapterName;
|
|||
|
CTELockHandle LockHandle;
|
|||
|
|
|||
|
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
|
|||
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|||
|
|
|||
|
IPX_DEBUG (NDIS, ("%s operation started\n", Enable ? "Enable" : "Disable"));
|
|||
|
|
|||
|
{
|
|||
|
ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
|
|||
|
|
|||
|
for (i = FIRST_REAL_BINDING; i <= Index; i++) {
|
|||
|
|
|||
|
Binding = NIC_ID_TO_BINDING(Device, i);
|
|||
|
if (Binding == NULL) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
Adapter = Binding->Adapter;
|
|||
|
if (Adapter->BroadcastEnabled == Enable) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (Enable) {
|
|||
|
if ((Adapter->MacInfo.MediumType == NdisMedium802_5) && (Adapter->EnableFunctionalAddress)) {
|
|||
|
PacketFilter = (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_FUNCTIONAL);
|
|||
|
} else {
|
|||
|
PacketFilter = (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST);
|
|||
|
}
|
|||
|
} else {
|
|||
|
PacketFilter = NDIS_PACKET_TYPE_DIRECTED;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now fill in the NDIS_REQUEST.
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory(&IpxRequest, sizeof(NDIS_REQUEST));
|
|||
|
|
|||
|
IpxRequest.RequestType = NdisRequestSetInformation;
|
|||
|
IpxRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
|
|||
|
IpxRequest.DATA.SET_INFORMATION.InformationBuffer = &PacketFilter;
|
|||
|
IpxRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
|
|||
|
|
|||
|
AdapterName.Buffer = Adapter->AdapterName;
|
|||
|
AdapterName.Length = (USHORT)Adapter->AdapterNameLength;
|
|||
|
AdapterName.MaximumLength = (USHORT)(Adapter->AdapterNameLength + sizeof(WCHAR));
|
|||
|
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|||
|
|
|||
|
(VOID)IpxSubmitNdisRequest (Adapter, &IpxRequest, &AdapterName);
|
|||
|
|
|||
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|||
|
|
|||
|
Adapter->BroadcastEnabled = Enable;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|||
|
|
|||
|
CTEGetLock (&Device->Lock, &LockHandle);
|
|||
|
|
|||
|
if (Enable) {
|
|||
|
|
|||
|
CTEAssert (Device->EnableBroadcastPending);
|
|||
|
Device->EnableBroadcastPending = FALSE;
|
|||
|
|
|||
|
if (Device->ReverseBroadcastOperation) {
|
|||
|
Device->ReverseBroadcastOperation = FALSE;
|
|||
|
Device->DisableBroadcastPending = TRUE;
|
|||
|
ExInitializeWorkItem(
|
|||
|
&Device->BroadcastOperationQueueItem,
|
|||
|
IpxBroadcastOperation,
|
|||
|
(PVOID)FALSE);
|
|||
|
ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
CTEAssert (Device->DisableBroadcastPending);
|
|||
|
Device->DisableBroadcastPending = FALSE;
|
|||
|
|
|||
|
if (Device->ReverseBroadcastOperation) {
|
|||
|
Device->ReverseBroadcastOperation = FALSE;
|
|||
|
Device->EnableBroadcastPending = TRUE;
|
|||
|
ExInitializeWorkItem(
|
|||
|
&Device->BroadcastOperationQueueItem,
|
|||
|
IpxBroadcastOperation,
|
|||
|
(PVOID)TRUE);
|
|||
|
ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
CTEFreeLock (&Device->Lock, LockHandle);
|
|||
|
|
|||
|
}/* IpxBroadcastOperation */
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IpxCloseNdis(
|
|||
|
IN PADAPTER Adapter
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine unbinds the transport from the NDIS interface and does
|
|||
|
any other work required to undo what was done in IpxInitializeNdis.
|
|||
|
It is written so that it can be called from within IpxInitializeNdis
|
|||
|
if it fails partway through.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Pointer to the device object for this driver.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NDIS_STATUS ndisStatus;
|
|||
|
|
|||
|
//
|
|||
|
// Close the NDIS binding.
|
|||
|
//
|
|||
|
|
|||
|
if (Adapter->NdisBindingHandle != (NDIS_HANDLE)NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// This event is used in case any of the NDIS requests
|
|||
|
// pend; we wait until it is set by the completion
|
|||
|
// routine, which also sets NdisRequestStatus.
|
|||
|
//
|
|||
|
|
|||
|
KeInitializeEvent(
|
|||
|
&Adapter->NdisRequestEvent,
|
|||
|
NotificationEvent,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
|
|||
|
NdisCloseAdapter(
|
|||
|
&ndisStatus,
|
|||
|
Adapter->NdisBindingHandle);
|
|||
|
|
|||
|
Adapter->NdisBindingHandle = (NDIS_HANDLE)NULL;
|
|||
|
|
|||
|
if (ndisStatus == NDIS_STATUS_PENDING) {
|
|||
|
|
|||
|
//
|
|||
|
// The completion routine will set NdisRequestStatus.
|
|||
|
//
|
|||
|
|
|||
|
KeWaitForSingleObject(
|
|||
|
&Adapter->NdisRequestEvent,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
TRUE,
|
|||
|
(PLARGE_INTEGER)NULL
|
|||
|
);
|
|||
|
|
|||
|
ndisStatus = Adapter->NdisRequestStatus;
|
|||
|
|
|||
|
KeResetEvent(
|
|||
|
&Adapter->NdisRequestEvent
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// We ignore ndisStatus.
|
|||
|
//
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#if 0
|
|||
|
if (Adapter->SendPacketPoolHandle != NULL) {
|
|||
|
NdisFreePacketPool (Adapter->SendPacketPoolHandle);
|
|||
|
}
|
|||
|
|
|||
|
if (Adapter->ReceivePacketPoolHandle != NULL) {
|
|||
|
NdisFreePacketPool (Adapter->ReceivePacketPoolHandle);
|
|||
|
}
|
|||
|
|
|||
|
if (Adapter->NdisBufferPoolHandle != NULL) {
|
|||
|
NdisFreeBufferPool (Adapter->NdisBufferPoolHandle);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
} /* IpxCloseNdis */
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IpxOpenAdapterComplete(
|
|||
|
IN NDIS_HANDLE BindingContext,
|
|||
|
IN NDIS_STATUS NdisStatus,
|
|||
|
IN NDIS_STATUS OpenErrorStatus
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called by NDIS to indicate that an open adapter
|
|||
|
is complete. Since we only ever have one outstanding, and then only
|
|||
|
during initialization, all we do is record the status and set
|
|||
|
the event to signalled to unblock the initialization thread.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BindingContext - Pointer to the device object for this driver.
|
|||
|
|
|||
|
NdisStatus - The request completion code.
|
|||
|
|
|||
|
OpenErrorStatus - More status information.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PADAPTER Adapter = (PADAPTER)BindingContext;
|
|||
|
|
|||
|
Adapter->NdisRequestStatus = NdisStatus;
|
|||
|
Adapter->OpenErrorStatus = OpenErrorStatus;
|
|||
|
|
|||
|
KeSetEvent(
|
|||
|
&Adapter->NdisRequestEvent,
|
|||
|
0L,
|
|||
|
FALSE);
|
|||
|
|
|||
|
} /* IpxOpenAdapterComplete */
|
|||
|
|
|||
|
VOID
|
|||
|
IpxCloseAdapterComplete(
|
|||
|
IN NDIS_HANDLE BindingContext,
|
|||
|
IN NDIS_STATUS NdisStatus
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called by NDIS to indicate that a close adapter
|
|||
|
is complete. Currently we don't close adapters, so this is not
|
|||
|
a problem.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BindingContext - Pointer to the device object for this driver.
|
|||
|
|
|||
|
NdisStatus - The request completion code.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PADAPTER Adapter = (PADAPTER)BindingContext;
|
|||
|
|
|||
|
Adapter->NdisRequestStatus = NdisStatus;
|
|||
|
|
|||
|
KeSetEvent(
|
|||
|
&Adapter->NdisRequestEvent,
|
|||
|
0L,
|
|||
|
FALSE);
|
|||
|
|
|||
|
} /* IpxCloseAdapterComplete */
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IpxResetComplete(
|
|||
|
IN NDIS_HANDLE BindingContext,
|
|||
|
IN NDIS_STATUS NdisStatus
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called by NDIS to indicate that a reset adapter
|
|||
|
is complete. Currently we don't reset adapters, so this is not
|
|||
|
a problem.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BindingContext - Pointer to the device object for this driver.
|
|||
|
|
|||
|
NdisStatus - The request completion code.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UNREFERENCED_PARAMETER(BindingContext);
|
|||
|
UNREFERENCED_PARAMETER(NdisStatus);
|
|||
|
|
|||
|
} /* IpxResetComplete */
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IpxRequestComplete(
|
|||
|
IN NDIS_HANDLE BindingContext,
|
|||
|
IN PNDIS_REQUEST NdisRequest,
|
|||
|
IN NDIS_STATUS NdisStatus
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called by NDIS to indicate that a request is complete.
|
|||
|
Since we only ever have one request outstanding, and then only
|
|||
|
during initialization, all we do is record the status and set
|
|||
|
the event to signalled to unblock the initialization thread.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BindingContext - Pointer to the device object for this driver.
|
|||
|
|
|||
|
NdisRequest - The object describing the request.
|
|||
|
|
|||
|
NdisStatus - The request completion code.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PADAPTER Adapter = (PADAPTER)BindingContext;
|
|||
|
PIPX_NDIS_REQUEST IpxRequest = (PIPX_NDIS_REQUEST) NdisRequest;
|
|||
|
|
|||
|
IpxRequest->Status = NdisStatus;
|
|||
|
|
|||
|
KeSetEvent(
|
|||
|
&IpxRequest->NdisRequestEvent,
|
|||
|
0L,
|
|||
|
FALSE);
|
|||
|
|
|||
|
} /* IpxRequestComplete */
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IpxStatus(
|
|||
|
IN NDIS_HANDLE NdisBindingContext,
|
|||
|
IN NDIS_STATUS NdisStatus,
|
|||
|
IN PVOID StatusBuffer,
|
|||
|
IN UINT StatusBufferSize
|
|||
|
)
|
|||
|
{
|
|||
|
PADAPTER Adapter, TmpAdapter;
|
|||
|
|
|||
|
PNDIS_WAN_LINE_UP LineUp;
|
|||
|
PNDIS_WAN_LINE_DOWN LineDown;
|
|||
|
PIPXCP_CONFIGURATION Configuration; // contains ipx net and node
|
|||
|
|
|||
|
BOOLEAN UpdateLineUp;
|
|||
|
PBINDING Binding, TmpBinding;
|
|||
|
PDEVICE Device;
|
|||
|
PADDRESS Address;
|
|||
|
ULONG CurrentHash;
|
|||
|
PIPX_ROUTE_ENTRY RouteEntry;
|
|||
|
PNDIS_BUFFER NdisBuffer;
|
|||
|
PNWLINK_ACTION NwlinkAction;
|
|||
|
PIPX_ADDRESS_DATA IpxAddressData;
|
|||
|
PREQUEST Request;
|
|||
|
UINT BufferLength;
|
|||
|
IPX_LINE_INFO LineInfo;
|
|||
|
ULONG Segment;
|
|||
|
ULONG LinkSpeed;
|
|||
|
PLIST_ENTRY p;
|
|||
|
NTSTATUS Status;
|
|||
|
#ifdef SUNDOWN
|
|||
|
// To avoid a warning when Binding->NicId = i;
|
|||
|
// Assume we have no more than 16-bit number of binding.
|
|||
|
USHORT i, j;
|
|||
|
#else
|
|||
|
UINT i, j;
|
|||
|
#endif
|
|||
|
IPX_DEFINE_LOCK_HANDLE (LockHandle)
|
|||
|
IPX_DEFINE_LOCK_HANDLE (OldIrq)
|
|||
|
NTSTATUS ntStatus;
|
|||
|
CTEEvent *Event;
|
|||
|
KIRQL irql;
|
|||
|
|
|||
|
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
|
|||
|
Adapter = (PADAPTER)NdisBindingContext;
|
|||
|
|
|||
|
IpxReferenceAdapter(Adapter);
|
|||
|
|
|||
|
Device = Adapter->Device;
|
|||
|
|
|||
|
switch (NdisStatus) {
|
|||
|
|
|||
|
case NDIS_STATUS_WAN_LINE_UP:
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If the line is already up, then we are just getting
|
|||
|
// a change in line conditions, and the IPXCP_CONFIGURATION
|
|||
|
// information is not included. If it turns out we need
|
|||
|
// all the info, we check the size again later.
|
|||
|
//
|
|||
|
|
|||
|
if (StatusBufferSize < sizeof(NDIS_WAN_LINE_UP)) {
|
|||
|
IPX_DEBUG (WAN, ("Line up, status buffer size wrong %d/%d\n", StatusBufferSize, sizeof(NDIS_WAN_LINE_UP)));
|
|||
|
goto error_no_lock;
|
|||
|
}
|
|||
|
|
|||
|
LineUp = (PNDIS_WAN_LINE_UP)StatusBuffer;
|
|||
|
|
|||
|
//
|
|||
|
// We scan through the adapter's NIC ID range looking
|
|||
|
// for an active binding with the same remote address.
|
|||
|
//
|
|||
|
|
|||
|
UpdateLineUp = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// See if this is a new lineup or not
|
|||
|
//
|
|||
|
*((ULONG UNALIGNED *)(&Binding)) =
|
|||
|
*((ULONG UNALIGNED *)(&LineUp->LocalAddress[2]));
|
|||
|
|
|||
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|||
|
|
|||
|
if (Binding != NULL) {
|
|||
|
UpdateLineUp = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if (LineUp->ProtocolType != Adapter->BindSap) {
|
|||
|
IPX_DEBUG (WAN, ("Line up, wrong protocol type %lx\n", LineUp->ProtocolType));
|
|||
|
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|||
|
goto error_no_lock;
|
|||
|
}
|
|||
|
|
|||
|
Configuration = (PIPXCP_CONFIGURATION)LineUp->ProtocolBuffer;
|
|||
|
|
|||
|
//
|
|||
|
// PNP_POWER - We hold the exclusive lock to the binding array (thru both the device and adapter)
|
|||
|
// and the reference to the adapter at this point.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// If this line was previously down, create a new binding
|
|||
|
// if needed.
|
|||
|
//
|
|||
|
|
|||
|
if (!UpdateLineUp) {
|
|||
|
|
|||
|
//
|
|||
|
// We look for a binding that is allocated but down, if
|
|||
|
// we can't find that then we look for any empty spot in
|
|||
|
// the adapter's NIC ID range and allocate a binding in it.
|
|||
|
// Since we always allocate this way, the allocated
|
|||
|
// bindings are all clumped at the beginning and once
|
|||
|
// we find a NULL spot we know there are no more
|
|||
|
// allocated ones.
|
|||
|
//
|
|||
|
// We keep track of the first binding on this adapter
|
|||
|
// in TmpBinding in case we need config info from it.
|
|||
|
//
|
|||
|
|
|||
|
TmpBinding = NULL;
|
|||
|
|
|||
|
IPX_GET_LOCK (&Device->Lock, &LockHandle);
|
|||
|
|
|||
|
for (i = Adapter->FirstWanNicId;
|
|||
|
i <= Adapter->LastWanNicId;
|
|||
|
i++) {
|
|||
|
Binding = NIC_ID_TO_BINDING(Device, i);
|
|||
|
if (TmpBinding == NULL) {
|
|||
|
TmpBinding = Binding;
|
|||
|
}
|
|||
|
|
|||
|
if ((Binding == NULL) ||
|
|||
|
(!Binding->LineUp)) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (i > Adapter->LastWanNicId) {
|
|||
|
IPX_FREE_LOCK (&Device->Lock, LockHandle);
|
|||
|
IPX_DEBUG (WAN, ("Line up, no WAN binding available\n"));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (Binding == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// We need to allocate one.
|
|||
|
//
|
|||
|
|
|||
|
CTEAssert (TmpBinding != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// CreateBinding does an InterLockedPop with the DeviceLock.
|
|||
|
// So, release the lock here.
|
|||
|
//
|
|||
|
IPX_FREE_LOCK (&Device->Lock, LockHandle);
|
|||
|
Status = IpxCreateBinding(
|
|||
|
Device,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
Adapter->AdapterName,
|
|||
|
&Binding);
|
|||
|
|
|||
|
if (Status != STATUS_SUCCESS) {
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|||
|
IpxWriteGeneralErrorLog(
|
|||
|
(PVOID)IpxDevice->DeviceObject,
|
|||
|
EVENT_TRANSPORT_RESOURCE_POOL,
|
|||
|
816,
|
|||
|
Status,
|
|||
|
L"IpxStatus: failed to create wan binding",
|
|||
|
0,
|
|||
|
NULL);
|
|||
|
DbgPrint("IPX: IpxCreateBinding on wan binding failed with status %x\n.",Status);
|
|||
|
IPX_DEBUG (WAN, ("Line up, could not create WAN binding\n"));
|
|||
|
goto error_no_lock;
|
|||
|
}
|
|||
|
|
|||
|
IPX_GET_LOCK (&Device->Lock, &LockHandle);
|
|||
|
//
|
|||
|
// Binding->AllRouteXXX doesn't matter for WAN.
|
|||
|
//
|
|||
|
|
|||
|
Binding->FrameType = ISN_FRAME_TYPE_ETHERNET_II;
|
|||
|
Binding->SendFrameHandler = IpxSendFrameWanEthernetII;
|
|||
|
++Adapter->BindingCount;
|
|||
|
Binding->Adapter = Adapter;
|
|||
|
|
|||
|
Binding->NicId = i;
|
|||
|
|
|||
|
/*
|
|||
|
Abandoning this fix in favor of checking for null binding all over.
|
|||
|
|
|||
|
//
|
|||
|
// Nt5.0 NDISWAN tells us that there are 1000 ports configured, we
|
|||
|
// take it one line up at a time... [ShreeM]
|
|||
|
//
|
|||
|
Device->HighestExternalNicId += 1;
|
|||
|
Device->ValidBindings += 1;
|
|||
|
Device->BindingCount += 1;
|
|||
|
Device->SapNicCount++;
|
|||
|
*/
|
|||
|
INSERT_BINDING(Device, i, Binding);
|
|||
|
|
|||
|
//
|
|||
|
// Other fields are filled in below.
|
|||
|
//
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This is not an update, so note that the line is active.
|
|||
|
//
|
|||
|
// [FW] Binding->LineUp = TRUE;
|
|||
|
Binding->LineUp = LINE_UP;
|
|||
|
|
|||
|
if (Configuration->ConnectionClient == 1) {
|
|||
|
Binding->DialOutAsync = TRUE;
|
|||
|
} else {
|
|||
|
Binding->DialOutAsync = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Keep track of the highest NIC ID that we should
|
|||
|
// send type 20s out on.
|
|||
|
//
|
|||
|
|
|||
|
if (i > (UINT)MIN (Device->MaxBindings, Device->HighestType20NicId)) {
|
|||
|
|
|||
|
if ((Binding->DialOutAsync) ||
|
|||
|
((Device->DisableDialinNetbios & 0x01) == 0)) {
|
|||
|
|
|||
|
Device->HighestType20NicId = i;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We could error out below, trying to insert this network number. In RipShortTimeout
|
|||
|
// we dont check for LineUp when calculating the tick counts; set this before the insert
|
|||
|
// attempt.
|
|||
|
//
|
|||
|
Binding->MediumSpeed = LineUp->LinkSpeed;
|
|||
|
|
|||
|
IPX_FREE_LOCK (&Device->Lock, LockHandle);
|
|||
|
|
|||
|
//
|
|||
|
// [FW] No need to update these if this flag is on since these values will be
|
|||
|
// provided with IPX_WAN_CONFIG_DONE ioctl; instead we zero out the fields so that
|
|||
|
// IPXWAN packets have proper source addresses.
|
|||
|
//
|
|||
|
if (Device->ForwarderBound &&
|
|||
|
Configuration->IpxwanConfigRequired) {
|
|||
|
Binding->LocalAddress.NetworkAddress = 0;
|
|||
|
RtlZeroMemory (Binding->LocalAddress.NodeAddress, 6);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Add a router entry for this net if there is no router.
|
|||
|
// We want the number of ticks for a 576-byte frame,
|
|||
|
// given the link speed in 100 bps units, so we calculate
|
|||
|
// as:
|
|||
|
//
|
|||
|
// seconds 18.21 ticks 4608 bits
|
|||
|
// --------------------- * ----------- * ---------
|
|||
|
// link_speed * 100 bits second frame
|
|||
|
//
|
|||
|
// to get the formula
|
|||
|
//
|
|||
|
// ticks/frame = 839 / link_speed.
|
|||
|
//
|
|||
|
// We add link_speed to the numerator also to ensure
|
|||
|
// that the value is at least 1.
|
|||
|
//
|
|||
|
|
|||
|
if ((!Device->UpperDriverBound[IDENTIFIER_RIP]) &&
|
|||
|
(*(UNALIGNED ULONG *)Configuration->Network != 0)) {
|
|||
|
if (RipInsertLocalNetwork(
|
|||
|
*(UNALIGNED ULONG *)Configuration->Network,
|
|||
|
Binding->NicId,
|
|||
|
Adapter->NdisBindingHandle,
|
|||
|
(USHORT)((839 + LineUp->LinkSpeed) / LineUp->LinkSpeed)) != STATUS_SUCCESS) {
|
|||
|
//
|
|||
|
// This means we couldn't allocate memory, or
|
|||
|
// the entry already existed. If it already
|
|||
|
// exists we can ignore it for the moment.
|
|||
|
//
|
|||
|
// Now it will succeed if the network exists.
|
|||
|
//
|
|||
|
|
|||
|
IPX_DEBUG (WAN, ("Line up, could not insert local network\n"));
|
|||
|
// [FW] Binding->LineUp = FALSE;
|
|||
|
Binding->LineUp = LINE_DOWN;
|
|||
|
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|||
|
goto error_no_lock;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Update our addresses.
|
|||
|
//
|
|||
|
Binding->LocalAddress.NetworkAddress = *(UNALIGNED ULONG *)Configuration->Network;
|
|||
|
RtlCopyMemory (Binding->LocalAddress.NodeAddress, Configuration->LocalNode, 6);
|
|||
|
RtlCopyMemory (Binding->WanRemoteNode, Configuration->RemoteNode, 6);
|
|||
|
|
|||
|
//
|
|||
|
// Update the device node and all the address
|
|||
|
// nodes if we have only one bound, or this is
|
|||
|
// binding one.
|
|||
|
//
|
|||
|
|
|||
|
if (!Device->VirtualNetwork) {
|
|||
|
|
|||
|
if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
|
|||
|
Device->SourceAddress.NetworkAddress = *(UNALIGNED ULONG *)(Configuration->Network);
|
|||
|
RtlCopyMemory (Device->SourceAddress.NodeAddress, Configuration->LocalNode, 6);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Scan through all the addresses that exist and modify
|
|||
|
// their pre-constructed local IPX address to reflect
|
|||
|
// the new local net and node.
|
|||
|
//
|
|||
|
|
|||
|
IPX_GET_LOCK (&Device->Lock, &LockHandle);
|
|||
|
|
|||
|
for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
|
|||
|
|
|||
|
for (p = Device->AddressDatabases[CurrentHash].Flink;
|
|||
|
p != &Device->AddressDatabases[CurrentHash];
|
|||
|
p = p->Flink) {
|
|||
|
|
|||
|
Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
|
|||
|
|
|||
|
Address->LocalAddress.NetworkAddress = *(UNALIGNED ULONG *)Configuration->Network;
|
|||
|
RtlCopyMemory (Address->LocalAddress.NodeAddress, Configuration->LocalNode, 6);
|
|||
|
}
|
|||
|
}
|
|||
|
IPX_FREE_LOCK (&Device->Lock, LockHandle);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return the binding context for this puppy!
|
|||
|
//
|
|||
|
*((ULONG UNALIGNED *)(&LineUp->LocalAddress[2])) =
|
|||
|
*((ULONG UNALIGNED *)(&Binding));
|
|||
|
|
|||
|
RtlCopyMemory (Binding->LocalMacAddress.Address, LineUp->LocalAddress, 6);
|
|||
|
RtlCopyMemory (Binding->RemoteMacAddress.Address, LineUp->RemoteAddress, 6);
|
|||
|
|
|||
|
//
|
|||
|
// Reset this since the line just came up.
|
|||
|
//
|
|||
|
|
|||
|
Binding->WanInactivityCounter = 0;
|
|||
|
|
|||
|
//
|
|||
|
// [FW] Update the InterfaceIndex and ConnectionId.
|
|||
|
//
|
|||
|
Binding->InterfaceIndex = Configuration->InterfaceIndex;
|
|||
|
Binding->ConnectionId = Configuration->ConnectionId;
|
|||
|
Binding->IpxwanConfigRequired = Configuration->IpxwanConfigRequired;
|
|||
|
|
|||
|
//
|
|||
|
// [FW] We need to keep track of WAN inactivity counters ourselves.
|
|||
|
// Every minute, the wan inactivity counters are incremented for all
|
|||
|
// UP WAN lines.
|
|||
|
//
|
|||
|
IPX_GET_LOCK (&Device->Lock, &LockHandle);
|
|||
|
if (Device->UpWanLineCount == 0) {
|
|||
|
}
|
|||
|
|
|||
|
Device->UpWanLineCount++;
|
|||
|
IPX_FREE_LOCK (&Device->Lock, LockHandle);
|
|||
|
}
|
|||
|
|
|||
|
LinkSpeed = LineUp->LinkSpeed;
|
|||
|
|
|||
|
//
|
|||
|
// Scan through bindings to update Device->LinkSpeed.
|
|||
|
// If SingleNetworkActive is set, we only count WAN
|
|||
|
// bindings when doing this (although it is unlikely
|
|||
|
// a LAN binding would be the winner).
|
|||
|
//
|
|||
|
// Update other device information?
|
|||
|
//
|
|||
|
|
|||
|
for (i = FIRST_REAL_BINDING; i <= Device->ValidBindings; i++) {
|
|||
|
if (TmpBinding = NIC_ID_TO_BINDING(Device, i)) {
|
|||
|
TmpAdapter = TmpBinding->Adapter;
|
|||
|
if (TmpBinding->LineUp &&
|
|||
|
(!Device->SingleNetworkActive || TmpAdapter->MacInfo.MediumAsync) &&
|
|||
|
(TmpBinding->MediumSpeed < LinkSpeed)) {
|
|||
|
LinkSpeed = TmpBinding->MediumSpeed;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Release the lock after incrementing the reference count
|
|||
|
//
|
|||
|
IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|||
|
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|||
|
|
|||
|
Device->LinkSpeed = LinkSpeed;
|
|||
|
|
|||
|
if ((Adapter->ConfigMaxPacketSize == 0) ||
|
|||
|
(LineUp->MaximumTotalSize < Adapter->ConfigMaxPacketSize)) {
|
|||
|
Binding->MaxSendPacketSize = LineUp->MaximumTotalSize;
|
|||
|
} else {
|
|||
|
Binding->MaxSendPacketSize = Adapter->ConfigMaxPacketSize;
|
|||
|
}
|
|||
|
MacInitializeBindingInfo (Binding, Adapter);
|
|||
|
|
|||
|
//
|
|||
|
// [FW] If the IpxwanConfigRequired flag is true, we don't inform
|
|||
|
// the upper layers until IPXWAN sends down the ioctl to do so.
|
|||
|
//
|
|||
|
// Inform IpxWan only if this is not an Update; it will be an update in
|
|||
|
// the case of multilink. In fact, do not access the Configuration param in
|
|||
|
// case UpdateLineUp is TRUE.
|
|||
|
//
|
|||
|
if (!UpdateLineUp &&
|
|||
|
Configuration->IpxwanConfigRequired) {
|
|||
|
|
|||
|
IPX_DEBUG(WAN, ("IPXWAN configuration required on LineUp: %lx\n", LineUp));
|
|||
|
CTEAssert(!UpdateLineUp);
|
|||
|
Binding->LineUp = LINE_CONFIG;
|
|||
|
goto InformIpxWan;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Tell FWD if it wants to know [Shreem]
|
|||
|
//
|
|||
|
Binding->PastAutoDetection = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// We dont give lineups; instead indicate only if the PnP reserved address
|
|||
|
// changed to SPX. NB gets all PnP indications with the reserved address case
|
|||
|
// marked out.
|
|||
|
//
|
|||
|
Event = CTEAllocMem( sizeof(CTEEvent) );
|
|||
|
if ( Event ) {
|
|||
|
CTEInitEvent(Event, LineUpOnWorkerThread);
|
|||
|
CTEScheduleEvent(Event, Binding);
|
|||
|
ntStatus = STATUS_PENDING;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
{
|
|||
|
IPX_PNP_INFO NBPnPInfo;
|
|||
|
|
|||
|
if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == FIRST_REAL_BINDING)) {
|
|||
|
|
|||
|
//
|
|||
|
// NB's reserved address changed.
|
|||
|
//
|
|||
|
NBPnPInfo.NewReservedAddress = TRUE;
|
|||
|
|
|||
|
if (!Device->VirtualNetwork) {
|
|||
|
//
|
|||
|
// Let SPX know because it fills in its own headers.
|
|||
|
//
|
|||
|
if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
|
|||
|
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
|
|||
|
IPX_PNP_INFO IpxPnPInfo;
|
|||
|
|
|||
|
IpxPnPInfo.NewReservedAddress = TRUE;
|
|||
|
IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
|
|||
|
IpxPnPInfo.FirstORLastDevice = FALSE;
|
|||
|
|
|||
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|||
|
RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
|
|||
|
NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|||
|
|
|||
|
//
|
|||
|
// give the PnP indication
|
|||
|
//
|
|||
|
(*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
|
|||
|
IPX_PNP_ADDRESS_CHANGE,
|
|||
|
&IpxPnPInfo);
|
|||
|
|
|||
|
IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADDRESS_CHANGED to SPX: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
NBPnPInfo.NewReservedAddress = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (Device->UpperDriverBound[IDENTIFIER_NB]) {
|
|||
|
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
|
|||
|
|
|||
|
Binding->IsnInformed[IDENTIFIER_NB] = TRUE;
|
|||
|
|
|||
|
NBPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
|
|||
|
NBPnPInfo.LineInfo.MaximumPacketSize =
|
|||
|
Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
|
|||
|
NBPnPInfo.LineInfo.MaximumSendSize =
|
|||
|
Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
|
|||
|
NBPnPInfo.LineInfo.MacOptions = Device->MacOptions;
|
|||
|
|
|||
|
NBPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
|
|||
|
NBPnPInfo.FirstORLastDevice = FALSE;
|
|||
|
|
|||
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|||
|
RtlCopyMemory(NBPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
|
|||
|
NIC_HANDLE_FROM_NIC(NBPnPInfo.NicHandle, Binding->NicId);
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|||
|
|
|||
|
//
|
|||
|
// give the PnP indication
|
|||
|
//
|
|||
|
(*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
|
|||
|
IPX_PNP_ADD_DEVICE,
|
|||
|
&NBPnPInfo);
|
|||
|
|
|||
|
IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADD_DEVICE (lineup) to NB: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Register this address with the TDI clients.
|
|||
|
//
|
|||
|
RtlCopyMemory (Device->TdiRegistrationAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
|
|||
|
|
|||
|
if ((ntStatus = TdiRegisterNetAddress(
|
|||
|
Device->TdiRegistrationAddress,
|
|||
|
#if defined(_PNP_POWER_)
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
#endif _PNP_POWER_
|
|||
|
&Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
|
|||
|
|
|||
|
IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
|
|||
|
}
|
|||
|
}
|
|||
|
*/
|
|||
|
//
|
|||
|
// Indicate to the upper drivers.
|
|||
|
//
|
|||
|
LineInfo.LinkSpeed = LineUp->LinkSpeed;
|
|||
|
LineInfo.MaximumPacketSize = LineUp->MaximumTotalSize - 14;
|
|||
|
LineInfo.MaximumSendSize = LineUp->MaximumTotalSize - 14;
|
|||
|
LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
|
|||
|
|
|||
|
//
|
|||
|
// Give line up to RIP as it is not PnP aware.
|
|||
|
// Give lineup to FWD only if it opened this adapter first.
|
|||
|
//
|
|||
|
if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
|
|||
|
|
|||
|
//
|
|||
|
// Line status, after lineup.
|
|||
|
//
|
|||
|
if (UpdateLineUp) {
|
|||
|
//
|
|||
|
// was the lineup given earlier? if not, then dont send this up.
|
|||
|
//
|
|||
|
if (Binding->IsnInformed[IDENTIFIER_RIP]) {
|
|||
|
CTEAssert(Binding->FwdAdapterContext);
|
|||
|
|
|||
|
(*Device->UpperDrivers[IDENTIFIER_RIP].LineUpHandler)(
|
|||
|
Binding->NicId,
|
|||
|
&LineInfo,
|
|||
|
NdisMediumWan,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
Binding->IsnInformed[IDENTIFIER_RIP] = TRUE;
|
|||
|
(*Device->UpperDrivers[IDENTIFIER_RIP].LineUpHandler)(
|
|||
|
Binding->NicId,
|
|||
|
&LineInfo,
|
|||
|
NdisMediumWan,
|
|||
|
Configuration);
|
|||
|
}
|
|||
|
}
|
|||
|
if (!UpdateLineUp) {
|
|||
|
|
|||
|
if ((Device->SingleNetworkActive) &&
|
|||
|
(Configuration->ConnectionClient == 1)) {
|
|||
|
//
|
|||
|
// Drop all entries in the database if rip is not bound.
|
|||
|
//
|
|||
|
|
|||
|
if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
|
|||
|
RipDropRemoteEntries();
|
|||
|
}
|
|||
|
|
|||
|
Device->ActiveNetworkWan = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Find a queued line change and complete it.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
if ((p = ExInterlockedRemoveHeadList(
|
|||
|
&Device->LineChangeQueue,
|
|||
|
&Device->Lock)) != NULL) {
|
|||
|
|
|||
|
Request = LIST_ENTRY_TO_REQUEST(p);
|
|||
|
|
|||
|
IoAcquireCancelSpinLock( &irql );
|
|||
|
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
|
|||
|
IoReleaseCancelSpinLock( irql );
|
|||
|
REQUEST_STATUS(Request) = STATUS_SUCCESS;
|
|||
|
IpxCompleteRequest (Request);
|
|||
|
IpxFreeRequest (Device, Request);
|
|||
|
|
|||
|
IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we have a virtual net, do a broadcast now so
|
|||
|
// the router on the other end will know about us.
|
|||
|
//
|
|||
|
// Use RipSendResponse, and do it even
|
|||
|
// if SingleNetworkActive is FALSE??
|
|||
|
//
|
|||
|
|
|||
|
if (Device->RipResponder && (Configuration->ConnectionClient == 1)) {
|
|||
|
DbgPrint("IPX:Sending RIP Response for Virtual Net %x\n",Device->VirtualNetworkNumber);
|
|||
|
(VOID)RipQueueRequest (Device->VirtualNetworkNumber, RIP_RESPONSE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Find a queued address notify and complete it.
|
|||
|
// If WanGlobalNetworkNumber is TRUE, we only do
|
|||
|
// this when the first dialin line comes up.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
if ((!Device->WanGlobalNetworkNumber ||
|
|||
|
(!Device->GlobalNetworkIndicated && !Binding->DialOutAsync))
|
|||
|
&&
|
|||
|
((p = ExInterlockedRemoveHeadList(
|
|||
|
&Device->AddressNotifyQueue,
|
|||
|
&Device->Lock)) != NULL)) {
|
|||
|
|
|||
|
if (Device->WanGlobalNetworkNumber) {
|
|||
|
Device->GlobalWanNetwork = Binding->LocalAddress.NetworkAddress;
|
|||
|
Device->GlobalNetworkIndicated = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
Request = LIST_ENTRY_TO_REQUEST(p);
|
|||
|
NdisBuffer = REQUEST_NDIS_BUFFER(Request);
|
|||
|
NdisQueryBufferSafe (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength, HighPagePriority);
|
|||
|
|
|||
|
if (NwlinkAction != NULL) {
|
|||
|
|
|||
|
IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
|
|||
|
|
|||
|
if (Device->WanGlobalNetworkNumber) {
|
|||
|
IpxAddressData->adapternum = Device->SapNicCount - 1;
|
|||
|
} else {
|
|||
|
IpxAddressData->adapternum = Binding->NicId - 1;
|
|||
|
}
|
|||
|
*(UNALIGNED ULONG *)IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
|
|||
|
RtlCopyMemory(IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
|
|||
|
IpxAddressData->wan = TRUE;
|
|||
|
IpxAddressData->status = TRUE;
|
|||
|
IpxAddressData->maxpkt = Binding->AnnouncedMaxDatagramSize;
|
|||
|
IpxAddressData->linkspeed = Binding->MediumSpeed;
|
|||
|
|
|||
|
REQUEST_STATUS(Request) = STATUS_SUCCESS;
|
|||
|
} else {
|
|||
|
REQUEST_STATUS(Request) = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
IoAcquireCancelSpinLock( &irql );
|
|||
|
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
|
|||
|
IoReleaseCancelSpinLock( irql );
|
|||
|
IpxCompleteRequest (Request);
|
|||
|
IpxFreeRequest (Device, Request);
|
|||
|
|
|||
|
IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
|
|||
|
}
|
|||
|
|
|||
|
InformIpxWan:
|
|||
|
Binding->fInfoIndicated = FALSE;
|
|||
|
//
|
|||
|
// Tell FWD if it wants to know [Shreem]
|
|||
|
//
|
|||
|
Binding->PastAutoDetection = TRUE;
|
|||
|
|
|||
|
if ((p = ExInterlockedRemoveHeadList(
|
|||
|
&Device->NicNtfQueue,
|
|||
|
&Device->Lock)) != NULL)
|
|||
|
{
|
|||
|
Request = LIST_ENTRY_TO_REQUEST(p);
|
|||
|
|
|||
|
IPX_DEBUG(WAN, ("IpxStatus: WAN LINE UP\n"));
|
|||
|
Status = GetNewNics(Device, Request, FALSE, NULL, 0, TRUE);
|
|||
|
if (Status == STATUS_PENDING)
|
|||
|
{
|
|||
|
IPX_DEBUG(WAN, ("WANLineUp may not be responding properly\n"));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IoAcquireCancelSpinLock(&OldIrq);
|
|||
|
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
|
|||
|
IoReleaseCancelSpinLock(OldIrq);
|
|||
|
|
|||
|
REQUEST_STATUS(Request) = Status;
|
|||
|
IpxCompleteRequest (Request);
|
|||
|
IpxFreeRequest (Device, Request);
|
|||
|
IpxDereferenceDevice (Device, DREF_NIC_NOTIFY);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|||
|
{
|
|||
|
int kk;
|
|||
|
PBINDING pb = NULL;
|
|||
|
for (kk= LOOPBACK_NIC_ID; kk < Device->ValidBindings; kk++) {
|
|||
|
pb = NIC_ID_TO_BINDING(Device, kk);
|
|||
|
if (pb) {
|
|||
|
if (pb->NicId != kk) {
|
|||
|
DbgBreakPoint();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case NDIS_STATUS_WAN_LINE_DOWN:
|
|||
|
|
|||
|
if (StatusBufferSize < sizeof(NDIS_WAN_LINE_DOWN)) {
|
|||
|
IPX_DEBUG (WAN, ("Line down, status buffer size wrong %d/%d\n", StatusBufferSize, sizeof(NDIS_WAN_LINE_DOWN)));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
LineDown = (PNDIS_WAN_LINE_DOWN)StatusBuffer;
|
|||
|
|
|||
|
*((ULONG UNALIGNED*)(&Binding)) = *((ULONG UNALIGNED*)(&LineDown->LocalAddress[2]));
|
|||
|
|
|||
|
CTEAssert(Binding != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Note that the WAN line is down.
|
|||
|
//
|
|||
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|||
|
|
|||
|
// [FW] Binding->LineUp = FALSE;
|
|||
|
Binding->LineUp = LINE_DOWN;
|
|||
|
|
|||
|
//
|
|||
|
// PNP_POWER - we hold the exclusive lock to the binding
|
|||
|
// and reference to the adapter at this point.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Keep track of the highest NIC ID that we should
|
|||
|
// send type 20s out on.
|
|||
|
//
|
|||
|
|
|||
|
IPX_GET_LOCK (&Device->Lock, &LockHandle);
|
|||
|
|
|||
|
if (Binding->NicId == MIN (Device->MaxBindings, Device->HighestType20NicId)) {
|
|||
|
|
|||
|
//
|
|||
|
// This was the old limit, so we have to scan
|
|||
|
// backwards to update it -- we stop when we hit
|
|||
|
// a non-WAN binding, or a wan binding that is up and
|
|||
|
// dialout, or any wan binding if bit 1 in
|
|||
|
// DisableDialinNetbios is off.
|
|||
|
//
|
|||
|
|
|||
|
for (i = Binding->NicId-1; i >= FIRST_REAL_BINDING; i--) {
|
|||
|
TmpBinding = NIC_ID_TO_BINDING(Device, i);
|
|||
|
|
|||
|
if ((TmpBinding != NULL) &&
|
|||
|
((!TmpBinding->Adapter->MacInfo.MediumAsync) ||
|
|||
|
(TmpBinding->LineUp &&
|
|||
|
((Binding->DialOutAsync) ||
|
|||
|
((Device->DisableDialinNetbios & 0x01) == 0))))) {
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Device->HighestType20NicId = i;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Scan through bindings to update Device->LinkSpeed.
|
|||
|
// If SingleNetworkActive is set, we only count LAN
|
|||
|
// bindings when doing this.
|
|||
|
//
|
|||
|
// Update other device information?
|
|||
|
//
|
|||
|
|
|||
|
LinkSpeed = 0xffffffff;
|
|||
|
for (i = FIRST_REAL_BINDING; i <= Device->ValidBindings; i++) {
|
|||
|
if (TmpBinding = NIC_ID_TO_BINDING(Device, i)) {
|
|||
|
TmpAdapter = TmpBinding->Adapter;
|
|||
|
if (TmpBinding->LineUp &&
|
|||
|
(!Device->SingleNetworkActive || !TmpAdapter->MacInfo.MediumAsync) &&
|
|||
|
(TmpBinding->MediumSpeed < LinkSpeed)) {
|
|||
|
LinkSpeed = TmpBinding->MediumSpeed;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (LinkSpeed != 0xffffffff) {
|
|||
|
Device->LinkSpeed = LinkSpeed;
|
|||
|
}
|
|||
|
|
|||
|
IPX_FREE_LOCK (&Device->Lock, LockHandle);
|
|||
|
|
|||
|
IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|||
|
|
|||
|
//
|
|||
|
// Remove our router entry for this net.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// [FW] if this was a line on which IPXWAN config was happening, then we dont do this.
|
|||
|
//
|
|||
|
if (!Binding->IpxwanConfigRequired &&
|
|||
|
!Device->UpperDriverBound[IDENTIFIER_RIP]) {
|
|||
|
|
|||
|
Segment = RipGetSegment ((PUCHAR)&Binding->LocalAddress.NetworkAddress);
|
|||
|
IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
|
|||
|
|
|||
|
RouteEntry = RipGetRoute (Segment, (PUCHAR)&Binding->LocalAddress.NetworkAddress);
|
|||
|
|
|||
|
if (RouteEntry != (PIPX_ROUTE_ENTRY)NULL) {
|
|||
|
|
|||
|
RipDeleteRoute (Segment, RouteEntry);
|
|||
|
IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
|
|||
|
IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
|
|||
|
}
|
|||
|
|
|||
|
RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDown);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// [FW] If this was the last UpWanLine, cancel the inactivity timer.
|
|||
|
//
|
|||
|
/*
|
|||
|
IPX_GET_LOCK (&Device->Lock, &LockHandle);
|
|||
|
if (--Device->UpWanLineCount == 0) {
|
|||
|
if (!CTEStopTimer (&IpxDevice->WanInactivityTimer)) {
|
|||
|
DbgPrint("Could not stop the WanInactivityTimer\n");
|
|||
|
DbgBreakPoint();
|
|||
|
}
|
|||
|
}
|
|||
|
IPX_FREE_LOCK (&Device->Lock, LockHandle);
|
|||
|
*/
|
|||
|
|
|||
|
//
|
|||
|
// If this was a line on which IPXWAN config was going on, then we need to tell only the
|
|||
|
// IPXWAN layer that the line went down since none of the other clients were informed of
|
|||
|
// the line up in the first place.
|
|||
|
//
|
|||
|
if (Binding->IpxwanConfigRequired) {
|
|||
|
goto InformIpxWan1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Indicate to the upper drivers.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// DeRegister this address with the TDI clients.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Since the IRQL is too high, we will do this now on a worker thread. [Shreem]
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
Event = CTEAllocMem( sizeof(CTEEvent) );
|
|||
|
if ( Event ) {
|
|||
|
CTEInitEvent(Event, LineDownOnWorkerThread);
|
|||
|
CTEScheduleEvent(Event, Binding);
|
|||
|
ntStatus = STATUS_PENDING;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Tell FWD if it wants to know [Shreem]
|
|||
|
//
|
|||
|
Binding->PastAutoDetection = FALSE;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Indicate to the Fwd only if it opened this adapter first.
|
|||
|
//
|
|||
|
if (Device->UpperDriverBound[IDENTIFIER_RIP] &&
|
|||
|
(!Device->ForwarderBound || Binding->FwdAdapterContext)) {
|
|||
|
|
|||
|
(*Device->UpperDrivers[IDENTIFIER_RIP].LineDownHandler)(
|
|||
|
Binding->NicId,
|
|||
|
Binding->FwdAdapterContext);
|
|||
|
|
|||
|
CTEAssert(Binding->IsnInformed[IDENTIFIER_RIP]);
|
|||
|
|
|||
|
Binding->IsnInformed[IDENTIFIER_RIP] = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if ((Device->SingleNetworkActive) &&
|
|||
|
(Binding->DialOutAsync)) {
|
|||
|
|
|||
|
//
|
|||
|
// Drop all entries in the database if rip is not bound.
|
|||
|
//
|
|||
|
|
|||
|
if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
|
|||
|
RipDropRemoteEntries();
|
|||
|
}
|
|||
|
|
|||
|
Device->ActiveNetworkWan = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Find a queued line change and complete it.
|
|||
|
//
|
|||
|
|
|||
|
if ((p = ExInterlockedRemoveHeadList(
|
|||
|
&Device->LineChangeQueue,
|
|||
|
&Device->Lock)) != NULL) {
|
|||
|
|
|||
|
Request = LIST_ENTRY_TO_REQUEST(p);
|
|||
|
|
|||
|
IoAcquireCancelSpinLock( &irql );
|
|||
|
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
|
|||
|
IoReleaseCancelSpinLock( irql );
|
|||
|
REQUEST_STATUS(Request) = STATUS_SUCCESS;
|
|||
|
IpxCompleteRequest (Request);
|
|||
|
IpxFreeRequest (Device, Request);
|
|||
|
|
|||
|
IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find a queued address notify and complete it.
|
|||
|
//
|
|||
|
|
|||
|
if ((!Device->WanGlobalNetworkNumber) &&
|
|||
|
((p = ExInterlockedRemoveHeadList(
|
|||
|
&Device->AddressNotifyQueue,
|
|||
|
&Device->Lock)) != NULL)) {
|
|||
|
|
|||
|
Request = LIST_ENTRY_TO_REQUEST(p);
|
|||
|
NdisBuffer = REQUEST_NDIS_BUFFER(Request);
|
|||
|
NdisQueryBufferSafe (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength, HighPagePriority);
|
|||
|
|
|||
|
if (NwlinkAction != NULL) {
|
|||
|
|
|||
|
IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
|
|||
|
|
|||
|
IpxAddressData->adapternum = Binding->NicId - 1;
|
|||
|
*(UNALIGNED ULONG *)IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
|
|||
|
RtlCopyMemory(IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
|
|||
|
IpxAddressData->wan = TRUE;
|
|||
|
IpxAddressData->status = FALSE;
|
|||
|
IpxAddressData->maxpkt = Binding->AnnouncedMaxDatagramSize; // Use real?
|
|||
|
IpxAddressData->linkspeed = Binding->MediumSpeed;
|
|||
|
REQUEST_STATUS(Request) = STATUS_SUCCESS;
|
|||
|
} else {
|
|||
|
REQUEST_STATUS(Request) = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
|
|||
|
|
|||
|
IoAcquireCancelSpinLock( &irql );
|
|||
|
IpxCompleteRequest (Request);
|
|||
|
IoReleaseCancelSpinLock( irql );
|
|||
|
IpxFreeRequest (Device, Request);
|
|||
|
|
|||
|
IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
|
|||
|
}
|
|||
|
|
|||
|
InformIpxWan1:
|
|||
|
Binding->fInfoIndicated = FALSE;
|
|||
|
if ((p = ExInterlockedRemoveHeadList(
|
|||
|
&Device->NicNtfQueue,
|
|||
|
&Device->Lock)) != NULL)
|
|||
|
{
|
|||
|
|
|||
|
Request = LIST_ENTRY_TO_REQUEST(p);
|
|||
|
IPX_DEBUG(WAN, ("IpxStatus: WAN LINE DOWN\n"));
|
|||
|
|
|||
|
Status = GetNewNics(Device, Request, FALSE, NULL, 0, TRUE);
|
|||
|
if (Status == STATUS_PENDING)
|
|||
|
{
|
|||
|
IPX_DEBUG(WAN, ("WANLineDown may not be responding properly\n"));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IoAcquireCancelSpinLock(&OldIrq);
|
|||
|
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
|
|||
|
IoReleaseCancelSpinLock(OldIrq);
|
|||
|
|
|||
|
REQUEST_STATUS(Request) = Status;
|
|||
|
IpxCompleteRequest (Request);
|
|||
|
IpxFreeRequest (Device, Request); //noop
|
|||
|
IpxDereferenceDevice (Device, DREF_NIC_NOTIFY);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|||
|
|
|||
|
{
|
|||
|
int kk;
|
|||
|
PBINDING pb = NULL;
|
|||
|
for (kk = LOOPBACK_NIC_ID; kk < Device->ValidBindings; kk++) {
|
|||
|
pb = NIC_ID_TO_BINDING(Device, kk);
|
|||
|
if (pb) {
|
|||
|
if (pb->NicId != kk) {
|
|||
|
DbgBreakPoint();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case NDIS_STATUS_WAN_FRAGMENT:
|
|||
|
|
|||
|
//
|
|||
|
// No response needed, IPX is a datagram service.
|
|||
|
//
|
|||
|
// What about telling Netbios/SPX?
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case NDIS_STATUS_MEDIA_CONNECT:
|
|||
|
|
|||
|
//
|
|||
|
// We bind to the new adapter and compare if the characteristics of any of
|
|||
|
// the previously disabled adapters matches with the characteristics of this new one.
|
|||
|
//
|
|||
|
// if we find a match then we must be on the same LAN/WAN as the disabled adapter.
|
|||
|
// We just enable this adapter and Unbind the new one. If we cant find a match, we
|
|||
|
// unbind/free one of these disbled adapters.
|
|||
|
//
|
|||
|
// IpxUnbindAdapter() sends the upper drivers a IPX_PNP_DELETE messages
|
|||
|
// and they purge their addresses, caches etc.
|
|||
|
{
|
|||
|
|
|||
|
#ifdef _NDIS_MEDIA_SENSE_
|
|||
|
|
|||
|
CTEEvent *Event;
|
|||
|
|
|||
|
// IPX_DEBUG(PNP, ("Ndis_Media_Sense: CONNECT for %ws. Queueing WorkerThread\n", Adapter->AdapterName));
|
|||
|
|
|||
|
Event = CTEAllocMem( sizeof(CTEEvent) );
|
|||
|
if ( Event ) {
|
|||
|
CTEInitEvent(Event, IpxMediaSenseHandler);
|
|||
|
CTEScheduleEvent(Event, Adapter);
|
|||
|
ntStatus = STATUS_PENDING;
|
|||
|
} else {
|
|||
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
#endif // _NDIS_MEDIA_SENSE_
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case NDIS_STATUS_MEDIA_DISCONNECT:
|
|||
|
|
|||
|
//
|
|||
|
// It must fail all datagram sends. It must fail all
|
|||
|
// connects right away but not disconnect sessions in progress.
|
|||
|
// These must timeout the way they do today. The router
|
|||
|
// must age out routes on this interface and not propagate them.
|
|||
|
//
|
|||
|
// All of the above can be achieved by setting Bindings->Lineup = DOWN;
|
|||
|
//
|
|||
|
#ifdef _NDIS_MEDIA_SENSE_
|
|||
|
|
|||
|
{
|
|||
|
int j;
|
|||
|
|
|||
|
//IPX_DEBUG(PNP, ("Ndis_Status_Media_Sense: DISCONNECT for %ws\n", Adapter->AdapterName));
|
|||
|
|
|||
|
for ( j = 0; j< ISN_FRAME_TYPE_MAX; j++ ) {
|
|||
|
if (Adapter->Bindings[j]) {
|
|||
|
Adapter->Bindings[j]->Disabled = DISABLED;
|
|||
|
}
|
|||
|
Adapter->Disabled = DISABLED;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
#endif // _NDIS_MEDIA_SENSE_
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
error_no_lock:
|
|||
|
IpxDereferenceAdapter(Adapter);
|
|||
|
|
|||
|
} /* IpxStatus */
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Since IPXStatus is called by NDIS at DISPATCH_LEVEL irql and TDIRegisterNetAddress
|
|||
|
// needs to be called at PASSIVE_LEVEL, We now do this TDI and PnpNotifications on a
|
|||
|
// worker thread launched from IpxStatus. Hopefully there arent any repercussions of this.
|
|||
|
// [ShreeM]
|
|||
|
|
|||
|
void
|
|||
|
LineUpOnWorkerThread(
|
|||
|
IN CTEEvent *WorkerThreadEvent,
|
|||
|
IN PVOID Context)
|
|||
|
{
|
|||
|
PBINDING Binding = (PBINDING) Context;
|
|||
|
NTSTATUS ntStatus;
|
|||
|
IPX_PNP_INFO NBPnPInfo;
|
|||
|
PDEVICE Device = IpxDevice;
|
|||
|
|
|||
|
//
|
|||
|
// Qos changes
|
|||
|
//
|
|||
|
int count, i;
|
|||
|
int size;
|
|||
|
NTSTATUS NdisStatus = STATUS_SUCCESS;
|
|||
|
UNICODE_STRING AdapterName;
|
|||
|
NDIS_REQUEST IpxRequest;
|
|||
|
PNETWORK_ADDRESS_LIST AddrList;
|
|||
|
PNETWORK_ADDRESS Address;
|
|||
|
NETWORK_ADDRESS_IPX *TdiAddress;
|
|||
|
PBINDING TempBinding;
|
|||
|
|
|||
|
IPX_DEFINE_LOCK_HANDLE (LockHandle)
|
|||
|
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
|
|||
|
|
|||
|
|
|||
|
ASSERT(Context != NULL);
|
|||
|
|
|||
|
CTEFreeMem(WorkerThreadEvent);
|
|||
|
|
|||
|
IPX_DEBUG(WAN, ("TDIRegisterNetAddress etc. on worker thread.\n"));
|
|||
|
|
|||
|
if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == FIRST_REAL_BINDING)) {
|
|||
|
|
|||
|
//
|
|||
|
// NB's reserved address changed.
|
|||
|
//
|
|||
|
NBPnPInfo.NewReservedAddress = TRUE;
|
|||
|
|
|||
|
if (!Device->VirtualNetwork) {
|
|||
|
//
|
|||
|
// Let SPX know because it fills in its own headers.
|
|||
|
//
|
|||
|
if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
|
|||
|
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
|
|||
|
IPX_PNP_INFO IpxPnPInfo;
|
|||
|
|
|||
|
IpxPnPInfo.NewReservedAddress = TRUE;
|
|||
|
IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
|
|||
|
IpxPnPInfo.FirstORLastDevice = FALSE;
|
|||
|
|
|||
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|||
|
RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
|
|||
|
NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|||
|
|
|||
|
//
|
|||
|
// give the PnP indication
|
|||
|
//
|
|||
|
(*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
|
|||
|
IPX_PNP_ADDRESS_CHANGE,
|
|||
|
&IpxPnPInfo);
|
|||
|
|
|||
|
IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADDRESS_CHANGED to SPX: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
NBPnPInfo.NewReservedAddress = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (Device->UpperDriverBound[IDENTIFIER_NB]) {
|
|||
|
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
|
|||
|
|
|||
|
Binding->IsnInformed[IDENTIFIER_NB] = TRUE;
|
|||
|
|
|||
|
NBPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
|
|||
|
NBPnPInfo.LineInfo.MaximumPacketSize =
|
|||
|
Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
|
|||
|
NBPnPInfo.LineInfo.MaximumSendSize =
|
|||
|
Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
|
|||
|
NBPnPInfo.LineInfo.MacOptions = Device->MacOptions;
|
|||
|
|
|||
|
NBPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
|
|||
|
NBPnPInfo.FirstORLastDevice = FALSE;
|
|||
|
|
|||
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|||
|
RtlCopyMemory(NBPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
|
|||
|
NIC_HANDLE_FROM_NIC(NBPnPInfo.NicHandle, Binding->NicId);
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|||
|
|
|||
|
//
|
|||
|
// give the PnP indication
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(Binding->NicId != LOOPBACK_NIC_ID);
|
|||
|
ASSERT(IpxHasInformedNbLoopback());
|
|||
|
ASSERT(NBPnPInfo.FirstORLastDevice == FALSE);
|
|||
|
|
|||
|
(*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
|
|||
|
IPX_PNP_ADD_DEVICE,
|
|||
|
&NBPnPInfo);
|
|||
|
|
|||
|
IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADD_DEVICE (lineup) to NB: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Register this address with the TDI clients.
|
|||
|
//
|
|||
|
RtlCopyMemory (Device->TdiRegistrationAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
|
|||
|
|
|||
|
if ((ntStatus = TdiRegisterNetAddress(
|
|||
|
Device->TdiRegistrationAddress,
|
|||
|
#if defined(_PNP_POWER_)
|
|||
|
&IpxDeviceName,
|
|||
|
NULL,
|
|||
|
#endif _PNP_POWER_
|
|||
|
&Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
|
|||
|
|
|||
|
DbgPrint("TdiRegisterNetAddress failed with %lx. (0xC000009A is STATUS_INSUFFICIENT_RESOURCES)", ntStatus);
|
|||
|
}
|
|||
|
|
|||
|
#if 0
|
|||
|
//
|
|||
|
// Register with QoS
|
|||
|
//
|
|||
|
IPX_DEBUG(PNP, ("Register a new address with QoS over here\n"));
|
|||
|
|
|||
|
for (count=0, i=IpxDevice->HighestLanNicId+1; i < IpxDevice->ValidBindings; i++) {
|
|||
|
if (NIC_ID_TO_BINDING(IpxDevice, i)) {
|
|||
|
count++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
IPX_DEBUG(PNP, ("This adapter has %d valid WAN bindings\n", count));
|
|||
|
size = FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address) + count * (FIELD_OFFSET(NETWORK_ADDRESS, Address) + sizeof(NETWORK_ADDRESS_IPX));
|
|||
|
|
|||
|
AddrList = IpxAllocateMemory(
|
|||
|
size,
|
|||
|
MEMORY_ADAPTER,
|
|||
|
"QoS specific stuff");
|
|||
|
|
|||
|
// 270344
|
|||
|
if (AddrList == NULL) {
|
|||
|
DbgPrint("IpxAllocateMemory returned NULL. Skip QoS registration.\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory(AddrList, size);
|
|||
|
AddrList->AddressCount = count;
|
|||
|
AddrList->AddressType = NDIS_PROTOCOL_ID_IPX;
|
|||
|
|
|||
|
count = 0;
|
|||
|
Address = &AddrList->Address[0];
|
|||
|
|
|||
|
for (i=IpxDevice->HighestLanNicId+1; i < IpxDevice->ValidBindings; i++) {
|
|||
|
|
|||
|
if (TempBinding = NIC_ID_TO_BINDING(IpxDevice, i)) {
|
|||
|
|
|||
|
Address->AddressLength = sizeof(NETWORK_ADDRESS_IPX);
|
|||
|
Address->AddressType = NDIS_PROTOCOL_ID_IPX;
|
|||
|
TdiAddress = (NETWORK_ADDRESS_IPX *) &Address->Address[0];
|
|||
|
|
|||
|
TdiAddress->NetworkAddress = TempBinding->LocalAddress.NetworkAddress;
|
|||
|
RtlCopyMemory (TdiAddress->NodeAddress, TempBinding->LocalAddress.NodeAddress, 6);
|
|||
|
|
|||
|
TdiAddress->Socket = 0;
|
|||
|
|
|||
|
IPX_DEBUG(PNP, ("Node is %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x, ",
|
|||
|
TdiAddress->NodeAddress[0], TdiAddress->NodeAddress[1],
|
|||
|
TdiAddress->NodeAddress[2], TdiAddress->NodeAddress[3],
|
|||
|
TdiAddress->NodeAddress[4], TdiAddress->NodeAddress[5]));
|
|||
|
IPX_DEBUG(PNP, ("Network is %lx\n", REORDER_ULONG (TdiAddress->NetworkAddress)));
|
|||
|
count++;
|
|||
|
Address = (PNETWORK_ADDRESS) (((PUCHAR)(&AddrList->Address[0])) + count * (FIELD_OFFSET(NETWORK_ADDRESS, Address) + sizeof(NETWORK_ADDRESS_IPX)));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
IpxRequest.RequestType = NdisRequestSetInformation;
|
|||
|
|
|||
|
IpxRequest.DATA.SET_INFORMATION.Oid = OID_GEN_NETWORK_LAYER_ADDRESSES;
|
|||
|
IpxRequest.DATA.SET_INFORMATION.InformationBuffer = AddrList;
|
|||
|
IpxRequest.DATA.SET_INFORMATION.InformationBufferLength = size;
|
|||
|
|
|||
|
TempBinding = NIC_ID_TO_BINDING(IpxDevice, IpxDevice->HighestLanNicId+1);
|
|||
|
|
|||
|
if (TempBinding) {
|
|||
|
|
|||
|
RtlInitUnicodeString(&AdapterName, TempBinding->Adapter->AdapterName);
|
|||
|
|
|||
|
NdisStatus = IpxSubmitNdisRequest (TempBinding->Adapter, &IpxRequest, &AdapterName);
|
|||
|
|
|||
|
IPX_DEBUG(PNP, ("Returned from NDISRequest :%lx\n", NdisStatus));
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DbgPrint("IpxDevice->Binding[highestlannicid+1] is NULL!!\n");
|
|||
|
CTEAssert(TempBinding != NULL);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|||
|
|
|||
|
IPX_DEBUG(PNP, ("Setting the QoS OID failed - Error %lx\n", NdisStatus));
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
IPX_DEBUG(PNP, ("Setting the QoS OID was successful\n"));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
IpxFreeMemory(AddrList,
|
|||
|
size,
|
|||
|
MEMORY_ADAPTER,
|
|||
|
"QoS specific stuff");
|
|||
|
#endif
|
|||
|
|
|||
|
} /* LineUpOnWorkerThread */
|
|||
|
|
|||
|
//
|
|||
|
// Since IPXStatus is called by NDIS at DISPATCH_LEVEL irql and TDIDeregisterNetAddress
|
|||
|
// needs to be called at PASSIVE_LEVEL, We now do this TDI and PnpNotifications on a
|
|||
|
// worker thread launched from IpxStatus. Hopefully there arent any repercussions of this.
|
|||
|
// [ShreeM]
|
|||
|
|
|||
|
void
|
|||
|
LineDownOnWorkerThread(
|
|||
|
IN CTEEvent *WorkerThreadEvent,
|
|||
|
IN PVOID Context)
|
|||
|
{
|
|||
|
PBINDING Binding = (PBINDING) Context;
|
|||
|
NTSTATUS ntStatus;
|
|||
|
IPX_PNP_INFO NBPnPInfo;
|
|||
|
PDEVICE Device = IpxDevice;
|
|||
|
IPX_DEFINE_LOCK_HANDLE (LockHandle)
|
|||
|
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
|
|||
|
|
|||
|
|
|||
|
ASSERT(Context != NULL);
|
|||
|
|
|||
|
CTEFreeMem(WorkerThreadEvent);
|
|||
|
|
|||
|
IPX_DEBUG(WAN, ("TDIDeregister etc. on worker thread.\n"));
|
|||
|
|
|||
|
//
|
|||
|
// DeRegister this address with the TDI clients.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|||
|
|
|||
|
// CTEAssert(Binding->TdiRegistrationHandle);
|
|||
|
// TdiRegisterNetAddress could fail due to insufficient resources. In which case,
|
|||
|
// TdiRegistrationHandle could be null. Removed assertion failure, added check. [TC]
|
|||
|
if (Binding->TdiRegistrationHandle != NULL) {
|
|||
|
|
|||
|
if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
|
|||
|
DbgPrint("TdiDeRegisterNetAddress failed: %lx", ntStatus);
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// 118187: Dont deregister twice! [ShreeM]
|
|||
|
//
|
|||
|
Binding->TdiRegistrationHandle = NULL;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
IPX_GET_LOCK(&Device->Lock, &LockHandle);
|
|||
|
|
|||
|
if (Device->UpperDriverBound[IDENTIFIER_NB]) {
|
|||
|
|
|||
|
IPX_FREE_LOCK(&Device->Lock, LockHandle);
|
|||
|
|
|||
|
// CTEAssert(Binding->IsnInformed[IDENTIFIER_NB]);
|
|||
|
if (Binding->IsnInformed[IDENTIFIER_NB]) {
|
|||
|
|
|||
|
NBPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
|
|||
|
NBPnPInfo.LineInfo.MaximumPacketSize =
|
|||
|
Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
|
|||
|
NBPnPInfo.LineInfo.MaximumSendSize =
|
|||
|
Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
|
|||
|
NBPnPInfo.LineInfo.MacOptions = Device->MacOptions;
|
|||
|
|
|||
|
NBPnPInfo.NewReservedAddress = FALSE;
|
|||
|
NBPnPInfo.FirstORLastDevice = FALSE;
|
|||
|
|
|||
|
NBPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
|
|||
|
|
|||
|
RtlCopyMemory(NBPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
|
|||
|
NIC_HANDLE_FROM_NIC(NBPnPInfo.NicHandle, Binding->NicId);
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|||
|
|
|||
|
//
|
|||
|
// give the PnP indication
|
|||
|
//
|
|||
|
|
|||
|
CTEAssert(Binding->NicId != LOOPBACK_NIC_ID);
|
|||
|
|
|||
|
(*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
|
|||
|
IPX_PNP_DELETE_DEVICE,
|
|||
|
&NBPnPInfo);
|
|||
|
|
|||
|
Binding->IsnInformed[IDENTIFIER_NB] = FALSE;
|
|||
|
|
|||
|
IPX_DEBUG(PNP,("Indicate to NB IPX_PNP_DELETE_DEVICE with FirstORLastDevice = (%d)",NBPnPInfo.FirstORLastDevice));
|
|||
|
IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_DELETE_DEVICE (linedown) to NB: addr: %lx\n", Binding->LocalAddress.NetworkAddress));
|
|||
|
} else {
|
|||
|
DbgPrint("LineDownOnWorkerThread: Binding (%p) ->IsnInformed[IDENTIFIER_NB] is FALSE",Binding);
|
|||
|
}
|
|||
|
} else {
|
|||
|
IPX_FREE_LOCK(&Device->Lock, LockHandle);
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|||
|
}
|
|||
|
|
|||
|
} /* LineDownOnWorkerThread */
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IpxStatusComplete(
|
|||
|
IN NDIS_HANDLE NdisBindingContext
|
|||
|
)
|
|||
|
{
|
|||
|
UNREFERENCED_PARAMETER (NdisBindingContext);
|
|||
|
|
|||
|
} /* IpxStatusComplete */
|
|||
|
|
|||
|
|
|||
|
#ifdef _NDIS_MEDIA_SENSE_
|
|||
|
//
|
|||
|
// CompareBindingCharacteristics
|
|||
|
//
|
|||
|
// Inputs: Binding1, Binding2
|
|||
|
//
|
|||
|
// Output:
|
|||
|
// COMPLETE_MATCH : They match completely
|
|||
|
// PARTIAL_MATCH : They match partially
|
|||
|
// zero otherwise
|
|||
|
//
|
|||
|
|
|||
|
UINT
|
|||
|
CompareBindingCharacteristics(
|
|||
|
PBINDING Binding1,
|
|||
|
PBINDING Binding2
|
|||
|
)
|
|||
|
{
|
|||
|
UINT Match = 0; // we return this if nothing matches.
|
|||
|
|
|||
|
//
|
|||
|
// if the mac address happens to be the same, it must be
|
|||
|
// the same card on a different net.
|
|||
|
//
|
|||
|
|
|||
|
if (IPX_NODE_EQUAL(Binding1->LocalMacAddress.Address, Binding2->LocalMacAddress.Address)) {
|
|||
|
Match = PARTIAL_MATCH;
|
|||
|
}
|
|||
|
|
|||
|
if ((Binding1->FrameType == Binding2->FrameType) &&
|
|||
|
(Binding1->LocalAddress.NetworkAddress == Binding2->LocalAddress.NetworkAddress) &&
|
|||
|
(IPX_NODE_EQUAL(Binding1->LocalAddress.NodeAddress, Binding2->LocalAddress.NodeAddress))) {
|
|||
|
|
|||
|
/*if ((LINE_UP == Binding1->LineUp) && (LINE_UP == Binding2->LineUp) &&
|
|||
|
(Binding1->MaxSendPacketSize == Binding2->MaxSendPacketSize) &&
|
|||
|
(Binding1->MediumSpeed == Binding2->MediumSpeed) &&
|
|||
|
(IPX_NODE_EQUAL(Binding1->RemoteMacAddress, Binding2->RemoteMacAddress))) {
|
|||
|
*/
|
|||
|
return COMPLETE_MATCH;
|
|||
|
// }
|
|||
|
}
|
|||
|
|
|||
|
return Match;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//** IpxMediaSenseWorker - Handles Media Sense work on a CTE worker
|
|||
|
// because NdisProtocolStatus runs at DPC.
|
|||
|
//
|
|||
|
// Called from the worker thread event scheduled by IPXStatus.
|
|||
|
//
|
|||
|
// Entry:
|
|||
|
// NdisProtocolBindingContext == AdapterName
|
|||
|
//
|
|||
|
// Exit:
|
|||
|
// None.
|
|||
|
//
|
|||
|
void
|
|||
|
IpxMediaSenseHandler(
|
|||
|
IN CTEEvent *WorkerThreadEvent,
|
|||
|
IN PVOID Context)
|
|||
|
{
|
|||
|
|
|||
|
PADAPTER Adapter = (PADAPTER) Context;
|
|||
|
UNICODE_STRING DeviceName;
|
|||
|
BOOLEAN MatchFound[ISN_FRAME_TYPE_MAX], AdapterMatched;
|
|||
|
PADAPTER DisabledAdapter = NULL;
|
|||
|
int j, MatchLevel;
|
|||
|
ULONG Index, i;
|
|||
|
NDIS_STRING AdapterName;
|
|||
|
NTSTATUS Status;
|
|||
|
PDEVICE Device = IpxDevice;
|
|||
|
PBINDING Binding;
|
|||
|
IPX_DEFINE_LOCK_HANDLE (LockHandle)
|
|||
|
|
|||
|
ASSERT(Context != NULL);
|
|||
|
|
|||
|
IpxReferenceAdapter(Adapter);
|
|||
|
|
|||
|
CTEFreeMem(WorkerThreadEvent);
|
|||
|
|
|||
|
IPX_DEBUG(PNP, ("Ndis_Status_Media_Sense: CONNECT for %ws\n", Adapter->AdapterName));
|
|||
|
|
|||
|
RtlInitUnicodeString(&AdapterName, Adapter->AdapterName);
|
|||
|
|
|||
|
for (j = 0; j < ISN_FRAME_TYPE_MAX; j++) {
|
|||
|
MatchFound[j] = FALSE;
|
|||
|
}
|
|||
|
AdapterMatched = FALSE;
|
|||
|
|
|||
|
IpxBindAdapter(
|
|||
|
&Status,
|
|||
|
NULL, //Adapter,
|
|||
|
&AdapterName, // \\Device\IEEPRO1
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (STATUS_SUCCESS != Status) {
|
|||
|
IPX_DEBUG(PNP, ("IpxBindAdapter returned : %x\n", Status));
|
|||
|
}
|
|||
|
|
|||
|
// new Adapter's characteristics with in the list of previously disabled adapters.
|
|||
|
Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
|
|||
|
|
|||
|
IPX_GET_LOCK1(&Device->BindAccessLock, LockHandle);
|
|||
|
|
|||
|
for (i = FIRST_REAL_BINDING; i <= Index; i++) {
|
|||
|
|
|||
|
Binding = NIC_ID_TO_BINDING(Device, i);
|
|||
|
|
|||
|
if (!Binding) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (Binding->Disabled == DISABLED) {
|
|||
|
|
|||
|
for (j = 0; j < ISN_FRAME_TYPE_MAX; j++) {
|
|||
|
if (!Adapter->Bindings[j]) {
|
|||
|
continue; // NULL Binding
|
|||
|
}
|
|||
|
|
|||
|
if (!MatchFound[j]) {
|
|||
|
MatchLevel = CompareBindingCharacteristics(Binding, Adapter->Bindings[j]);
|
|||
|
if (COMPLETE_MATCH == MatchLevel) {
|
|||
|
MatchFound[j] = TRUE;
|
|||
|
DisabledAdapter = Binding->Adapter;
|
|||
|
} else if (PARTIAL_MATCH == MatchLevel) {
|
|||
|
// if we had more than one disabled adapters, this is
|
|||
|
// most probably the one which is changed
|
|||
|
DisabledAdapter = Binding->Adapter; // Free this puppy later
|
|||
|
}
|
|||
|
}
|
|||
|
// Try another
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
for (j = 0; j < ISN_FRAME_TYPE_MAX; j++) {
|
|||
|
if (MatchFound[j]) {
|
|||
|
AdapterMatched = TRUE;
|
|||
|
IPX_DEBUG(PNP, ("Found a matching adapter !\n"));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle);
|
|||
|
|
|||
|
if (AdapterMatched) {
|
|||
|
|
|||
|
IPX_DEBUG(PNP, ("Freeing the newly created adapter since we found a match !\n"));
|
|||
|
|
|||
|
IpxUnbindAdapter(
|
|||
|
&Status,
|
|||
|
Adapter,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (STATUS_SUCCESS != Status) {
|
|||
|
IPX_DEBUG(PNP, ("IpxUnBindAdapter returned : %x\n", Status));
|
|||
|
} else {
|
|||
|
for ( j = 0; j< ISN_FRAME_TYPE_MAX; j++ ) {
|
|||
|
if (DisabledAdapter->Bindings[j]) {
|
|||
|
DisabledAdapter->Bindings[j]->Disabled = ENABLED;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
Adapter->Disabled = ENABLED;
|
|||
|
}
|
|||
|
|
|||
|
} else if (DisabledAdapter != NULL) {
|
|||
|
|
|||
|
IPX_DEBUG(PNP, ("Freeing the previously disabled adapter since we have new characteristics...!\n"));
|
|||
|
|
|||
|
ASSERT(DisabledAdapter != NULL);
|
|||
|
|
|||
|
IpxUnbindAdapter(
|
|||
|
&Status,
|
|||
|
DisabledAdapter,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (STATUS_SUCCESS != Status) {
|
|||
|
IPX_DEBUG(PNP, ("IpxBindAdapter returned : %x\n", Status));
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
IPX_DEBUG(PNP, ("NULL Disabled Adapter. Ndis is probably giving random notifications.\n"));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
IpxDereferenceAdapter(Adapter);
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
#endif // _NDIS_MEDIA_SENSE_
|