summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isn/ipx/ndis.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/isn/ipx/ndis.c2381
1 files changed, 2381 insertions, 0 deletions
diff --git a/private/ntos/tdi/isn/ipx/ndis.c b/private/ntos/tdi/isn/ipx/ndis.c
new file mode 100644
index 000000000..db1d41e13
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/ndis.c
@@ -0,0 +1,2381 @@
+/*++
+
+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 (in _PNP_POWER)
+
+ 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_STATUS
+IpxSubmitNdisRequest(
+ IN PADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ );
+
+#ifndef _PNP_POWER
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxRegisterProtocol)
+#pragma alloc_text(INIT,IpxInitializeNdis)
+#endif
+#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
+
+
+ //
+ // 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;
+
+#ifdef _PNP_POWER
+ ProtChars.BindAdapterHandler = IpxBindAdapter;
+ ProtChars.UnbindAdapterHandler = IpxUnbindAdapter;
+ ProtChars.TranslateHandler = IpxTranslate;
+#endif // _PNP_POWER
+
+ NdisRegisterProtocol (
+ &ndisStatus,
+ &IpxNdisProtocolHandle,
+ &ProtChars,
+ (UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + NameString->Length);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS) {
+ return (NTSTATUS)ndisStatus;
+ }
+
+ 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;
+
+ if (IpxNdisProtocolHandle != (NDIS_HANDLE)NULL) {
+ NdisDeregisterProtocol (
+ &ndisStatus,
+ IpxNdisProtocolHandle);
+ IpxNdisProtocolHandle = (NDIS_HANDLE)NULL;
+ }
+
+} /* IpxDeregisterProtocol */
+
+
+NDIS_STATUS
+IpxSubmitNdisRequest(
+ IN PADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest,
+ 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.
+
+ NdisRequest - 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;
+
+ NdisRequest(
+ &NdisStatus,
+ Adapter->NdisBindingHandle,
+ NdisRequest);
+
+ 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
+ );
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ IPX_DEBUG (NDIS, ("%s on OID %8.8lx failed %lx\n",
+ NdisRequest->RequestType == NdisRequestSetInformation ? "Set" : "Query",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ NdisStatus));
+
+ IpxWriteOidErrorLog(
+ Adapter->Device->DeviceObject,
+ NdisRequest->RequestType == NdisRequestSetInformation ?
+ EVENT_TRANSPORT_SET_OID_FAILED : EVENT_TRANSPORT_QUERY_OID_FAILED,
+ NdisStatus,
+ AdapterString->Buffer,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid);
+
+ } else {
+
+ IPX_DEBUG (NDIS, ("%s on OID %8.8lx succeeded\n",
+ NdisRequest->RequestType == NdisRequestSetInformation ? "Set" : "Query",
+ NdisRequest->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:
+
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+
+ }
+
+ 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).
+ //
+ // BETABUGBUG: 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);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // 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) {
+ 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.
+ //
+
+ 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) {
+ 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;
+
+ }
+
+ //
+ // BUGBUG: 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;
+ 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;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)TRUE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+ }
+ }
+
+} /* 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;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)FALSE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+ }
+ }
+
+} /* 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.
+
+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;
+
+#ifdef _PNP_POWER
+ 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 = 1; i <= Index; i++) {
+
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ IPX_DEBUG (NDIS, ("%s operation started\n", Enable ? "Enable" : "Disable"));
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+
+ Binding = Device->Bindings[i];
+#endif
+ 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.
+ //
+
+ 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));
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ (VOID)IpxSubmitNdisRequest (Adapter, &IpxRequest, &AdapterName);
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ Adapter->BroadcastEnabled = Enable;
+
+ }
+ }
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ 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);
+
+ 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;
+
+ Adapter->NdisRequestStatus = NdisStatus;
+
+ KeSetEvent(
+ &Adapter->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;
+ UINT i, j;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ IPX_DEFINE_LOCK_HANDLE (OldIrq)
+ NTSTATUS ntStatus;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ Adapter = (PADAPTER)NdisBindingContext;
+
+ IpxReferenceAdapter(Adapter);
+#else
+ Adapter = (PADAPTER)NdisBindingContext;
+#endif
+
+ 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)));
+#ifdef _PNP_POWER
+ goto error_no_lock;
+#else
+ return;
+#endif
+ }
+
+ 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]));
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ if (Binding != NULL) {
+ UpdateLineUp = TRUE;
+ }
+
+ if (LineUp->ProtocolType != Adapter->BindSap) {
+ IPX_DEBUG (WAN, ("Line up, wrong protocol type %lx\n", LineUp->ProtocolType));
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto error_no_lock;
+#else
+ return;
+#endif
+ }
+
+ 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++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ 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);
+
+#ifdef _PNP_POWER
+ //
+ // CreateBinding does an InterLockedPop with the DeviceLock.
+ // So, release the lock here.
+ //
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ Status = IpxCreateBinding(
+ Device,
+ NULL,
+ 0,
+ Adapter->AdapterName,
+ &Binding);
+
+ if (Status != STATUS_SUCCESS) {
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IPX_DEBUG (WAN, ("Line up, could not create WAN binding\n"));
+ goto error_no_lock;
+#else
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IPX_DEBUG (WAN, ("Line up, could not create WAN binding\n"));
+ return;
+#endif
+ }
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+#endif
+ //
+ // 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;
+#ifdef _PNP_POWER
+ INSERT_BINDING(Device, i, Binding);
+#else
+ Device->Bindings[i] = Binding;
+#endif
+
+ //
+ // 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.
+ //
+ // BUGBUG: 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;
+
+ #ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto error_no_lock;
+ #else
+ return;
+ #endif
+ }
+ }
+
+
+ //
+ // 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) {
+/*
+ //
+ // [BUGBUGZZ] remove this...
+ //
+ CTEStartTimer(
+ &Device->WanInactivityTimer,
+ 60000, // 1 minute
+ IpxInternalIncrementWanInactivity,
+ (PVOID)Device);
+*/
+ }
+
+ 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).
+ //
+ // BUGBUG: Update other device information?
+ //
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (TmpBinding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (TmpBinding = Device->Bindings[i]) {
+#endif
+ TmpAdapter = TmpBinding->Adapter;
+ if (TmpBinding->LineUp &&
+ (!Device->SingleNetworkActive || TmpAdapter->MacInfo.MediumAsync) &&
+ (TmpBinding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = TmpBinding->MediumSpeed;
+ }
+ }
+ }
+
+#ifdef _PNP_POWER
+ //
+ // Release the lock after incrementing the reference count
+ //
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ 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;
+ }
+
+#ifdef _PNP_POWER
+
+ //
+ // 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.
+ //
+ {
+ IPX_PNP_INFO NBPnPInfo;
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+
+ //
+ // 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,
+ &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);
+ }
+ }
+#else
+ //
+ // Indicate to the upper drivers.
+ //
+ LineInfo.LinkSpeed = LineUp->LinkSpeed;
+ LineInfo.MaximumPacketSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MaximumSendSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+
+ if (Device->UpperDriverBound[i]) {
+ (*Device->UpperDrivers[i].LineUpHandler)(
+ Binding->NicId,
+ &LineInfo,
+ NdisMediumWan,
+ UpdateLineUp ? NULL : Configuration);
+ }
+ }
+#endif
+ 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);
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ 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.
+ //
+ // BUGBUG: Use RipSendResponse, and do it even
+ // if SingleNetworkActive is FALSE??
+ //
+
+ if (Device->RipResponder) {
+ (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);
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ 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; // BUGBUG: Use real?
+ IpxAddressData->linkspeed = Binding->MediumSpeed;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ }
+
+InformIpxWan:
+ Binding->fInfoIndicated = FALSE;
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->NicNtfQueue,
+ &Device->Lock)) != NULL)
+ {
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ DbgPrint("IpxStatus: WAN LINE UP\n");
+ Status = GetNewNics(Device, Request, FALSE, NULL, 0, FALSE);
+ if (Status != STATUS_SUCCESS)
+ {
+ DbgPrint("WAN Line up screw up\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);
+ }
+
+ }
+ }
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ 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.
+ //
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ // [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 >= 1; i--) {
+#ifdef _PNP_POWER
+ TmpBinding = NIC_ID_TO_BINDING(Device, i);
+#else
+ TmpBinding = Device->Bindings[i];
+#endif
+
+ 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.
+ //
+ // BUGBUG: Update other device information?
+ //
+
+ LinkSpeed = 0xffffffff;
+ for (i = 1; i <= Device->ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (TmpBinding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (TmpBinding = Device->Bindings[i]) {
+#endif
+ 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);
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ //
+ // 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.
+ //
+#ifdef _PNP_POWER
+
+ //
+ // DeRegister this address with the TDI clients.
+ //
+ {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ CTEAssert(Binding->TdiRegistrationHandle);
+
+ if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_PNP_INFO NBPnPInfo;
+
+ CTEAssert(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
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &NBPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_DELETE_DEVICE (linedown) to NB: addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ } else {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+ }
+
+ //
+ // 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;
+ }
+#else
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+
+ if (Device->UpperDriverBound[i]) {
+ (*Device->UpperDrivers[i].LineDownHandler)(
+ Binding->NicId);
+ }
+ }
+#endif
+
+ 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);
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ 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);
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ 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; // BUGBUG: Use real?
+ IpxAddressData->linkspeed = Binding->MediumSpeed;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ 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);
+ DbgPrint("IpxStatus: WAN LINE DOWN\n");
+
+ Status = GetNewNics(Device, Request, FALSE, NULL, 0, FALSE);
+ if (Status != STATUS_SUCCESS)
+ {
+ DbgPrint("WAN Line down screw up\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);
+ }
+ }
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ break;
+
+ case NDIS_STATUS_WAN_FRAGMENT:
+
+ //
+ // No response needed, IPX is a datagram service.
+ //
+ // BUGBUG: What about telling Netbios/SPX?
+ //
+
+ break;
+
+ default:
+
+ break;
+
+ }
+
+#ifdef _PNP_POWER
+error_no_lock:
+ IpxDereferenceAdapter(Adapter);
+#endif
+
+} /* IpxStatus */
+
+
+VOID
+IpxStatusComplete(
+ IN NDIS_HANDLE NdisBindingContext
+ )
+{
+ UNREFERENCED_PARAMETER (NdisBindingContext);
+
+} /* IpxStatusComplete */
+
+
+