windows-nt/Source/XPSP1/NT/net/nwlink/ipx/ndis.c

3086 lines
91 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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_